c語言記憶體管理、野指標、malloc
C語言一共定義四個區塊:程式碼區、全域性變數和靜態變數區、棧、堆
針對四個區塊,使用者的記憶體分配也有三種不同的方式:
靜態變數區:在程式碼編譯的時候就分配好了,比如全域性變數,被static定義的變數
堆:這需要程式設計師自己分配和釋放,分別使用malloc和free函式
棧:在程式執行的時候,系統會自動的給程式分配記憶體,在程式結束的時候,就自動的釋放
堆和棧的區別:
分配方式不同:
棧是在程式執行的時候,由系統自動分配的,在程式執行完,自動釋放的
堆是的申請和釋放都是由程式設計師自己完成
空間大小不同:
(1)棧:棧是向低地址擴充套件的資料結構,是一塊連續的記憶體區域(它的生長方向與記憶體的生長方向相反)。棧的大小是固定的。如果申請的空間超過棧的剩餘空間時,將提示overflow。
(2)堆:堆是高地址擴充套件的資料結構(它的生長方向與記憶體的方向相同),是不連續的記憶體區域。這是由於系統使用連結串列來儲存空閒記憶體地址的,自然是不連續的,而連結串列的遍歷方向是由底地址向高地址。堆的大小受限於計算機系統中有效的虛擬記憶體。
碎片:
對於堆來講,頻繁的new/delete勢必會造成記憶體空間的不連續,從而造成大量的碎片,使程式效率降低。對於棧來講,則不會存在這個問題,1、程式碼區:存放我們編寫的程式碼和字串常量,屬性是隻讀的,所以不用太多的討論
2、全域性變數和靜態變數區:存放通過static關鍵字定義的變數,這塊區域的資料在程式編譯時就存在,在程式執行結束後釋放。
3、棧區:在棧上存放,儲存函式執行時的區域性變數,函式執行結束後自動釋放,獲取和釋放都是程式自動執行的,不需要程式設計師操作。
4、堆區:我的理解是,堆區一般存放的是指標變數,需要通過函式malloc()申請。
實際上,堆區存放的一般是隻有在程式執行的時候才能確定的變數,因為無法確定變數的大小,編譯器無法給這些變數分配空間,所以需要程式設計師手動分配記憶體空間。
注意:malloc()和free()函式要成對出現,
若只有malloc()無free()會造成記憶體的洩露(只分配沒釋放,別的變數無法再使用該區域)
若free()過多,則會出錯,因為該區域可能已經被再分配(在別的檔案中分配)。
野指標:指向的地址是不確定的指標
有三種情況會造成野指標的出現
1、指標定義之後沒有初始化,其值是不確定的
2、指標被free後,沒有賦值NULL,後續又使用了該指標
3、指標的操作超越了變數的作用範圍(不是指標越界)
4、函式返回指向棧記憶體的指標(棧記憶體在函式執行結束後被釋放)
遺留問題:
問題一:野指標出現情況第三條,指標的操作超越了變數的作用範圍,例
int main()
{
int a[5] = {1,2,3,4,5},*p,i,n;
n = sizeof(a)/sizeof(n);
p = a;
for(i=0;i<=n;i++)
{
printf("%d", *p);
p++;//程式執行後,p指向陣列以外的空間
}
*p =100; //對非法記憶體進行寫操作
printf("*p=%d\n",*p);
return 0;
}
假設:a = 0x99f90000,這是陣列a的首地址,也是元素a[0]的首地址,for迴圈執行結束之後,p的值0x99f90005,指向的是元素a[4]的下一個地址,雖然這個地址所儲存的資料是不確定的,但是此地址是確定的,為什麼說是非法記憶體呢?
因為a這個陣列中並沒有a[5]這個成員變數,也就是說棧中沒有為a[5]分配棧空間。