C語(yǔ)言動(dòng)態(tài)內(nèi)存分配圖文講解
思維導(dǎo)圖
1.為什么存在動(dòng)態(tài)內(nèi)存分配
我們現(xiàn)在學(xué)習(xí)了一些內(nèi)存開(kāi)辟的方式:
int main() { int i;//在內(nèi)存棧區(qū)開(kāi)辟4個(gè)字節(jié)空間 char arr[5];//在??臻g上開(kāi)辟5個(gè)字節(jié)的連續(xù)空間 return 0; }
但是,這樣開(kāi)辟的內(nèi)存是靜態(tài)的,固定的:
1. 空間開(kāi)辟大小是固定的。
2. 數(shù)組在申明的時(shí)候,必須指定數(shù)組的長(zhǎng)度,它所需要的內(nèi)存在編譯時(shí)分配。
如果想要在編譯過(guò)程中開(kāi)辟空間,就需要用到動(dòng)態(tài)內(nèi)存。
2.動(dòng)態(tài)內(nèi)存函數(shù)的介紹
2.1 malloc
void* malloc (size_t size)
2.2 free
void free (void* ptr)
例:
#include <stdio.h> #include <stdlib.h> int main() { //申請(qǐng)40給字節(jié),用來(lái)存放10個(gè)整形 int* p = (int*)malloc(40);//malloc申請(qǐng)的空間不會(huì)初始化 if (p == NULL) //直接返回起始地址 { perror("malloc");//如果空間開(kāi)辟失敗要報(bào)錯(cuò)并返回 return 1; } //使用空間 int i = 0; for (i = 0; i < 10; i++) { printf("%d\n", *(p + i)); } //釋放申請(qǐng)的內(nèi)存 free(p); p = NULL; return 0; }
輸出:
輸出:
-842150451
-842150451
-842150451
-842150451
-842150451
-842150451
-842150451
-842150451
-842150451
-842150451
malloc不會(huì)自己初始化,所以打印隨機(jī)值。
例:
#include <stdio.h> #include <stdlib.h> int main() { //申請(qǐng)40給字節(jié),用來(lái)存放10個(gè)整形 int* p = (int*)malloc(40);//malloc申請(qǐng)的空間沒(méi)有初始化 if (p == NULL) //直接返回起始地址 { perror("malloc");//如果空間開(kāi)辟失敗要報(bào)錯(cuò)并返回 return 1; } //使用空間 int i = 0; for (i = 0; i < 10; i++) { *(p + i) = i + 1;//初始化賦值 printf("%d ", *(p + i)); } //釋放申請(qǐng)的內(nèi)存 free(p); p = NULL; return 0; }
輸出:
輸出:1 2 3 4 5 6 7 8 9 10
2.3 calloc
void* calloc (size_t num, size_t size)
例:
#include <stdio.h> #include <stdlib.h> int main() { int* p = (int*)calloc(10, sizeof(int));//10是要初始化的個(gè)數(shù),sizeof(int)是每個(gè)的大小 if (NULL == p) { perror("calloc");//判斷內(nèi)存是否申請(qǐng)成功 return 1; } //使用 int i = 0; for (i = 0; i < 10; i++) { printf("%d ", *(p + i));//calloc申請(qǐng)空間后,會(huì)把空間初始化成0 } //再返回起始地址 //釋放 free(p); p = NULL; }
輸出:
輸出:0 0 0 0 0 0 0 0 0 0
2.4 realloc
void* realloc (void* ptr, size_t size)
realloc函數(shù)可以追加更多動(dòng)態(tài)內(nèi)存。
例:
#include <stdio.h> #include <stdlib.h> int main() { int* p = (int*)malloc(5 * sizeof(int));//開(kāi)辟一段動(dòng)態(tài)內(nèi)存20個(gè)字節(jié) if (NULL == p) { perror("malloc");//檢查是否創(chuàng)建成功 return 1; } //使用 int i = 0; for (i = 0; i < 5; i++) { *(p + i) = i + 1; } //不夠用,增加5個(gè)整形的空間 int* ptr = (int*)realloc(p, 10 * sizeof(int));//這里是開(kāi)辟到40個(gè)字節(jié) //realloc函數(shù)開(kāi)辟內(nèi)存空間有兩種情況: //1.原內(nèi)存塊后面空間足夠,在原內(nèi)存塊后面追加內(nèi)存 //2.原內(nèi)存塊后面空間不夠,另外找一片區(qū)域開(kāi)辟內(nèi)存,將原內(nèi)存塊釋放 if (ptr != NULL) { p = ptr;//為什么不直接用p接收? //如果內(nèi)存追加失敗,直接用p接收的話(huà),原本已經(jīng)開(kāi)辟的動(dòng)態(tài)內(nèi)存空間就會(huì)被覆蓋 } for (i = 0; i < 10; i++) { printf("%d ", *(p + i)); } //釋放 free(p); p = NULL; return 0; }
輸出:
輸出:1 2 3 4 5 -842150451 -842150451 -842150451 -842150451 -842150451
3.常見(jiàn)的動(dòng)態(tài)內(nèi)存錯(cuò)誤
例1:
開(kāi)辟動(dòng)態(tài)內(nèi)存記得要判斷,最后釋放內(nèi)存。
#include <stdio.h> #include <stdlib.h> int main() { int* p = (int*)malloc(100); //內(nèi)存開(kāi)辟后沒(méi)有判斷是否開(kāi)辟成功 int i = 0; for (i = 0; i < 10; i++) { *(p + i) = 0;//危險(xiǎn)代碼,我們無(wú)法知道是否存在非法訪(fǎng)問(wèn) } //并且最后也沒(méi)有將開(kāi)辟的內(nèi)存還給操作系統(tǒng) return 0; }
例2:
動(dòng)態(tài)內(nèi)存開(kāi)辟了多少就用多少,小心越界訪(fǎng)問(wèn)。
#include <stdio.h> #include <stdlib.h> int main() { int* p = (int*)malloc(100);//開(kāi)辟了100字節(jié)空間 //判斷 if (p == NULL) { perror("malloc"); return 1; } int i = 0; for (i = 0; i < 100; i++)//造成越界訪(fǎng)問(wèn) { *(p + i) = 0;//一個(gè)整形4個(gè)字節(jié) } //釋放 free(p); p = NULL; return 0; }
例3:
不要亂釋放其他內(nèi)存空間。
int main() { int a = 10; int* p = &a; //你沒(méi)有權(quán)限亂釋放其他的內(nèi)存空間 free(p);//不能對(duì)棧區(qū)的內(nèi)存釋放 return 0; }
例4:
不要多次釋放內(nèi)存空間。
#include <stdio.h> #include <stdlib.h> int main() { //開(kāi)辟空間 int* p = (int*)malloc(100); //判斷 if (p == NULL) { perror("malloc"); return 1; } //使用 int i = 0; for (i = 0; i < 25; i++) { *p = i; p++;//p指針不斷往后移動(dòng) } //釋放的時(shí)候指針應(yīng)該指向起始地址,否則程序又會(huì)出錯(cuò) free(p); p = NULL; return 0; }
例5:
#include <stdio.h> #include <stdlib.h> int main() { //創(chuàng)建 int* p = (int*)malloc(100); //判斷 if (p == NULL) { return 1; } //釋放 free(p); free(p);//已經(jīng)釋放了,重復(fù)釋放會(huì)導(dǎo)致程序出錯(cuò) return 0; }
這就要說(shuō)到最后置為空指針的好處了:
#include <stdio.h> #include <stdlib.h> int main() { //創(chuàng)建 int* p = (int*)malloc(100); //判斷 if (p == NULL) { return 1; } //釋放 free(p); p = NULL;//置為空指針后程序就不會(huì)崩潰了 free(p);//p為空指針時(shí),程序不會(huì)報(bào)錯(cuò) return 0; }
例5:
在實(shí)現(xiàn)函數(shù)時(shí)開(kāi)辟了動(dòng)態(tài)內(nèi)存要記得及時(shí)釋放或者返回地址,
不然就再也找不到那段內(nèi)存空間了,最后導(dǎo)致內(nèi)存泄漏。
#include <stdio.h> #include <stdlib.h> void test() { int* p = (int*)malloc(100); //忘記釋放 }//出了函數(shù)就找不到了,因?yàn)樽兞縫被銷(xiāo)毀了 //造成內(nèi)存泄漏 int main() { test(); return 0; }
例6:
這道題也是類(lèi)似的:
#include <stdio.h> #include <stdlib.h> void test() { int* p = (int*)malloc(100); if (p == NULL) { return; } //使用 if (1) return;//出問(wèn)題//內(nèi)存泄漏 //釋放 free(p); p = NULL; } int main() { test(); return 0; }
要小心出現(xiàn)內(nèi)存泄漏,記得釋放空間。
到此這篇關(guān)于C語(yǔ)言動(dòng)態(tài)內(nèi)存分配圖文講解的文章就介紹到這了,更多相關(guān)C語(yǔ)言動(dòng)態(tài)內(nèi)存分配內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 深入了解C語(yǔ)言的動(dòng)態(tài)內(nèi)存管理
- 詳解C語(yǔ)言中動(dòng)態(tài)內(nèi)存管理及柔性數(shù)組的使用
- C語(yǔ)言動(dòng)態(tài)內(nèi)存的分配最全面分析
- 一文帶你搞懂C語(yǔ)言動(dòng)態(tài)內(nèi)存管理
- 詳解C語(yǔ)言中的動(dòng)態(tài)內(nèi)存管理
- 使用c語(yǔ)言輕松實(shí)現(xiàn)動(dòng)態(tài)內(nèi)存管
- 一文帶你了解C語(yǔ)言中的動(dòng)態(tài)內(nèi)存管理函數(shù)
- C語(yǔ)言動(dòng)態(tài)內(nèi)存管理的原理及實(shí)現(xiàn)方法
- 詳解C語(yǔ)言中動(dòng)態(tài)內(nèi)存管理
- C語(yǔ)言中常見(jiàn)的六種動(dòng)態(tài)內(nèi)存錯(cuò)誤總結(jié)
- 一文解析C語(yǔ)言中動(dòng)態(tài)內(nèi)存管理
- C語(yǔ)言動(dòng)態(tài)內(nèi)存管理的實(shí)現(xiàn)示例
相關(guān)文章
C/C++使用C語(yǔ)言實(shí)現(xiàn)多態(tài)
這篇文章主要介紹了C/C++多態(tài)的實(shí)現(xiàn)機(jī)制理解的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下,希望能給你帶來(lái)幫助2021-08-08C語(yǔ)言實(shí)現(xiàn)字母大小寫(xiě)轉(zhuǎn)換的方法
這篇文章主要介紹了C語(yǔ)言實(shí)現(xiàn)字母大小寫(xiě)轉(zhuǎn)換的方法,涉及C語(yǔ)言字符串的遍歷與轉(zhuǎn)換技巧,非常簡(jiǎn)單實(shí)用,需要的朋友可以參考下2015-07-07C++設(shè)計(jì)模式之適配器模式(Adapter)
這篇文章主要為大家詳細(xì)介紹了C++設(shè)計(jì)模式之適配器模式Adapter,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-03-03