前言:
記憶體區域劃分與配置設定:
1、棧區(stack)——程式運作時由編譯器自動配置設定,存放函數的參數值,局部變量的值等,程式結束時由編譯器自動釋放。
2、堆區(heap) —— 在記憶體開辟另一塊存儲區域。一般由程式員配置設定釋放, 若程式員不釋放,程式結束時可能由OS回收 。用malloc, calloc, realloc等配置設定記憶體的函數配置設定得到的就是在堆上。
3、全局區(靜态區)(static)——編譯器編譯時即配置設定記憶體。全局變量和靜态變量的存儲是放在一塊的。對于C語言初始化的全局變量和靜态變量在一塊區域, 未初始化的全局變量和未初始化的靜态變量在相鄰的另一塊區域。而C++則沒有這個差別 - 程式結束後由系統釋放
4、文字常量區 ——常量字元串就是放在這裡的, 程式結束後由系統釋放。
5、程式代碼區——存放函數體的二進制代碼。
初識記憶體配置設定函數malloc/ calloc/ realloc及記憶體釋放free
從前言中我們知道,如果要想申請一段動态記憶體需要常見的堆上記憶體管理函數malloc(), calloc(), recalloc(), free(),而堆上的記憶體空間不會自動釋放,直到調用free()函數,才會釋放堆上的存儲空間。
接下來我們一起來看一下這些函數具體實作及功能差別
1、malloc()
頭檔案:stdlib.h
聲明:void *malloc(size_t size);
含義:在堆上,配置設定size個位元組,并傳回void指針類型。
傳回值:配置設定記憶體成功,傳回配置設定的堆上存儲空間的首位址;否則,傳回NULL
例如:給一個長度為4的字元數組申請一個動态記憶體
char *p = (char *)malloc(4*sizeof(char));
2、calloc()
頭檔案:stdlib.h
聲明:void *calloc(size_t nobj, size_t size);
含義:在堆上,配置設定nobj*size個位元組,并初始化為0,傳回void* 類型
傳回值:同malloc() 函數
例如:給一個長度為4的字元數組申請一個動态記憶體,并初識化為0.
char *p = (char *)calloc(4,sizeof(char));
=char *p = (char *)malloc(4*sizeof(char));
for(int i=0;i<4;i++)
{
p[i]=0;
}
3、recalloc()
頭檔案:stdlib.h
聲明:void *realloc(void *p, size_t size);//新的大小一定要大于原來的大小不然的話會導緻資料丢失!
含義:重新配置設定堆上的void指針p所指的空間為個位元組,同時會複制原有内容到新配置設定的堆上存儲空間。注意,若原來的void指針p在堆上的空間不大于n個位元組,則保持不變。
傳回值:同malloc() 函數
例如:給一個長度為4的字元數組動态記憶體擴容為一個長度為8的字元數組
p=(char*)realloc(p,8*sizeof(char))
=char *p = (char *)malloc(4*sizeof(char));
for(int i=0;i<4;i++)
{
p[i]=i;
}
char *q = (char *)malloc(8*sizeof(char));
for(int i=0;i<4;i++)
{
q[i]=p[i];
}
free(p);
p=q;
q=NULL;
(過程大概如右:重新申請一段記憶體——>将原來的值移到新空間——>釋放原來記憶體——>更改位址)
4、free()
頭檔案:stdlib.h
聲明:void free(void *p);
含義:釋放void指針p所指的堆上的空間。
傳回值:無
對于free(p)這句語句,如果p 是NULL 指針,那麼free 對p無論操作多少次都不會出問題。如果p 不是NULL 指針,那麼free 對p連續操作兩次就會導緻程式運作錯誤。
free函數如何知道釋放的位置及大小?
答案:實際上在free釋放的時候會根據傳入的位址向前偏移一定位元組(頭), 從這些位元組中擷取具體的記憶體塊大小并釋放。
free 函數崩潰的原因:
1、越界(把尾資訊給破壞了)
2、修改指針的指向(free找不到頭資訊)
3、重複釋放同一段記憶體
4、釋放非動态建立的記憶體