【摘要】malloc、calloc和realloc的用法


轉載自:https://blog.csdn.net/snlying/article/details/4005238

 

realloc 
原型:extern void *realloc(void *mem_address, unsigned int newsize); 
用法:#include <stdlib.h> 有些編譯器需要#include <alloc.h> 
功能:改變mem_address所指內存區域的大小為newsize長度。 
說明:如果重新分配成功則返回指向被分配內存的指針,否則返回空指針NULL。 
當內存不再使用時,應使用free()函數將內存塊釋放。 
注意:這里原始內存中的數據還是保持不變的。 
舉例: 
// realloc.c 
#include <syslib.h> 
#include <alloc.h> 
main() 

char *p; 
clrscr(); // clear screen 
p=(char *)malloc(100); 
if(p) 
printf("Memory Allocated at: %x",p); 
else 
printf("Not Enough Memory!/n"); 
getchar(); 
p=(char *)realloc(p,256); 
if(p) 
printf("Memory Reallocated at: %x",p); 
else 
printf("Not Enough Memory!/n"); 
free(p); 
getchar(); 
return 0; 

詳細說明及注意要點: 
1、如果有足夠空間用於擴大mem_address指向的內存塊,則分配額外內存,並返回mem_address 
這里說的是“擴大”,我們知道,realloc是從堆上分配內存的,當擴大一塊內存空間時, realloc()試圖直接從堆上現存的數據后面的那些字節中獲得附加的字節,如果能夠滿足,自然天下太平。也就是說,如果原先的內存大小后面還有足夠的空閑空間用來分配,加上原來的空間大小= newsize。那么就ok。得到的是一塊連續的內存。 
2、如果原先的內存大小后面沒有足夠的空閑空間用來分配,那么從堆中另外找一塊newsize大小的內存。 
並把原來大小內存空間中的內容復制到newsize中。返回新的mem_address指針。(數據被移動了)。 
老塊被放回堆上。 
例如: 
#include <malloc.h> 
char *p,*q; 
p = (char * ) malloc (10); 
q=p; 
p = (char * ) realloc (p,20); 
………………………… 
這段程序也許在編譯器中沒有辦法通過,因為編譯器可能會為我們消除一些隱患!在這里我們只是增加了一個記錄原來內存地址的指針q,然后記錄了原來的內存地址p,如果不幸的話,數據發生了移動,那么所記錄的原來的內存地址q所指向的內存空間實際上已經放回到堆上了!這樣一來,我們應該終於意識到問題的所在和可怕了吧! 
3、返回情況 
返回的是一個void類型的指針,調用成功。(這就再你需要的時候進行強制類型轉換) 
返回NULL,當需要擴展的大小(第二個參數)為0並且第一個參數不為NULL,此時原內存變成了“freed(游離)”的了。 
返回NULL,當沒有足夠的空間可供擴展的時候,此時,原內存空間的大小維持不變。 
4、特殊情況 
如果mem_address為null,則realloc()和malloc()類似。分配一個newsize的內存塊,返回一個指向該內存塊的指針。 
如果newsize大小為0,那么釋放mem_address指向的內存,並返回null。 
如果沒有足夠可用的內存用來完成重新分配(擴大原來的內存塊或者分配新的內存塊),則返回null.而原來的內存塊保持不變。

==============================================================

 

void* malloc(unsigned size); void* calloc(size_t nelem, size_t elsize); 和void* realloc(void* ptr, unsigned newsize);都在stdlib.h函數庫內,是C語言的標准內存分配函數。
1. 函數malloc()和calloc()都可以用來動態分配內存空間。malloc()函數有一個參數,即要分配的內存空間的大小,malloc 在分配內存時會保留一定的空間用來記錄分配情況,分配的次數越多,這些記錄占用的空間就越多。另外,根據 malloc 實現策略的不同,malloc 每次在分配的時候,可能分配的空間比實際要求的多些,多次分配會導致更多的這種浪費。當然,這些都和 malloc 的實現有關;calloc()函數有兩個參數,分別為元素的數目和每個元素的大小,這兩個參數的乘積就是要分配的內存空間的大小。如果調用成功,它們都將返回所分配內存空間的首地址。
2. 函數malloc()和函數calloc()的主要區別是前者不能初始化所分配的內存空間,而后者能。
3. realloc可以對給定的指針所指的空間進行擴大或者縮小,無論是擴張或是縮小,原有內存的中內容將保持不變。當然,對於縮小,則被縮小的那一部分的內容會丟失。
4. realloc 並不保證調整后的內存空間和原來的內存空間保持同一內存地址。相反,realloc 返回的指針很可能指向一個新的地址。所以在代碼中,我們必須將realloc返回的值,重新賦值給 p :
p = (int *) realloc (p, sizeof(int) *15);

 

