C語(yǔ)言中堆上內(nèi)存分配和棧上變量的區(qū)別及使用malloc和calloc在堆上分配內(nèi)存
在C語(yǔ)言中,我們經(jīng)常需要在程序運(yùn)行時(shí)動(dòng)態(tài)地分配內(nèi)存。堆和棧是兩個(gè)常用的內(nèi)存分配方式。區(qū)別在于棧上的變量由編譯器自動(dòng)管理,而堆上的內(nèi)存則需要手動(dòng)分配和釋放。為在堆上分配內(nèi)存,我們通常會(huì)使用兩個(gè)函數(shù):ma
在C語(yǔ)言中,我們經(jīng)常需要在程序運(yùn)行時(shí)動(dòng)態(tài)地分配內(nèi)存。堆和棧是兩個(gè)常用的內(nèi)存分配方式。區(qū)別在于棧上的變量由編譯器自動(dòng)管理,而堆上的內(nèi)存則需要手動(dòng)分配和釋放。
為在堆上分配內(nèi)存,我們通常會(huì)使用兩個(gè)函數(shù):malloc和calloc。它們的功能類似,都可以用來(lái)分配指定大小的內(nèi)存塊。其中,malloc需要傳入一個(gè)代表要分配的字節(jié)數(shù)的參數(shù),而calloc則需要傳入兩個(gè)參數(shù),表示要分配的元素個(gè)數(shù)和每個(gè)元素的字節(jié)大小。
以使用malloc函數(shù)為例,代碼如下:
```c
int *b (int *) malloc(sizeof(int) * 10);
```
這段代碼會(huì)在堆上分配10個(gè)整型的內(nèi)存,并把分配到的內(nèi)存的首地址賦給b。需要注意的是,使用malloc分配的數(shù)組看起來(lái)和直接聲明的數(shù)組類似,一樣可以通過(guò)下標(biāo)訪問(wèn)和使用。但是,其本質(zhì)不同,一個(gè)在棧上,一個(gè)在堆上。
對(duì)比匯編代碼可以更好地理解這個(gè)區(qū)別。關(guān)于棧上變量a和堆上變量b的匯編有很大不同,無(wú)論是聲明還是訪問(wèn)。具體來(lái)說(shuō),int a[10]并不對(duì)應(yīng)任何匯編。這句話只是告知編譯器,在棧上預(yù)定10個(gè)int的空間,好吧a[0]、a[1]...映射到棧上。a的地址并不存儲(chǔ)在堆或棧上,而是被寫(xiě)進(jìn)了匯編碼的操作數(shù)。而malloc函數(shù)的調(diào)用,則會(huì)有實(shí)際代碼執(zhí)行,并且把堆上的地址存入b。b是棧上的一個(gè)變量。
對(duì)a[0]和a[6]的賦值代碼需要三條語(yǔ)句,調(diào)入一個(gè)int的字節(jié)數(shù)4,計(jì)算與a[0]的地址偏移,根據(jù)棧底指針ebp算出編譯器決定的a[0]位置ebp 2Ch,然后加上偏移得到a[i]的位置并操作。而對(duì)b[0]和b[6]的賦值代碼需要四條語(yǔ)句,調(diào)入一個(gè)int的字節(jié)數(shù)4,計(jì)算與b[0]的地址偏移,從棧上的指針變量b獲得堆上b[0]的地址,再根據(jù)b[0]算出b[i]在堆上的位置并操作。
通過(guò)上述對(duì)比,我們可以更形象地認(rèn)識(shí)到使用malloc函數(shù),棧上的變量b持有堆上b[0]所在的地址。而直接聲明變量int a[10],則a不存在,a[0]是一個(gè)地址常量,由編譯器寫(xiě)進(jìn)匯編。
綜上所述,堆和棧的內(nèi)存分配方式各有優(yōu)缺點(diǎn),需要根據(jù)具體情況進(jìn)行選擇。同時(shí),使用malloc和calloc函數(shù)在堆上分配內(nèi)存時(shí)需要注意及時(shí)釋放內(nèi)存避免內(nèi)存泄漏。