1 malloc函數(shù)
malloc的全稱是memory allocation,中文叫做:動態(tài)內(nèi)存分配。
原型:extern void* malloc(unsigned int num_bytes);
說明:分配長度為num_bytes字節(jié)的內(nèi)存塊。如果分配成功,則返回指向被分類內(nèi)存的指針;如果分配失敗,則返回空指針NULL。(所以申請完內(nèi)存需要判斷所申請內(nèi)存是否為空)當(dāng)內(nèi)存不再使用時,應(yīng)使用free()函數(shù)講內(nèi)存塊釋放。
返回類型:void*類型,表示通用變體類型指針,c,c++規(guī)定,void*類型可以強(qiáng)制轉(zhuǎn)換為任何其他類型的指針;void*指申請內(nèi)存空間時,還不知道用戶用這段空間來存儲什么類型的數(shù)據(jù)。
釋放:void free(void * FirstByte);講malloc分配的空間還給程序或者是操作系統(tǒng),也就是釋放了這塊內(nèi)存。
注意事項:
1)申請內(nèi)存空間后,必須檢查是否分配成功;
2)當(dāng)不需要再使用申請的內(nèi)存時,記得釋放;釋放后應(yīng)該把指向這塊內(nèi)存的指針指向NULL,以防后面的程序不小心使用了野指針
3)malloc和free應(yīng)該配對使用;釋放只能釋放一次,若釋放兩次或更多會出現(xiàn)錯誤,(釋放空指針例外,釋放空指針其實等于啥都沒做,釋放空指針多少次都沒有問題)
4)malloc從堆里面獲得內(nèi)存;函數(shù)返回的指針指向堆里面的一塊內(nèi)存。操作系統(tǒng)中有一個記錄空閑內(nèi)存地址的鏈表,當(dāng)操作系統(tǒng)收到程序的申請時,就會遍歷鏈表,然后尋找第一個空間大于所申請空間的堆結(jié)點,然后將該結(jié)點從空閑結(jié)點鏈表中刪除,并將該結(jié)點分配給程序。
2 new運(yùn)算符
c++中,用new和delete動態(tài)創(chuàng)建和釋放數(shù)組或者單個對象。
動態(tài)創(chuàng)建對象時,只需要指定其數(shù)據(jù)類型,而不必為該對象命名。
1) new運(yùn)算符返回指向該創(chuàng)建對象的指針。
我們可以通過指針來訪問此對象。int *pi = new int ;此new表達(dá)式在堆區(qū)中分配創(chuàng)建了一個整型對象,并返回此對象的地址,并用該地址初始化指針pi。
2) 動態(tài)創(chuàng)建對象的初始化
2.1) 動態(tài)創(chuàng)建的對象可以用初始化變量的方式初始化。
int * pi = new int (100);//指針pi所指向的對象初始化為100
string *ps = new string(10,'9')//*ps為“9999999999”
如果不提供顯示初始化,對于類類型,用該類的默認(rèn)構(gòu)造函數(shù)初始化;而內(nèi)置類型的對象則無初始化。
2.2) 可以對動態(tài)創(chuàng)建的對象做值初始化:
int *pi = new int ();//初始化為0;
int *pi = new int ;//pi指向一個沒有初始化的int
string *ps = new string();//初始化為空字符串(對于提供了默認(rèn)構(gòu)造函數(shù)的類型,沒有必要對其對象進(jìn)行值初始化)
3)delete撤銷動態(tài)創(chuàng)建的對象
delete表達(dá)式釋放指針指向的地址空間;
delete pi;//釋放單個對象
delete [ ] pi;//釋放數(shù)組
如果指針指向的不是new分配的內(nèi)存地址,則使用delete是不合法的。
4) delete之后,重設(shè)指針的值
delete p;執(zhí)行完該語句后,p變成了不確定的指針,盡管p值沒有明確定義,但仍然存放了它之前所指對象的地址,然后p所指的內(nèi)存已經(jīng)被釋放了,所以p不再有效。此時,該指針變成了懸垂指針(懸垂指針指向曾經(jīng)存放對象的內(nèi)存,但該對象已經(jīng)不存在了)。懸垂指針往往導(dǎo)致程序錯誤,而且很難檢測出來。
一旦刪除了指針?biāo)傅膶ο螅⒓磳⒅羔樦脼?,這樣就可以非常清楚的指明指針不再指向任何對象。(零值指針:int * ip =0;)
5)分配失敗
new在分配內(nèi)存失敗時,拋出std::bad_alloc異常。但1993年前,c++一直要求在內(nèi)存分配失敗時operator? new要返回0,很多c++程序是在編譯器開始支持新規(guī)范前寫的。c++標(biāo)準(zhǔn)委員會不想放棄那些已有的遵循返回0規(guī)范的代碼,所以他們提供了另外形式的operator? new(以及operator? new[])以繼續(xù)提供返回0功能。這些形式被稱為“無拋出”,因為他們沒用過一個throw,而是在使用new的入口點采用了nothrow對象:
class?? widget?? {?? ...?? };
widget?? *pw1?? =?? new?? widget;//?? 分配失敗拋出std::bad_alloc
if?? (pw1?? ==?? 0)?? ... //?? 這個檢查一定失敗
widget?? *pw2?? =?? new?? (nothrow)?? widget;?? //?? 若分配失敗返回0
if?? (pw2?? ==?? 0)?? ... //?? 這個檢查可能會成功
3 malloc和new的區(qū)別
(1)new 返回指定類型指針,并且可以自動計算所需要的大小;malloc需要手動計算字節(jié)數(shù),并且在返回后強(qiáng)制類型轉(zhuǎn)換為實際類型的指針。
(2)malloc只管分配內(nèi)存,并不能對所得到的內(nèi)存進(jìn)行初始化,所以得到的一片新內(nèi)存中,其值將是隨機(jī)的;new不僅分配內(nèi)存,還對內(nèi)存中的對象進(jìn)行初始化;free只管釋放內(nèi)存;delete不僅釋放內(nèi)存,還會調(diào)用對象的析構(gòu)函數(shù),銷毀對象。
(3) malloc/free是c++/c的標(biāo)準(zhǔn)庫函數(shù),頭文件為stdlib.h;而new/delete是c++的運(yùn)算符。他們都可用于申請動態(tài)內(nèi)存和釋放內(nèi)存。
(4) 對于非內(nèi)部數(shù)據(jù)結(jié)構(gòu)的對象而言,光用malloc/free無法滿足動態(tài)對象的要求,對象在創(chuàng)建的同時,還要自動執(zhí)行構(gòu)造函數(shù),對象在消亡之前要自動執(zhí)行析構(gòu)函數(shù),由于malloc/free是庫函數(shù)而不是運(yùn)算符,不在編譯器控制權(quán)限之內(nèi),不能夠把執(zhí)行構(gòu)造函數(shù)和析構(gòu)函數(shù)的任務(wù)強(qiáng)加于malloc/free;因此,c++語言需要一個能夠完成動態(tài)內(nèi)存分配和初始化的運(yùn)算符new,以及一個能完成清理與釋放內(nèi)存工作的運(yùn)算符delete;我們不要企圖用malloc和free來完成動態(tài)對象的內(nèi)存管理,應(yīng)該用new/delete。由于內(nèi)部數(shù)據(jù)類型沒有構(gòu)造和析構(gòu)過程,對他們而言malloc/free和new/delete是等價的。
4new/delete的功能完全覆蓋了malloc/free,為什么還要malloc和free了?
這是因為c++程序經(jīng)常要調(diào)用c函數(shù),而c程序只能用malloc和free來管理動態(tài)內(nèi)存。
如果用free釋放new創(chuàng)建的動態(tài)對象,那么該對象因無法執(zhí)行析構(gòu)函數(shù)而可能導(dǎo)致程序出錯。如果用delete釋放掉malloc申請的動態(tài)內(nèi)存,結(jié)果也會導(dǎo)致程序出錯,結(jié)果理論上應(yīng)該可以,但是程序的可讀性很差。所以new/delete必須配對使用,malloc和free也一樣。
參考:http://www.cnblogs.com/fly1988happy/archive/2012/04/26/2470542.html