關(guān)于C語言動(dòng)態(tài)內(nèi)存管理介紹
1.為什么需要?jiǎng)討B(tài)內(nèi)存分配
關(guān)于這個(gè)問題,我們先看看我們之前是如何開辟內(nèi)存的。
int val = 20;//在??臻g上開辟四個(gè)字節(jié) char arr[10] = {0};//在??臻g上開辟10個(gè)字節(jié)的連續(xù)空間
但可以發(fā)現(xiàn)的一個(gè)問題是,無論我們?cè)鯓娱_辟內(nèi)存空間,他的大小都在開辟前就已經(jīng)被指定,而顯然在實(shí)際應(yīng)用中并不是所有情況我們都能在程序編譯前就知道他需要多大的內(nèi)存空間?;蛟S你想說那有備無患開大點(diǎn)不久好了?但這樣所造成的空間浪費(fèi)并不是我們所希望看到的結(jié)果。于是我們就只能試試動(dòng)態(tài)內(nèi)存分配了。
2.有關(guān)動(dòng)態(tài)內(nèi)存函數(shù)介紹
2.1 malloc和free
c語言已經(jīng)為我們提供了一個(gè)動(dòng)態(tài)內(nèi)存開辟的函數(shù)malloc
void* malloc (size_t size);
1.這個(gè)函數(shù)向內(nèi)存申請(qǐng)一塊連續(xù)可用的空間,并返回指向這塊空間的指針。
2.如果開辟成功,則返回一個(gè)指向開辟好空間的指針。
3.如果開辟失敗,則返回一個(gè)NULL指針,因此malloc的返回值一定要做檢查。
4.返回值的類型是 void* ,所以malloc函數(shù)并不知道開辟空間的類型,具體在使用的時(shí)候使用者自 己來決定。
5.如果參數(shù) size 為0,malloc的行為是標(biāo)準(zhǔn)是未定義的,取決于編譯器。
當(dāng)然有分配就會(huì)有釋放,c語言也為我們提供了另一個(gè)函數(shù)free,專門用來做動(dòng)態(tài)內(nèi)存的釋放以及回收,函數(shù)原型如下。
void free (void* ptr);
1.free函數(shù)用來釋放動(dòng)態(tài)開辟的內(nèi)存。
2.如果參數(shù) ptr 指向的空間不是動(dòng)態(tài)開辟的,那free函數(shù)的行為是未定義的。
3.如果參數(shù) ptr 是NULL指針,則函數(shù)什么事都不做。
我們看到下面的一個(gè)例子
#include <stdio.h> int main() { int* ptr = NULL; ptr = (int*)malloc(num * sizeof(int)); if (NULL != ptr)//判斷ptr指針是否為空 { int i = 0; for (i = 0; i < num; i++) { *(ptr + i) = 0; } } free(ptr);//釋放ptr所指向的動(dòng)態(tài)內(nèi)存 ptr = NULL; return 0; }
相信這串代碼大家在有注釋的情況下都能夠看懂。但是有細(xì)心的讀者可能會(huì)發(fā)現(xiàn)free(ptr)之后又令ptr=NULL,這是為什么呢?其實(shí)在一塊內(nèi)存空間被釋放后,該指針仍指向被釋放掉的內(nèi)存地址,而此時(shí)的ptr便成了野指針,一旦后續(xù)不小心被程序調(diào)用就會(huì)導(dǎo)致程序崩潰,所以在指針釋放后要將其置為NULL防止這種情況的發(fā)生。
2.2 calloc函數(shù)
calloc函數(shù)類似與malloc,同樣用于動(dòng)態(tài)內(nèi)存分配,函數(shù)原型如下。
void* calloc (size_t num, size_t size);
函數(shù)的功能是為 num個(gè)大小為size的元素開辟一塊空間,并且把空間的每個(gè)字節(jié)初始化為0。
與函數(shù)malloc的區(qū)別只在于calloc會(huì)在返回地址之前把申請(qǐng)的空間的每個(gè)字節(jié)初始化為全0。
2.3 realloc函數(shù)
有時(shí)會(huì)我們發(fā)現(xiàn)過去申請(qǐng)的空間太小了,有時(shí)候我們又會(huì)覺得申請(qǐng)的空間過大了,那為了合理的時(shí) 候內(nèi)存,我們一定會(huì)對(duì)內(nèi)存的大小做靈活的調(diào)整。那 realloc 函數(shù)就可以做到對(duì)動(dòng)態(tài)開辟內(nèi)存大 小的調(diào)整。函數(shù)原型如下。
void* realloc (void* ptr, size_t size);
ptr 是要調(diào)整的內(nèi)存地址
size 調(diào)整之后新大小
返回值為調(diào)整之后的內(nèi)存起始位置。
這個(gè)函數(shù)調(diào)整原內(nèi)存空間大小的基礎(chǔ)上,還會(huì)將原來內(nèi)存中的數(shù)據(jù)移動(dòng)到新的空間。
需要注意的是:
realloc在調(diào)整內(nèi)存空間時(shí)存在兩種情況
情況1:原有空間之后有足夠大的空間
情況2:原有空間之后沒有足夠大的空間
參見下圖示意
情況1
當(dāng)是情況1的時(shí)候,要擴(kuò)展內(nèi)存就直接原有內(nèi)存之后直接追加空間,原來空間的數(shù)據(jù)不發(fā)生變化。
情況2
當(dāng)是情況2 的時(shí)候,原有空間之后沒有足夠多的空間時(shí),擴(kuò)展的方法是:在堆空間上另找一個(gè)合適大小 的連續(xù)空間來使用。這樣函數(shù)返回的是一個(gè)新的內(nèi)存地址。
針對(duì)情況二,若realloc成功,指向原內(nèi)存地址的指針就成了懸掛指針,即指針指向了一塊沒有分配給用戶使用的內(nèi)存,如果再使用該指針進(jìn)行操作就可能發(fā)生意想不到的情況,因此要格外注意這種情況。
#include <stdio.h> int main() { int* ptr = (int*)malloc(100);//動(dòng)態(tài)分配 int* p = NULL; p = (int*)realloc(ptr, 1000);//重分配 if (p != NULL)//判斷是否成功 { ptr = p;//防止懸掛指針出現(xiàn) } //業(yè)務(wù)處理 free(ptr); ptr=NULL;//釋放后置空防止野指針 return 0; }
注意動(dòng)態(tài)內(nèi)存分配時(shí)應(yīng)當(dāng)像上述代碼一樣盡量規(guī)范。
3. 常見的動(dòng)態(tài)內(nèi)存錯(cuò)誤
3.1 對(duì)NULL指針進(jìn)行解引用操作
這個(gè)點(diǎn)就不再過多敘述,大家記住即可,對(duì)空指針進(jìn)行解引用操作可能會(huì)引發(fā)各種奇怪的問題。
3.2 對(duì)動(dòng)態(tài)開辟空間的越界訪問
同數(shù)組類似,即使是動(dòng)態(tài)開辟的空間也不能越界訪問。
3.3 對(duì)非動(dòng)態(tài)開辟內(nèi)存使用free釋放
切記只有動(dòng)態(tài)開辟的內(nèi)存才能使用free。
3.4 使用free釋放一塊動(dòng)態(tài)開辟內(nèi)存的一部分
參見下面代碼
void test() { int *p = (int *)malloc(100); p++; free(p);//p不再指向動(dòng)態(tài)內(nèi)存的起始位置 }
雖然有些小伙伴可能想既然free函數(shù)是根據(jù)指針來釋放內(nèi)存的,那我能不能通過對(duì)指針進(jìn)行操作去部分釋放動(dòng)態(tài)分配的內(nèi)存呢?然而夢(mèng)想很美好,現(xiàn)實(shí)很骨感。如果強(qiáng)行這樣做的話只可能會(huì)造成·更多不可預(yù)估的結(jié)果。
3.5 對(duì)同一塊動(dòng)態(tài)內(nèi)存多次釋放
這個(gè)錯(cuò)誤應(yīng)該大家目前應(yīng)該不太常犯,但是一旦后面代碼量大了之后就很有可能忘記是否已經(jīng)釋放過內(nèi)存從而導(dǎo)致重復(fù)釋放而bug。
3.6 動(dòng)態(tài)開辟內(nèi)存忘記釋放(內(nèi)存泄漏)
void test() { int *p = (int *)malloc(100); if(NULL != p) { *p = 20; } } int main() { test(); while(1); }
看到這個(gè)標(biāo)題再看這串代碼,大家應(yīng)該都很容易能夠知道上面的代碼忘記釋放內(nèi)存了從而導(dǎo)致內(nèi)存泄漏,但實(shí)際日常我們非常容易忘記開辟內(nèi)存后free。
忘記釋放不再使用的動(dòng)態(tài)開辟的空間會(huì)造成內(nèi)存泄漏。
切記:
動(dòng)態(tài)開辟的空間一定要釋放,并且正確釋放 。
總結(jié)
到此這篇關(guān)于關(guān)于C語言動(dòng)態(tài)內(nèi)存管理介紹的文章就介紹到這了,更多相關(guān)C語言動(dòng)態(tài)內(nèi)存內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
關(guān)于C++中0是十進(jìn)制還是八進(jìn)制的問題
本篇文章中,小編將為大家介紹關(guān)于C++中0是十進(jìn)制還是八進(jìn)制的問題,有需要的朋友可以參考一下2013-04-04C語言執(zhí)行時(shí),程序控制臺(tái)輸出窗口 一閃而過問題及解決
這篇文章主要介紹了C語言執(zhí)行時(shí),程序控制臺(tái)輸出窗口 一閃而過問題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11C++中整形與浮點(diǎn)型如何在內(nèi)存中的存儲(chǔ)詳解
大家好!這期和大家分享整形和浮點(diǎn)型是如何在數(shù)據(jù)是如何在內(nèi)存中存儲(chǔ),下面文章具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-05-05C++簡單五子棋的AI設(shè)計(jì)實(shí)現(xiàn)
這篇文章主要為大家詳細(xì)介紹了C++簡單五子棋的AI設(shè)計(jì)實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-09-09