malloc/calloc/realloc/alloca內存分配函數


calloc(), malloc(), realloc(), free(),alloca()

內存區域可以分為棧、堆、靜態存儲區和常量存儲區,局部變量,函數形參,臨時變量都是在棧上獲得內存的,它們獲取的方式都是由編譯器自動執行的。
利用指針,我們可以像匯編語言一樣處理內存地址,C 標准函數庫提供了許多函數來實現對堆上內存管理,其中包括:malloc函數,free函數,calloc函數和realloc函數。使用這些函數需要包含頭文件stdlib.h。

四個函數之間的有區別,也有聯系,我們應該學會把握這種關系,從而編出精煉而高效的程序。

在說明它們具體含義之前,先簡單從字面上加以認識,前3個函數有個共同的特點,就是都帶有字符”alloc”,就是”allocate”,”分配”的意思,也就是給對象分配足夠的內存,” calloc()”是”分配內存給多個對象”,” malloc()”是”分配內存給一個對象”,”realloc()”是”重新分配內存”之意。”free()”就比較簡單了,”釋放”的意思,就是把之前所分配的內存空間給釋放出來。

void *calloc(size_t nobj, size_t size);

分配足夠的內存給nobj個大小為size的對象組成的數組, 並返回指向所分配區域的第一個字節的指針;
若內存不夠,則返回NULL. 該空間的初始化大小為0字節.
char *p = (char *) calloc(100,sizeof(char));


void *malloc(size_t size);

分配足夠的內存給大小為size的對象, 並返回指向所分配區域的第一個字節的指針;
若內存不夠,則返回NULL. 不對分配的空間進行初始化.
char *p = (char *)malloc(sizeof(char));


void *realloc(void *p, size_t size);

將p所指向的對象的大小改為size個字節.
如果新分配的內存比原內存大, 那么原內存的內容保持不變, 增加的空間不進行初始化.
如果新分配的內存比原內存小, 那么新內存保持原內存的內容, 增加的空間不進行初始化.
返回指向新分配空間的指針; 若內存不夠,則返回NULL, 原p指向的內存區不變.
char *p = (char *)malloc(sizeof(char));
p= (char *)realloc(p, 256);


void free(void *p);

釋放p所指向的內存空間; 當p為NULL時, 不起作用.
p必先調用calloc, malloc或realloc.


值得注意的有以下5點:

(1)通過malloc函數得到的堆內存必須使用memset函數來初始化

malloc函數分配得到的內存空間是未初始化的。因此,一般在使用該內存空間時,要調用另一個函數memset來將其初始化為全0,memset函數的聲明如下:void * memset (void * p,int c,int n) ;

該函數可以將指定的內存空間按字節單位置為指定的字符c,其中,p為要清零的內存空間的首地址,c為要設定的值,n為被操作的內存空間的字節長度。如果要用memset清0,變量c實參要為0。

malloc函數和memset函數的操作語句一般如下:

int * p=NULL;

p=(int*)malloc(sizeof(int));

if(p==NULL)

printf(“Can’t get memory!\n”);

memset(p,0,siezeof(int));

(2)使用malloc函數分配的堆空間在程序結束之前必須釋放

從堆上獲得的內存空間在程序結束以后,系統不會將其自動釋放,需要程序員來自己管理。一個程序結束時,必須保證所有從堆上獲得的內存空間已被安全釋放,否則,會導致內存泄露。

我們可以使用free()函數來釋放內存空間,但是,free函數只是釋放指針指向的內容,而該指針仍然指向原來指向的地方,此時,指針為野指針,如果此時操作該指針會導致不可預期的錯誤。安全做法是:在使用free函數釋放指針指向的空間之后,將指針的值置為NULL。

(3)calloc函數的分配的內存也需要自行釋放

calloc函數的功能與malloc函數的功能相似,都是從堆分配內存,它與malloc函數的一個顯著不同時是,calloc函數得到的內存空間是經過初始化的,其內容全為0。calloc函數適合為數組申請空間,可以將size設置為數組元素的空間長度,將n設置為數組的容量。

(4)如果要使用realloc函數分配的內存,必須使用memset函數對其內存初始化

realloc函數的功能比malloc函數和calloc函數的功能更為豐富,可以實現內存分配和內存釋放的功能。realloc 可以對給定的指針所指的空間進行擴大或者縮小,無論是擴張或是縮小,原有內存的中內容將保持不變。當然,對於縮小,則被縮小的那一部分的內容會丟失。realloc 並不保證調整后的內存空間和原來的內存空間保持同一內存地址。相反,realloc 返回的指針很可能指向一個新的地址。

所以,在代碼中,我們必須將realloc返回的值,重新賦值給 p :

p = (int *) realloc(p, sizeof(int) *15);

甚至,你可以傳一個空指針(0)給 realloc ,則此時realloc 作用完全相當於malloc。

int* p = (int *)realloc (0,sizeof(int) * 10); //分配一個全新的內存空間,

這一行,作用完全等同於:

int* p = (int *)malloc(sizeof(int) * 10);

(5)關於alloca()函數

還有一個函數也值得一提,這就是alloca()。其調用序列與malloc相同,但是它是在當前函數的棧幀上分配存儲空間,而不是在堆中。其優點是:當 函數返回時,自動釋放它所使用的棧幀,所以不必再為釋放空間而費心。其缺點是:某些系統在函數已被調用后不能增加棧幀長度,於是也就不能支持alloca 函數。盡管如此,很多軟件包還是使用alloca函數,也有很多系統支持它。

 

總結:應用時候需要記得,只有calloc可以指定個數和大小,而且能夠對分配內存進行初始化,其余函數均不會對內存進行初始化工作,需要自行調用memset()函數.

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM