【基礎C&C++】內存函數

 1.malloc函數

原型:extern void *malloc(unsigned int num_bytes);

  頭文件:在TC2.0中可以用malloc.h或 alloc.h (注意:alloc.h 與 malloc.h 的內容是完全一致的),而在Visual C++6.0中可以用malloc.h或者stdlib.h

  功能:分配長度爲num_bytes字節的內存塊

  返回值:如果分配成功則返回指向被分配內存的指針,否則返回空指針NULL。當內存不再使用時,應使用free()函數將內存塊釋放。

說明:關於該函數的原型,在舊的版本中malloc返回的是char型指針,新的ANSIC標準規定,該函數返回爲void型指針,因此必要時要進行類型轉換。void*類型可以強制轉換爲任何其它類型的指針。

1.1 malloc實現機制

    malloc函數的實質體現在,它有一個將可用的內存塊連接爲一個長長的列表的所謂空閒鏈表。調用malloc函數時,它沿連接表尋找一個大到足以滿足用戶請求所需要的內存塊。然後,將該內存塊一分爲二(一塊的大小與用戶請求的大小相等,另一塊的大小就是剩下的字節)。接下來,將分配給用戶的那塊內存傳給用戶,並將剩下的那塊(如果有的話)返回到連接表上。調用free函數時,它將用戶釋放的內存塊連接到空閒鏈上。到最後,空閒鏈會被切成很多的小內存片段,如果這時用戶申請一個大的內存片段,那麼空閒鏈上可能沒有可以滿足用戶要求的片段了。於是,malloc函數請求延時,並開始在空閒鏈上翻箱倒櫃地檢查各內存片段,對它們進行整理,將相鄰的小空閒塊合併成較大的內存塊。如果無法獲得符合要求的內存塊,malloc函數會返回NULL指針,因此在調用malloc動態申請內存塊時,一定要進行返回值的判斷。

1.2 malloc 和 new 比較

從函數聲明上可以看出。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 * 類型。對於C++,如果你寫成:p = malloc (sizeof(int)); 則程序無法通過編譯,報錯:“不能將 void* 賦值給 int * 類型變量”。所以必須通過 (int *) 來將強制轉換。而對於C,沒有這個要求,但爲了使C程序更方便的移植到C++中來,建議養成強制轉換的習慣。

  第二、函數的實參爲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("Gota null pointer");

  else

  puts("Gota valid pointer");

  此時得到的是Got avalid pointer。把0賦給malloc能得到一個合法的指針。

2. calloc函數

用 法: void *calloc(unsigned n,unsignedsize);

功 能: 在內存的動態存儲區中分配n個長度爲size的連續空間,函數返回一個指向分配起始地址的指針;如果分配不成功,返回NULL。

  跟malloc的區別:

  calloc在動態分配完內存後,自動初始化該內存空間爲零,而malloc不初始化,裏邊數據是隨機的垃圾數據

3. alloca

void * __cdecl alloca(size_t);

 內存分配函數,與malloc,calloc,realloc類似.

  但是注意一個重要的區別,_alloca是在棧(stack)上申請空間,用完馬上就釋放.

  包含在頭文件malloc.h中.

         alloca不具可移植性, 而且在沒有傳統堆棧的機器上很難實現。

  當它的返回值直接傳入另一個函數時會帶來問題,因爲他分配在棧上.

  由於這些原因, alloca不宜使用在必須廣泛移植的程序中, 不管它可能多麼有用。

4.realloc

extern void *realloc(void *mem_address, unsigned intnewsize);

 頭文件:#include <stdlib.h> 有些編譯器需要#include <alloc.h>,在TC2.0中可以使用alloc.h頭文件

  功能:先按照newsize指定的大小分配空間,將原有數據從頭到尾拷貝到新分配的內存區域,而後釋放原來mem_address所指內存區域,同時返回新分配的內存區域的首地址。即重新分配存儲器塊的地址。

  返回值:如果重新分配成功則返回指向被分配內存的指針,否則返回空指針NULL。 

注意:這裏原始內存中的數據還是保持不變的。當內存不再使用時,應使用free()函數將內存塊釋放。

詳細說明及注意要點

1、如果有足夠空間用於擴大mem_address指向的內存塊,則分配額外內存,並返回mem_address

  這裏說的是“擴大”,我們知道,realloc是從堆上分配內存的,當擴大一塊內存空間時, realloc()試圖直接從堆上現存的數據後面的那些字節中獲得附加的字節,如果能夠滿足,自然天下太平。也就是說,如果原先的內存大小後面還有足夠的空閒空間用來分配,加上原來的空間大小= newsize。那麼就ok。得到的是一塊連續的內存。

  2、如果原先的內存大小後面沒有足夠的空閒空間用來分配,那麼從堆中另外找一塊newsize大小的內存。並把原來大小內存空間中的內容複製到newsize中。返回新的mem_address指針。(數據被移動了)。老塊被放回堆上。

特殊情況

  如果mem_address爲null,則realloc()和malloc()類似。分配一個newsize的內存塊,返回一個指向該內存塊的指針。

  如果newsize大小爲0,那麼釋放mem_address指向的內存,並返回null。

 

 

 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章