在進行C/C++編程的時候,需要程序員對內存的了解比較清楚,經常需要操作的內存可分為下面幾個類別:
1.堆棧區(stack):由編譯器自動分配與釋放,存放函數的參數值,局部變量,臨時變量等等,它們獲取的方式都是由編譯器自動執行的; 2.堆區(heap):一般由程序員分配與釋放,如果編程者不釋放,程序結束時可能由操作系統回收(注意:C/C++沒有這種回收機制,但Java/C#有)。我們這裡說的堆區與數據結構中的堆是兩回事,分配方式類似於鏈表; 3.全局區(靜態區)(static):全局變量和靜態變量的存儲是放在一塊兒的,初始化的全局變量和靜態變量在一塊區域,未初始化的全局變量和未初始化的靜態變量在相鄰的另一塊區域,程序結束後由系統釋放。 4.文字常量區:常量字符串是放在這裡的,程序結束後由系統釋放。 5.程序代碼區:存放函數體的二進制代碼。
C標准函數庫提供了許多函數來實現對堆上內存管理,其中包括:malloc函數、calloc函數、realloc函數和free函數。使用這些函數需要包含頭文件stdlib.h。
它們的聲明如下:
•void* malloc(int n);
•void free (void * p);
•void* calloc(int n,int size);
•void* realloc(void * p,int n);
1. malloc函數
malloc函數可以從堆上獲得指定字節的內存空間,其函數聲明如下:
void* malloc(int n);
若函數執行成功,malloc返回獲得內存空間的首地址;當函數執行失敗,就返回NULL。其中,形參n為要求分配的字節數。由於malloc函數值的類型為void型指針,所以將其值類型轉換後可以賦給任意類型指針,這樣就可以通過操作該類型指針來操作從堆上獲得的內存空間。
通過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. calloc函數
calloc函數的功能與malloc函數的功能相似,都是從堆分配內存。
其函數聲明如下:
void *calloc(int n,int size);
函數返回值為void型指針。如果執行成功,函數從堆上獲得大小為size*n個字節空間,並返回該空間的首地址。如果執行失敗,函數返回NULL。
該函數與malloc函數的一個顯著不同時是,calloc函數得到的內存空間是經過初始化的,其內容全為0。calloc函數適合為數組申請空間,可以將size設置為數組元素的空間長度,將n設置為數組的容量。
3. realloc函數
用realloc函數可以實現內存分配和內存釋放的功能,其函數聲明如下:
void * realloc(void * p,int n);
其中,指針p為指向堆內存空間的指針,即由malloc函數、calloc函數或realloc函數分配空間的指針。realloc函數將指針p指向的內存塊的大小改變為n字節。如果n小於或等於p之前指向的空間大小,那麼。保持原有狀態不變。如果n大於原來p之前指向的空間大小,系統將重新為p從堆上分配一塊大小為n的內存空間;同時,將原來指向空間的內容依次復制到新的內存空間上,p之前指向的空間被釋放。relloc函數分配的空間也是未初始化的。
4. free函數
從堆上獲得的內存空間在程序結束以後,系統不會將其自動釋放,需要編程者自己來管理。一個程序結束時,必須保證所有從堆上獲得的內存空間已被安全釋放,否則,會導致內存洩露。例如上面的代碼就會發生內存洩露。
free函數可以實現釋放內存的功能。其函數聲明為:
void free ( * p);
free函數只是釋放指向原來指向的地方,這時的指針為野指針,如果此時操作該指針會導致不可預期的錯誤。
所以當在使用free函數釋放指針指向的空間之後,應該將指針的值置為NULL。對於上面的代碼,需要程序結束前加入以下兩行語句:
free(p);
p=NULL;
注意:使用malloc函數,calloc函數和realloc函數分配的內存空間都要使用free函數來釋放;free函數可以接受任意類型的指針實參。
malloc()分配的空間沒有初始化,relloc()如果沒有足夠可用的內存用來完成重新分配(擴大原來的內存塊或者分配新的內存塊),則返回null.而原來的內存塊保持不變。