==================================================================

realloc 用過很多次了。無非就是將已經存在的一塊內存擴大。

char* p = malloc(1024);
char* q = realloc(p,2048);

現在的問題是我們應該如何處理指針 p。 剛開始按照我最直觀的理解,如果就是直接將 p = NULL;。 到最后只需要釋放 q的空間就可以了。

因為最近在做個封裝。結果在做單元測試的時候發現。有時候我在 free(q); 的時候會出錯。這樣我就郁悶了。

后來仔細一跟蹤,發現 realloc 完以后 q 和 p 的指針地址是一樣。不過有時候又不一樣。

仔細查了下資料。得到如下信息:

       1.如果 當前連續內存塊足夠 realloc 的話,只是將p所指向的空間擴大,並返回p的指針地址。 這個時候 q 和 p 指向的地址是一樣的。

       2.如果 當前連續內存塊不夠長度,再找一個足夠長的地方,分配一塊新的內存,q,並將 p指向的內容 copy到 q,返回 q。並將p所指向的內存空間刪除。

這樣也就是說 realloc 有時候會產生一個新的內存地址 有的時候不會。所以在分配完成后。我們需要判斷下 p 是否等於 q。並做相應的處理。

這里有點要注意的是要避免 p = realloc(p,2048); 這種寫法。有可能會造成 realloc 分配失敗后,p原先所指向的內存地址丟失。

 

=========================================

關於realloc函數說明的補充:
函數定義:
void *realloc(void *ptr, size_t size);
上面的分析基本沒有問題,但有兩點要注意:
1.返回值可能與ptr的值不同,如果是不同的話,那么realloc函數完成后,ptr指向的舊內存已被free掉了。
2。如果返回NULL值,則分配不成功,而原來的ptr指向的內存還沒有被free掉,要求程序顯式free.

故p = (int *) realloc (p, sizeof(int) *15);語句有這么一個問題,
調用前p指向一個已分配成功的內存,而調用realloc時卻失敗(即返回NULL),此時,p原來指向的內存還沒有free掉,而現在又找不到地址,這樣就出現memory leak了。

關於這一點的確要注意,最好如下:
int *q
q = (int *) realloc (p, sizeof(int) *15);

if(!q) p =q;

 

======================================================

 

首先看一下下面的C程序片斷:

 

#include <malloc.h>

char  *p;

p = (char * ) malloc (10);

p = (char * ) realloc (p,20);

…………………………

返回值分了幾種情況:

1、  返回void * 指針,調用成功。

2、  返回NULL,當需要擴展的大小(第二個參數)為0並且第一個參數不為NULL,此時原內存變成了“freed(游離)”的了。

3、  返回NULL,當沒有足夠的空間可供擴展的時候,此時,原內存空間的大小維持不變。

 

第一種情況告訴了我們在得到需要的內存空間后需要做類型轉換的工作;

第二種情況可能只有傻瓜才會去使用吧!

第三種情況,內存空間不夠的時候就會維持未來的大小不變。

 

        MSDN上面說內存空間不夠的時候就不會擴展原來的內存空間的大小,這話固然沒有錯,但是有點含糊,似乎遺漏了一種情況!我們知道,realloc是從堆上分配內存的,當擴大一塊內存空間時, realloc()試圖直接從堆上現存的數據后面的那些字節中獲得附加的字節,如果能夠滿足,自然天下太平;可如果數據后面的字節不夠的話,問題就出來了,那么就使用堆上第一個有足夠大小的自由塊,現存的數據然后就被拷貝至新的位置,而老塊則放回到堆上。這句話傳遞的一個重要的信息就是數據可能被移動!看到這里,也許我們已經發現一開始我給出的程序的問題了。為了更清楚地說明問題,可以將上面的程序改成下面的形式:

 

#include <malloc.h>

char  *p,*q;

p = (char * ) malloc (10);

q=p;

p = (char * ) realloc (p,20);

…………………………

    這段程序也許在編譯器中沒有辦法通過,因為編譯器可能會為我們消除一些隱患!在這里我們只是增加了一個記錄原來內存地址的指針q,然后記錄了原來的內存地址p,如果不幸的話,數據發生了移動,那么所記錄的原來的內存地址q所指向的內存空間實際上已經放回到堆上了!這樣一來,我們應該終於意識到問題的所在和可怕了吧!

    這個問題似乎有點牛角尖的味道,因為我們也許從來不曾遇上過,但是我們應該明白這樣的事情的始終存在,只有這樣,在萬一我們碰上的時候才會去有意識的去避免這種隱患,否則,一旦這樣的隱患一旦發作,程序崩潰不說,恐怕查錯也不是一件容易的事!

 


免責聲明!

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



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