常見的記憶體配置和使用錯誤
1) 記憶體的申請和分配並沒有成功,但程式員卻使用了它。一些新手經常會犯這種錯誤,他們並不會留意到記憶體沒有分配成功。判斷指標的值是否為NULL可以有效地避免這種錯誤。
2) 記憶體的分配已經成功,但是卻沒有進行初始化就直接使用它了。首先是觀念上的問題,很多人都沒有在使用指標前要初始化這樣的習慣,然而這個習慣卻是很重要的,希望大家一定要強迫自己養成。第二就是主觀地認為自己申請的記憶體的預設值為0,這樣想是沒有什麼道理的,記憶體配置後的值是不確定的。
3) 上面的兩種工作都已經做好了(已經成功申請並初始化完成),但是操作時卻越界了。
4) 申請了記憶體,使用完了卻忘記了釋放,導致記憶體泄露。這樣的錯誤可以形容為一個惡性的腫瘤,它不會馬上要你的命,但是它會慢慢地吞噬你的系統資源,直到你的程式徹底完蛋。
5) 你很小心地釋放了記憶體,但是卻又使用了它。由於程式很複雜或者調用順序出錯,這樣可能導致出現上面的錯誤。
指標---一把偉大的雙刃劍
我真的非常佩服發明指標的人,他簡直太偉大了。能使用如此簡潔地方法將複雜的記憶體結構描述的如此清楚,這本身就是一種偉大的成就。但是,指標之於程式員如同武器之於士兵,用好了可以威力無比,用不好則害人害己。
我先說說指標和數組的區別。數組名對應著一塊記憶體,它的地址、容量在其生命週期中是不可變的,只有數組內容是可變的。指標可隨時指向任何類型的記憶體,它的特點就是“變”。指標遠比數組靈活,但也更危險。
數組名是不能直接進行賦值和比較的。如果你向要將數組a賦值給數組b,不能直接用指派陳述式b = a ,這樣會令編譯器產生錯誤的。必須使用標準的庫函數strcpy來進行賦值。相同地,要比較a和b的內容是否相同,不能使用普通的邏輯判斷if(b==a),也要應用庫函數strcmp來判斷。
//數組……
char a[] = “hello”;
char b[100];
strcpy(b, a); // b = a is wrong
if (strcmp(b, a) == 0) //if (b == a) is wrong
cout<<b<<endl;
//指標……
int len = strlen(a);
char *p = (char *)malloc(sizeof(char)*(len+1));
strcpy(p, a);
if (strcmp(p, a) == 0)
cout<<p<<endl;
free(p);
在計算記憶體容量的時候有一點是必須要指出的,那就是sizeof計算數組是計算它的實際的記憶體容量,而計算指標時則永遠都是4個位元組。C++是永遠沒有辦法知道指標所指的記憶體容量,除非在申請時記住它。
free和delete如何對付指標?
程式員都知道它們是用來釋放申請的記憶體的,但是卻很少有人注意到指標本身並沒有發生什麼變化。各位可以在VC中使用單步跟蹤一下,你們會驚奇地發現當指標p被調用了free後它的地址值並沒有改變,只是該地址對應的記憶體中原來有意義的值變成了垃圾,“p”卻還是指向的這塊記憶體。記住,一定要第一時間將p的值設為NULL,否則會讓別人以為p是一個有意義的指標而誤使用它(當別人使用該指標時會判斷指標的值是否為NULL,如果不為NULL就會以為它有意義)。
也就是說調用了free(p)之後,p仍然指向那塊記憶體,假若不顯示設定為NULL的話,以後就不能使用if (NULL == p)來判斷p是否釋放
char *p = (char *)malloc(100);
strcpy(p, “hello”);
free(p); // the address of “p” is not changed.
….
if (NULL != p) //it will return TRUE
strcpy(p, “world”); //Wrong!!!
下面提兩點,讓大家可以防止上面的情況出現:
1) 指標聲明後要馬上初始化。因為指標出現的預設值是隨機的,所以一定要賦值為NULL,然後再使用。
2) 調用了free和delete後一定要將指標賦值為NULL。原因上面已經提過了,就不再贅述了。
本文首先分析了使用記憶體會出現的常見錯誤。然後論述了記憶體使用量過程中最為關鍵的一環 — 指標的一些平時不為人注意的用法和技巧。這些都是我平時在做工程項目中積累下的經驗,希望能對大家(特別是那些還在記憶體的苦海中掙紮的苦難弟兄們)會有所協助。有什麼經驗和問題需要交流的,請MAIL我。paulni@citiz.net