1) 內存分配未成功,卻使用了它。
?
2) 內存分配雖然成功,但是尚未初始化就引用它。
?
3) 內存分配成功并且已經初始化,但操作越過了內存的邊界。
?
4) 忘記了釋放內存,造成內存泄露。
?
5) 釋放了內存卻繼續使用它。?
有三種情況: (1)程序中的對象調用關系過于復雜,實在難以搞清楚某個對象究竟是否已經釋放了內存,此時應該重新設計數據結構,從根本上解決對象管理的混亂局面。 (2)函數的return語句寫錯了,注意不要返回指向“棧內存”的“指針”或者“引用”,因為該內存在函數體結束時被自動銷毀。 (3)使用free或delete釋放了內存后,沒有將指針設置為NULL。導致產生“野指針”。 【規則7-2-1】用malloc或new申請內存之后,應該立即檢查指針值是否為NULL。防止使用指針值為NULL的內存。 【規則7-2-2】不要忘記為數組和動態內存賦初值。防止將未被初始化的內存作為右值使用。 【規則7-2-3】避免數組或指針的下標越界,特別要當心發生“多1”或者“少1”操作。 【規則7-2-4】動態內存的申請與釋放必須配對,防止內存泄漏。 【規則7-2-5】用free或delete釋放了內存之后,立即將指針設置為NULL,防止產生“野指針”。
參見http://hi.baidu.com/wangysh/blog/item/56275bc2114b6e36e5dd3bc1
自己編寫的一個不小的程序一直在運行退出時出錯,我對指針的使用很仔細但很長時間檢查不到錯誤,最后發現在一個地方沒有遵照規則【7-2-5】,大家如果指針出錯,一定要仔細的慢慢檢查,相信自己。
《c++內存訪問越界》
1. 原理分析
經常有些新C++程序員問:C++的類的成員個數是不是有限制,為什么我加一個變量后程序就死了?或者說:是不是成員變量的順序很重要,為什么我兩個成員變量順序換一換程序就不行了?凡此種種之怪現象,往往都是內存訪問越界所致。何謂內存訪問越界,簡單的說,你向系統申請了一塊內存,在使用這塊內存的時候,超出了你申請的范圍。例如,你明明申請的是100字節的空間,但是你由于某種原因寫入了120字節,這就是內存訪問越界。內存訪問越界的后果是:你的寫入破壞了本不屬于你的空間。
下面是一個簡單的例子:
int a;
char b[16]="abcd";
int c;
a = 1;
c = 2;
printf("a=%d,c=%d\n", a,c);
memset(b, 0,32); //注意這里訪問越界了,你只有16字節空間,卻修改了32字節
printf("a=%d,c=%d\n", a,c);
你可以看出,在memset前后,兩個printf語句打印出來的值并不一樣,因為memset越界后修改了a或者c的值(由于不同編譯器對變量在空間中順序的安排可能有不同策略,因此我用兩個變量,希望能抓到越界信息。對于VC,debug模式下系統添加了很多填充字節,你可能需要增加越界的數量才能看到效果)
2. 為什么增加一個變量后程序就崩潰了?
增加一個變量后,內存中變量的布局也發生了變化。如果一個內存越界破壞了一個不含指針的結構,程序雖然邏輯不對,但是不至于崩潰。但是如果增加變量后,內存訪問越界破壞了一個指針,則會導致程序崩潰。
例如:(這個例子沒看明白,好像有點問題)
int a;
char b[128];
//bool c;
char* d=new char[128];
int e;
b[136] = '\0';
b[137] = '\0';
b[138] = '\0';
b[139] = '\0';
strcpy(d, "haha");
注意, b訪問越界了8個字節位置處的4個字節。如果沒有c,那么越界破壞了e變量,不會導致程序崩潰。但是加上c之后,破壞的變量可能就是d了,由于指針被破壞后,一旦訪問就是內存訪問違例,導致程序崩潰。
這也解釋了為什么交換順序會導致程序崩潰。如果上面情況沒有變量c,你交換e和d,結構也是類似的,程序也一樣要崩潰。
3. 為什么有些情況越界了程序也沒錯?
這主要是說這個話的人對什么是“錯”沒有正確的認識。程序不是只有崩潰了才是錯!你破壞了別的變量,那個變量總有被使用的時候,盡管那個變量不會導致諸如程序崩潰、報警之類的嚴重錯誤,但是其計算結果必然是錯誤的。你說“程序沒錯”,是因為你根本沒有發現錯誤而已。這種情況甚至比程序直接崩潰還要惡劣,因為程序一旦崩潰你肯定會去查,可以在導致真正嚴重的問題之前就把問題解決了。而如果計算錯誤隱藏到很晚,你的損失就可能很大了。(例如,一顆衛星上天了,你才發現一臺儀器由于軟件故障無法測量真正的數據,那得多少損失?)
4. 如何解決內存訪問越界問題?
老實說沒有好的方法。遇到這種問題,首先你得找到哪里有內存訪問越界,而一個比較麻煩得問題在于,出現錯誤得地方往往不是真正內存越界得地方。對于內存訪問越界,往往需要進行仔細得代碼走查、單步跟蹤并觀察變量以及在調試環境得幫助下對變量進行寫入跟蹤(如VC6就有一旦變量被修改就break得機制)。
更重要得是,程序員要養成良好的編程習慣,在修改每個數組時一定要對這個數組有多少空間有清醒的認識,否則一旦出錯,找到原因是很痛苦的事情。