記憶體的申請和釋放

2022-06-25 15:30:17 字數 4411 閱讀 8969

在c裡,記憶體管理是通過專門的函式來實現。另外,為了相容各種程式語言,作業系統提供的介面通常是c 語言寫成的函式宣告(windows 本身也由c和組合語言寫成)。

1分配記憶體malloc函式

需要包含標頭檔案:

and  

函式宣告(函式原型)

void *malloc(int size);

說明:malloc 向系統申請分配指定size個位元組的記憶體空間。返回型別是void* 型別。void* 表示未確定型別的指標。c,c++規定,void* 型別可以強制轉換為任何其它型別的指標。

從函式宣告上可以看出。malloc 和new 至少有兩個不同:new返回指定型別的指標,並且可以自動計算所需要大小。比如:

int *p;

p = new int; //返回型別為int* 型別(整數型指標),分配大小為sizeof(int);

或: int* parr;

parr = new int [100];  //返回型別為int* 型別(整數型指標),分配大小為sizeof(int) * 100;

malloc則必須由我們計算要位元組數,並且在返回後強行轉換為實際型別的指標。

int* p;

p = (int *)  malloc (sizeof(int));

第一、malloc 函式返回的是void * 型別,如果你寫成:p = malloc (sizeof(int)); 則程式無法通過編譯,報錯:「不能將void* 賦值給int * 型別變數」。所以必須通過(int *) 來將強制轉換。

第二、函式的實參為sizeof(int) ,用於指明乙個整型資料需要的大小。如果你寫成: 

int* p = (int *) malloc (1);

**也能通過編譯,但事實上只分配了1個位元組大小的記憶體空間,當你往裡頭存入乙個整數,就會有3個位元組無家可歸,而直接「住進鄰居家」!造成的結果是後面的記憶體中原有資料內容全部被清空。

malloc 也可以達到new  的效果,申請出一段連續的記憶體,方法無非是指定你所需要記憶體大小。

比如想分配100int型別的空間:

int* p = (int *) malloc ( sizeof(int) * 100 ); //分配可以放得下100個整數的記憶體空間。

另外有一點不能直接看出的區別是,malloc 只管分配記憶體,並不能對所得的記憶體進行初始化,所以得到的一片新記憶體中,其值將是隨機的。

除了分配及最後釋放的方法不一樣以外,通過malloc或new得到指標,在其它操作上保持一致。

2釋放記憶體free函式

需要包含標頭檔案(和malloc 一樣):

函式宣告:

void free(void *block);

即:void free(指標變數);

之所以把形參中的指標宣告為void* ,是因為free必須可以釋放任意型別的指標,而任意型別的指標都可以轉換為void *。

舉例:

int* p = (int *) malloc(4); 

*p = 100;

free(p); //釋放p 所指的記憶體空間

或者:int* p = (int *) malloc ( sizeof(int) * 100 ); //分配可以放得下100個整數的記憶體空間。

……free(p);

free不管你的指標指向多大的空間,均可以正確地進行釋放,這一點釋放比delete/delete  要方便。不過,必須注意,如果你在分配指標時,用的是new或new,那麼抱歉,當你在釋放記憶體時,你並不能圖方便而使用free來釋放。反過來,你用malloc 分配的記憶體,也不能用delete/delete 來釋放。一句話,new/deletenew/deletemalloc/free三對均需配套使用,不可混用!

3.calloc()realloc()

calloc()函式有兩個引數,分別為元素的數目和每個元素的大小,這兩個引數的乘積就是要分配的記憶體空間的大小:void *calloc(size_t numelements,size_t sizeofelement); 。

如果呼叫成功,函式malloc()和函式calloc()都將返回所分配的記憶體空間的首位址。函式malloc()和函式calloc()的主要區別是前者不能初始化所分配的記憶體空間,而後者能。如果由malloc()函式分配的記憶體空間原來沒有被使用過,則其中的每一位可能都是0;反之,如果這部分記憶體曾經被分配過,則其中可能遺留有各種各樣的資料。也就是說,使用malloc()函式的程式開始時(記憶體空間還沒有被重新分配)能正常進行,但經過一段時間(記憶體空間還已經被重新分配)可能會出現問題。

