申請記憶體的函式

2021-05-26 18:19:54 字數 3361 閱讀 7504

c語言跟記憶體申請相關的函式主要有_alloca,calloc,malloc,free,realloc等,都位於標頭檔案malloc.h中(注意沒有alloc函式)

其中_alloca是向棧申請記憶體,因此無需釋放. malloc分配的記憶體是位於堆中的,並且沒有初始化記憶體的內容,因此基本上malloc之後,呼叫函式memset來初始化這部分的記憶體空間.calloc則將初始化這部分的記憶體,設定為0. 而realloc則對malloc申請的記憶體進行大小的調整.申請的記憶體最終需要通過函式free來釋放. 

一、malloc 和 calloc

malloc/calloc/free基本上都是c函式庫實現的,跟os無關.c函式庫內部通過一定的結構來儲存當前有多少可用記憶體.如果程式 malloc的大小超出了庫里所留存的空間,那麼將首先呼叫brk

系統呼叫來增加可用空間,然後再分配空間.free時,釋放的記憶體並不立即返回給os, 而是保留在內部結構中. 可以打個比方: brk類似於批發,一次性的向os申請大的記憶體,而malloc等函式則類似於零售,滿足程式執行時的要求.這套機制類似於緩衝.

使用這套機制的原因: 系統呼叫不能支援任意大小的記憶體分配(有的系統呼叫只支援固定大小以及其倍數的記憶體申請,這樣的話,對於小記憶體的分配會造成浪費; 系統呼叫申請記憶體代價昂貴,涉及到使用者態和核心態的轉換. 函式malloc()和calloc()都可以用來分配動態記憶體空間,但兩者稍有區別。

malloc()函式有乙個引數,即要分配的記憶體空間的大小:

void *malloc(size_t size);

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

void*calloc(size_t numelements,size_t sizeofelement);

如果呼叫成功,函式malloc()和calloc()都將返回所分配的記憶體空間的首位址。

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

calloc() 函式會將所分配的記憶體空間中的每一位都初始化為零,也就是說,如果你是為字元型別或整數型別的元素分配記憶體,那麼這些元素將保證會被初始化為零;如果你是為指標型別的元素分配記憶體,那麼這些元素通常(但無法保證)會被初始化為空指標;如果你是為實數型別的元素分配記憶體,那麼這些元素可能(只在某些計算機中)會被初始化為浮點型的零。

malloc() 函式和calloc()函式的另一點區別是calloc()函式會返回乙個由某種物件組成的陣列,但malloc()函式只返回乙個物件。為了明確是為乙個陣列分配記憶體空間,有些程式設計師會選用calloc()函式。但是,除了是否初始化所分配的記憶體空間這一點之外,絕大多數程式設計師認為以下兩種函式呼叫方式沒有區別:

calloc(numelements ,sizeofelement);

malloc(numelements *sizeofelement) ;

需要解釋的一點是,理論上(按照ansic標準)指標的算術運算只能在乙個指定的陣列中進行,但是在實踐中,即使c編譯程式或翻譯器遵循這種規定,許多c 程式還是衝破了這種限制。因此,儘管malloc()函式並不能返回乙個陣列,它所分配的記憶體空間仍然能供乙個陣列使用(對realloc()函式來說同樣如此,儘管它也不能返回乙個陣列)。

總之,當你在calloc()函式和malloc()函式之間作選擇時,你只需考慮是否要初始化所分配的記憶體空間,而不用考慮函式是否能返回乙個陣列。

當程式執行過程中malloc了,但是沒有free的話,會造成記憶體洩漏.一部分的記憶體沒有被使用,但是由於沒有free,因此系統認為這部分記憶體還在使用,造成不斷的向系統申請記憶體,是的系統可用記憶體不斷減少.但是,記憶體洩漏僅僅指程式在執行時,程式退出時,os將**所有的資源.因此,適當的重起一下程式,有時候還是有點作用.

二、realloc

void *realloc(void *mem_address, unsigned int newsize)

realloc更改以前分配區的長度(增加或減少)。當增加長度時,可能需將以前分配區的內容移到另乙個足夠大的區域,而新增區域內的初始值則不確定。減少時,則被減少的那一部分的內容會丟失。如果重新分配成功則返回指向被分配記憶體的指標,否則返回空指標null。 當記憶體不再使用時,應使用free()函式將記憶體塊釋放。

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

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

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

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

老塊被放回堆上。

例如:

#include

void main()

在這段程式中我們增加了指標q,用它記錄了原來的記憶體位址p。這段程式可以編譯通過,但在執行到a行時,如果原有記憶體後面沒有足夠空間將原有空間擴充套件成乙個連續的新大小的話,

realloc函式就會以第二種方式分配記憶體,此時資料發生了移動,那麼所記錄的原來的記憶體位址q所指向的記憶體空間實際上已經放回到堆上了!這樣就會產生q指標的指標懸掛,如果再用q指標進行操作就可能發生意想不到的問題。所以在應用realloc函式是應當格外注意這種情況。

3、返回情況

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

強制型別轉換)

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

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

4、特殊情況

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

如果newsize大小為0,那麼效果等同於free(),釋放mem_address指向的記憶體,並返回null。

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

**

申請記憶體的庫函式

1 void malloc size t size 申請一段size大小的記憶體,返回這段記憶體的首位址 指標 申請失敗返回null,malloc申請的記憶體空間可以用memset來初始化 2 void calloc size t num,size t size 申請一段size大小的記憶體,並且初...

外部函式中申請記憶體

在我們使用指標傳遞記憶體的時候,必須謹慎小心,否則常常會對非法記憶體 空位址 錯誤位址 進行操作。下面我們通過乙個程式來說明一些需要注意的問題。include include void test1 char p int num void test2 char pp int num void main...

外部函式中申請記憶體

在我們使用指標傳遞記憶體的時候,必須謹慎小心,否則常常會對非法記憶體 空位址 錯誤位址 進行操作。下面我們通過乙個程式來說明一些需要注意的問題。include include voidtest1 char p,intnum voidtest2 char pp,intnum voidmain 在上面的...