這篇文章是我在學(xué)習(xí)指針以及內(nèi)存分配,但我感覺那篇還不是很好,這篇我很把它更完善一些
1. 從靜態(tài)區(qū)分配,一般是全局變量和static類型變量
2.從棧區(qū)分配內(nèi)存,一般是局部的變量,會(huì)隨著所在函數(shù)的結(jié)束而自動(dòng)釋放
3.從堆中分配,一般是使用手動(dòng)分配,使用malloc()函數(shù)和new來申請(qǐng)任意大小空間,不過要手動(dòng)釋放空間,相應(yīng)的使用free()函數(shù)和delete釋放,
如果不釋放該空間,而且指向該空間的指針指向了別的空間.則該空間就無法釋放,造成內(nèi)存泄露,造成了內(nèi)存浪費(fèi)
1.在使用malloc()或new申請(qǐng)空間時(shí),要檢查有沒有分配空間成功,判斷方法是判斷指針是否為NULL,如申請(qǐng)一塊很大的內(nèi)存而沒有這么大的內(nèi)存則分配內(nèi)存會(huì)失敗
2.申請(qǐng)成功后最好是將該內(nèi)存清空,使用memset()后ZeroMemory()清空,不然存在垃圾而造成有時(shí)候輸出很大亂碼
3.不要忘記為數(shù)組和動(dòng)態(tài)內(nèi)存賦初值。防止將未被初始化的內(nèi)存作為右值使用。(這句話不太理解)
4.要防止數(shù)組或指針內(nèi)存越界,
5.申請(qǐng)內(nèi)存成功后,使用結(jié)束后要釋放,系統(tǒng)不會(huì)自動(dòng)釋放手動(dòng)分配的內(nèi)存
6.內(nèi)存釋放后,指針還是指向那塊地址,不過這指針已經(jīng)是"野指針"了,所以釋放內(nèi)存后指針要指向NULL,不然很危險(xiǎn),容易出錯(cuò),if()對(duì)野指針的判斷不起作用
1. 數(shù)組里的數(shù)據(jù)可以單個(gè)修改,但指針的不行,如我的例子,char str[] = "hello",數(shù)組的大小有6個(gè)字符(注意\0),可以通過str[0] = 'X'修改了的個(gè)字符,而指針
char *p = "Word",p是指向了一串常量的字符串,常量字符串是不可修改的,如 p[0] = 'X',編譯器編譯時(shí)不會(huì)保存,但執(zhí)行時(shí)會(huì)出錯(cuò)
2.內(nèi)容的復(fù)制與比較
內(nèi)容的復(fù)制要使用strcpy()函數(shù),不要使用賦值符"=",內(nèi)容的比較也是不要使用比較符號(hào)"<,>,==",使用strcmp()函數(shù)
3,計(jì)算空間的大小
對(duì)數(shù)組的計(jì)算是使用sizeof()函數(shù),該函數(shù)會(huì)按照內(nèi)存對(duì)齊的方式4的倍數(shù)計(jì)算,而指針的空間大小沒法計(jì)算,只能記住在申請(qǐng)空間時(shí)的空間大小
注意當(dāng)數(shù)組作為函數(shù)的參數(shù)進(jìn)行傳遞時(shí),該數(shù)組自動(dòng)退化為同類型的指針,不論數(shù)組a的容量是多少,sizeof(a)始終等于sizeof(char *)
如果函數(shù)的參數(shù)是指針,則不要使用該參數(shù)來申請(qǐng)內(nèi)存空間,這樣沒有實(shí)際的用處,而且這樣當(dāng)函數(shù)結(jié)束時(shí)還得不到釋放內(nèi)存而造成內(nèi)存泄露
這個(gè)問題可以使用"指針的指針"的方法可以解決,不然使用返回指針地址的辦法,先看一下使用 "指針的指針"方法,
還可以考慮一下引用
使用返回內(nèi)存地址的方法
使用返回的方式傳遞內(nèi)存地址容易出錯(cuò)的地方在于放回"棧內(nèi)存"的指針,當(dāng)GetMemory()函數(shù)結(jié)束時(shí)棧內(nèi)存也被釋放,
像這個(gè)代碼
函數(shù)Test5運(yùn)行雖然不會(huì)出錯(cuò),但是函數(shù)GetString2的設(shè)計(jì)概念卻是錯(cuò)誤的。因?yàn)镚etString2內(nèi)的“hello world”是常量字符串,位于靜態(tài)存儲(chǔ)區(qū),
它在程序生命期內(nèi)恒定不變。無論什么時(shí)候調(diào)用GetString2,它返回的始終是同一個(gè)“只讀”的內(nèi)存塊。
1. 當(dāng)我們使用free()和delete釋放一塊內(nèi)存時(shí),指針還是指向原來的地址,不過這時(shí)候的指針時(shí)野指針,
可以驗(yàn)證一下.這圖是我調(diào)試到if()語句時(shí)的情況,p還沒有指向NULL,只是釋放了p指向的空間了
執(zhí)行的結(jié)果可以看看...
所以有這樣的一些特征:
1.指針銷毀了,并不表示所指的空間也得到了釋放 :內(nèi)存泄露
2.內(nèi)存被釋放了,并不表示指針也被銷毀了或指向NULL :野指針
malloc與free是C++/C語言的標(biāo)準(zhǔn)庫函數(shù),new/delete是C++的運(yùn)算符。它們都可用于申請(qǐng)動(dòng)態(tài)內(nèi)存和釋放內(nèi)存。對(duì)于非內(nèi)部數(shù)據(jù)類型的對(duì)象而言,
光用maloc/free無法滿足動(dòng)態(tài)對(duì)象的要求。對(duì)象在創(chuàng)建的同時(shí)要自動(dòng)執(zhí)行構(gòu)造函數(shù),對(duì)象在消亡之前要自動(dòng)執(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++語言需要一個(gè)能完成動(dòng)態(tài)內(nèi)存分配和初始化工作的運(yùn)算符new,以及一個(gè)能完成清理與釋放內(nèi)存工作的運(yùn)算符delete。注意new/delete不是庫函數(shù)。
我們先看一看malloc/free和new/delete如何實(shí)現(xiàn)對(duì)象的動(dòng)態(tài)內(nèi)存管理,看代碼
類Obj的函數(shù)Initialize模擬了構(gòu)造函數(shù)的功能,函數(shù)Destroy模擬了析構(gòu)函數(shù)的功能。函數(shù)UseMallocFree中,由于malloc/free不能執(zhí)行構(gòu)造函數(shù)與析構(gòu)函數(shù),必須調(diào)用成員函數(shù)Initialize和Destroy來完成初始化與清除工作。函數(shù)UseNewDelete則簡單得多。
所以我們不要企圖用malloc/free來完成動(dòng)態(tài)對(duì)象的內(nèi)存管理,應(yīng)該用new/delete。由于內(nèi)部數(shù)據(jù)類型的“對(duì)象”沒有構(gòu)造與析構(gòu)的過程,對(duì)它們而言malloc/free和new/delete是等價(jià)的。
既然new/delete的功能完全覆蓋了malloc/free,為什么C++不把malloc/free淘汰出局呢?這是因?yàn)镃++程序經(jīng)常要調(diào)用C函數(shù),而C程序只能用malloc/free管理動(dòng)態(tài)內(nèi)存。
如果用free釋放“new創(chuàng)建的動(dòng)態(tài)對(duì)象”,那么該對(duì)象因無法執(zhí)行析構(gòu)函數(shù)而可能導(dǎo)致程序出錯(cuò)。如果用delete釋放“malloc申請(qǐng)的動(dòng)態(tài)內(nèi)存”,理論上講程序不會(huì)出錯(cuò),但是該程序的可讀性很差。所以new/delete必須配對(duì)使用,malloc/free也一樣。
1.判斷指針是否為NULL,如果是則馬上用return語句終止本函數(shù)
2.判斷指針是否為NULL,如果是則馬上用exit(1)終止整個(gè)程序的運(yùn)行
3.為new和malloc設(shè)置異常處理函數(shù)。例如Visual C++可以用_set_new_hander函數(shù)為new設(shè)置用戶自己定義的異常處理函數(shù),
malloc()/free()和new/delete的使用要點(diǎn)網(wǎng)上有更詳細(xì)的說明
聯(lián)系客服