函式calloc()會將所分配的記憶體空間中的每一位都初始化為零,也就是說,如果你是為字元型別或整數型別的元素分配記憶體,那麼這些元素將保證會被初始化為0;如果你是為指標型別的元素分配記憶體,那麼這些元素通常會被初始化為空指標;如果你為實型資料分配記憶體,則這些元素會被初始化為浮點型的零。

realloc()

原型:extern void *realloc(void *mem_address, unsigned int newsize);

用法:#include 有些編譯器需要#include

功能:改變mem_address所指記憶體區域的大小為newsize長度。

說明:如果重新分配成功則返回指向被分配記憶體的指標,否則返回空指標null。

當記憶體不再使用時,應使用free()函式將記憶體塊釋放。

注意:這裡原始記憶體中的資料還是保持不變的。

舉例:// realloc.c

#include

#include

main()

詳細說明及注意要點:

1、如果有足夠空間用於擴大mem_address指向的記憶體塊,則分配額外記憶體,並返回mem_address

這裡說的是「擴大」,我們知道,realloc是從堆上分配記憶體的,當擴大一塊記憶體空間時,realloc()試圖直接從堆上現存的資料後面的那些位元組中獲得附加的位元組,如果能夠滿足,自然天下太平。也就是說,如果原先的記憶體大小後面還有足夠的空閒空間用來分配,加上原來的空間大小=newsize。那麼就ok。得到的是一塊連續的記憶體。

2、如果原先的記憶體大小後面沒有足夠的空閒空間用來分配,那麼從堆中另外找一塊newsize大小的記憶體。

並把原來大小記憶體空間中的內容複製到newsize中。返回新的mem_address指標。(資料被移動了)。

老塊被放回堆上。

例如:#include

char *p,*q;

p = (char * ) malloc (10);

q=p;

p = (char * ) realloc (p,20);

…………………………

這段程式也許在編譯器中沒有辦法通過,因為編譯器可能會為我們消除一些隱患!在這裡我們只是增加了乙個記錄原來記憶體位址的指標q,然後記錄了原來的記憶體位址p,如果不幸的話,資料發生了移動,那麼所記錄的原來的記憶體位址q所指向的記憶體空間實際上已經放回到堆上了!這樣一來,我們應該終於意識到問題的所在和可怕了吧!

3、返回情況

返回的是乙個void型別的指標,呼叫成功。(這就再你需要的時候進行強制型別轉換)

返回null,當需要擴充套件的大小(第二個引數)為0並且第乙個引數不為null,此時原記憶體變成了「freed(游離)」的了。

返回null,當沒有足夠的空間可供擴充套件的時候,此時,原記憶體空間的大小維持不變。

4、特殊情況

如果mem_address為null,則realloc()和malloc()類似。分配乙個newsize的記憶體塊,返回乙個指向該記憶體塊的指標。

如果newsize大小為0,那麼釋放mem_address指向的記憶體,並返回null。

如果沒有足夠可用的記憶體用來完成重新分配(擴大原來的記憶體塊或者分配新的記憶體塊),則返回null.而原來的記憶體塊保持不變。

來自:

記憶體的申請和釋放

常規用法 virtualalloc lpvoid lpaddress,size t dwsize,dword flallocationtype,dword flprotect lpaddress,指定記憶體開始的位址。dwsize,分配記憶體的大小。flallocationtype,分配記憶體的型別...

私有記憶體申請和釋放

私有記憶體 獨佔物理頁 共享記憶體 和別人共享物理頁 由圖可知,多了乙個390 391,兩個物理頁 釋放記憶體 virtualfree lpvoid lpaddress,區域位址 size t dwsize,區域大小,位元組 dword dwfreetype 型別 mem decommit,線形位址...

共享記憶體申請和釋放

私有記憶體 獨佔物理頁 共享記憶體 和別人共享物理頁 invalid handle value,為invalid handle value時,不與檔案關聯 null,安全描述符 page readwrite,保護模式 讀寫的許可權 0,32位通常為空 bufsiz,物理頁的大小 mapfilenam...