C++編程常見的記憶體錯誤及其對策
發生記憶體錯誤是件非常麻煩的事情。編譯器不能自動探索這些錯誤,通常是在程式運行時才能捕捉到。而這些錯誤大多沒有明顯的癥狀,時隱時現,增加了改錯的難度。有時使用者怒氣沖沖地把你找來,程式卻沒有發生任何問題,你一走,錯誤又發作了。
常見的記憶體錯誤及其對策如下:
u 記憶體配置未成功,卻使用了它。
編程新手常犯這種錯誤,因為他們沒有意識到記憶體配置會不成功。常用解決辦法是,在使用記憶體之前檢查指標是否為NULL。如果指標p是函數的參數,那麼在函數的入口處用assert(p!=NULL)進行檢查。如果是用malloc或new來申請記憶體,應該用if(p==NULL) 或if(p!=NULL)進行防錯處理。
u 記憶體配置雖然成功,但是尚未初始化就引用它。
犯這種錯誤主要有兩個起因:一是沒有初始化的觀念;二是誤以為記憶體的預設初值全為零,導致引用初值錯誤(例如數組)。
記憶體的預設初值究竟是什麼並沒有統一的標準,儘管有些時候為零值,我們寧可信其無不可信其有。所以無論用何種方式建立數組,都別忘了賦初值,即便是賦零值也不可省略,不要嫌麻煩。
u 記憶體配置成功並且已經初始化,但操作越過了記憶體的邊界。
例如在使用數組時經常發生下標“多1”或者“少1”的操作。特別是在for迴圈語句中,迴圈次數很容易搞錯,導致數組操作越界。
u 忘記了釋放記憶體,造成記憶體泄露。
含有這種錯誤的函數每被調用一次就丟失一塊記憶體。剛開始時系統的記憶體充足,你看不到錯誤。終有一次程式突然死掉,系統出現提示:記憶體耗盡。
動態記憶體的申請與釋放必須配對,程式中malloc與free的使用次數一定要相同,否則肯定有錯誤(new/delete同理)。
u 釋放了記憶體卻繼續使用它。
有三種情況:
(1)程式中的對象調用關係過於複雜,實在難以搞清楚某個對象究竟是否已經釋放了記憶體,此時應該重新設計資料結構,從根本上解決對象管理的混亂局面。
(2)函數的return語句寫錯了,注意不要返回指向“棧記憶體”的“指標”或者“引用”,因為該記憶體在函數體結束時被自動銷毀。
(3)使用free或delete釋放了記憶體後,沒有將指標設定為NULL。導致產生“野指標”。
l 【規則7-2-1】用malloc或new申請記憶體之後,應該立即檢查指標值是否為NULL。防止使用指標值為NULL的記憶體。
l 【規則7-2-2】不要忘記為數組和動態記憶體賦初值。防止將未被初始化的記憶體作為右值使用。
l 【規則7-2-3】避免數組或指標的下標越界,特別要當心發生“多1”或者“少1”操作。
l 【規則7-2-4】動態記憶體的申請與釋放必須配對,防止記憶體流失。
【規則7-2-5】用free或delete釋放了記憶體之後,立即將指標設定為NULL,防止產生“野指標”。