標頭檔案:#include 或 #include (注意:alloc.h 與 malloc.h 的內容是完全一致的。)
功能:分配長度為num_bytes位元組的記憶體塊
說明:如果分配成功則返回指向被分配記憶體的指標,否則返回空指標NULL。
當記憶體不再使用時,應使用free()函式將記憶體塊釋放。
舉例:
/*malloc.c*/
#include
#include
main()
{
char *p;
clrscr(); /*clear screen*/
p=(char *)malloc(100);
if(p)
printf("Memory Allocated at: %x",p);
else
printf("Not Enough Memory!n");
free(p);
getchar();
return 0;
}
函式宣告(函式原型):
void *malloc(int size);
說明:malloc 向系統申請分配指定size個位元組的記憶體空間。返回型別是 void* 型別。void* 表示未確定型別的指標。C,C++規定,void* 型別可以強制轉換為任何其它型別的指標。
從函式宣告上可以看出。malloc 和 new 至少有兩個不同: new 返回指定型別的指標,並且可以自動計算所需要大小。比如:
int *p;
p = new int; //返回型別為int* 型別(整數型指標),分配大小為 sizeof(int);
或:
int* parr;
parr = new int [100]; //返回型別為 int* 型別(整數型指標),分配大小為 sizeof(int) * 100; 而 malloc 則必須由我們計算要位元組數,並且在返回後強行轉換為實際型別的指標。
int* p;
p = (int *) malloc (sizeof(int));
第一、malloc 函式返回的是 void * 型別,如果你寫成:p = malloc (sizeof(int)); 則程式無法透過編譯,報錯:“不能將 void* 賦值給 int * 型別變數”。所以必須透過 (int *) 來將強制轉換。
第二、函式的實參為 sizeof(int) ,用於指明一個整型資料需要的大小。如果你寫成:
int* p = (int *) malloc (1);
程式碼也能透過編譯,但事實上只分配了1個位元組大小的記憶體空間,當你往裡頭存入一個整數,就會有3個位元組無家可歸,而直接“住進鄰居家”!造成的結果是後面的記憶體中原有資料內容全部被清空。
malloc 也可以達到 new [] 的效果,申請出一段連續的記憶體,方法無非是指定你所需要記憶體大小。
比如想分配100個int型別的空間:
int* p = (int *) malloc ( sizeof(int) * 100 ); //分配可以放得下100個整數的記憶體空間。
另外有一點不能直接看出的區別是,malloc 只管分配記憶體,並不能對所得的記憶體進行初始化,所以得到的一片新記憶體中,其值將是隨機的。
除了分配及最後釋放的方法不一樣以外,透過malloc或new得到指標,在其它操作上保持一致。
對其做一個特例補充
char *ptr;
if ((ptr = (char *)malloc(0)) == NULL)
puts("Got a null pointer");
else
puts("Got a valid pointer");
此時得到的是Got a valid pointer。把0賦給malloc能得到一個合法的指標。
malloc()函式的工作機制
malloc函式的實質體現在,它有一個將可用的記憶體塊連線為一個長長的列表的所謂空閒連結串列。呼叫malloc函式時,它沿連線表尋找一個大到足以滿足使用者請求所需要的記憶體塊。然後,將該記憶體塊一分為二(一塊的大小與使用者請求的大小相等,另一塊的大小就是剩下的位元組)。接下來,將分配給使用者的那塊記憶體傳給使用者,並將剩下的那塊(如果有的話)返回到連線表上。呼叫free函式時,它將使用者釋放的記憶體塊連線到空閒鏈上。到最後,空閒鏈會被切成很多的小記憶體片段,如果這時使用者申請一個大的記憶體片段,那麼空閒鏈上可能沒有可以滿足使用者要求的片段了。於是,malloc函式請求延時,並開始在空閒鏈上翻箱倒櫃地檢查各記憶體片段,對它們進行整理,將相鄰的小空閒塊合併成較大的記憶體塊。
realloc
原型:extern void *realloc(void *mem_address, unsigned int newsize);
功能:改變mem_address所指記憶體區域的大小為newsize長度。
說明:如果重新分配成功則返回指向被分配記憶體的指標,否則返回空指標NULL。
當記憶體不再使用時,應使用free()函式將記憶體塊釋放。
注意:這裡原始記憶體中的資料還是保持不變的。
舉例:
// realloc.c
#include
#include
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
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.而原來的記憶體塊保持不變。