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