1. 程式人生 > >c語言記憶體管理、野指標、malloc

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]分配棧空間。