1. 程式人生 > >C/C++中的malloc、calloc和realloc

C/C++中的malloc、calloc和realloc

1. malloc

原型:extern void *malloc(unsigned int num_bytes);
標頭檔案:Visual C++6.0中可以用malloc.h或者stdlib.h
功能:分配長度為num_bytes位元組的記憶體塊
返回值:如果分配成功則返回指向被分配記憶體的指標(此儲存區中的初始值不確定),否則返回空指標NULL。當記憶體不再使用時,應使用free()函式將記憶體塊釋放。函式返回的指標一定要適當對齊,使其可以用於任何資料物件。

函式宣告:void *malloc(size_t size);

說明:malloc向系統申請分配指定size個位元組的記憶體空間。返回型別是void*

型別。void*表示未確定型別的指標。C,C++規定,void* 型別可以強制轉換為任何其它型別的指標。

備註:
  void*表示未確定型別的指標,更明確的說是指申請記憶體空間時還不知道使用者是用這段空間來儲存什麼型別的資料(比如是char還是int或者...)
  從函式宣告上可以看出。mallocnew至少有兩個不同:`new返回指定型別的指標,並且可以自動計算所需要大小。

比如:

int *p;
p = new int; //返回型別為int* 型別(整數型指標),分配大小為 sizeof(int);

// 或:
int* parr;
parr = new int [100]; //返回型別為 int* 型別(整數型指標),分配大小為 sizeof(int) * 100;

malloc則必須要由我們計算位元組數,並且在返回後強行轉換為實際型別的指標。

int* p;
//分配128個(可根據實際需要替換該數值)整型儲存單元,並將這128個連續的整型儲存單元的首地址儲存到指標變數p中
p = (int *) malloc (sizeof(int)*128);
//分配12個double型儲存單元,並將首地址儲存到指標變數pd中
double *pd=(double *) malloc (sizeof(double)*12);

使用malloc時要注意:

  • malloc函式返回的是void *型別。對於C++,如果你寫成:p = malloc (sizeof(int));
    則程式無法通過編譯,報錯:“不能將void*賦值給int *型別變數”。所以必須通過(int *)來將強制轉換。而對於C,沒有這個要求,但為了使C程式更方便的移植到C++中來,建議養成強制轉換的習慣
  • 函式的實參為sizeof(int),用於指明一個整型資料需要的大小。如果你寫成:
int* p = (int *) malloc (1);

程式碼也能通過編譯,但事實上只分配了1個位元組大小的記憶體空間,當你往裡頭存入一個整數,就會有3個位元組無家可歸,而直接“住進鄰居家”!造成的結果是後面的記憶體中原有資料內容被改寫。

malloc內部機制

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

2. calloc

函式宣告:void *calloc(unsigned n,unsigned size);
功能:在記憶體的動態儲存區中分配n個長度為size的連續空間,函式返回一個指向分配起始地址的指標,如果分配不成功,返回NULL

malloc的區別:
calloc在動態分配完記憶體後,自動初始化該記憶體空間為零,而malloc不初始化,裡邊資料是隨機的垃圾資料。

3. realloc

原型:extern void *realloc(void *mem_address, unsigned int newsize);
標頭檔案:#include <stdlib.h>
功能:先判斷當前的指標是否有足夠的連續空間,如果有,擴大mem_address指向的地址,並且將mem_address返回,如果空間不夠,先按照newsize指定的大小分配空間,將原有資料從頭到尾拷貝到新分配的記憶體區域,而後釋放原來mem_address所指記憶體區域,同時返回新分配的記憶體區域的首地址。即重新分配儲存器塊的地址。
返回值:如果重新分配成功則返回指向被分配記憶體的指標,否則返回空指標NULL
使用語法:指標名 = (資料型別*)realloc(要改變記憶體大小的指標名,新的大小)。//新的大小一定要大於原來的大小不然的話會導致資料丟失!

注意:這裡原始記憶體中的資料還是保持不變的。當記憶體不再使用時,應使用free()函式將記憶體塊釋放。