常見的錯誤
關於內存的一些知識已在內存分配中提及,現記錄與分享常見的內存錯誤與對策。
類型 1:內存未分配成功,卻使用了它。
方 法:在使用之前檢查指針是否爲NULL。
1)當指針p是函數的參數時,在函數入口處用語句assert(p!=NULL)進行斷言檢查。
2)當使用malloc或new來申請內存時,應該用if(p != NULL)進行防錯檢查。
類型 2:引用了尚未初始化的指針
原 因:內存的缺省初始值究竟是什麼並沒有統一的標準,在使用之前都進行初始化。
1)沒有初始化的觀念。
2)內存的缺省值是未定義,即垃圾值。
類型 3:越界操作內存
原 因:內存分配成功且初始了,但越界操作是不允許的。
例 如:在使用數組時經常發生下標“多1”或“少1”,特別是在for循環語句時。
類型 4:忘記釋放內存,造成內存泄漏。
原 因:含有這種類型錯誤的函數,每被調用一次,就丟失一塊內存。當內存充足時看不到這種錯誤帶來的影響,當內存耗盡時系統提示:“內存耗盡”。因此,動態內存的申請與釋放必須配對,程序中malloc與free的使用次數要相同。
類型 5:釋放了內存卻繼續使用它
原 因:對應的情況有2種
1)返回了“棧內存的指針或引用”,因爲堆棧中的變量在函數結束後自動銷燬。
2)某塊內存被free後,沒有將指向該內存的指針設置爲NULL,導致產生“野指針”。
使用規則
爲了保證代碼的健壯和安全,可以參考如下的規則:
規則1:使用malloc申請的內存時,必須要立即檢查相對應的指針是否爲NULL。
規則2:初始化數組和動態內存。
規則3:避免數組或指針下標越界。
規則4:動態內存的申請和釋放必須相配對,防止內存泄漏。
規則5:free釋放某塊內存之後,要立即將指針設置爲NULL,防止產生野指針。
幾個重要的概念
1.野指針
概念:“野指針”不是NULL指針,是指指向“垃圾”內存的指針。即指針指向的內容是不確定的。
產生的原因:1)指針變量沒有初始化。因此,創建指針變量時,該變量要被置爲NULL或者指向合法的內存單元。
2)指針p被free之後,沒有置爲NULL,讓人誤以爲p是個合法的指針。
3)指針跨越合法範圍操作。不要返回指向棧內存的指針或引用
例子1-1:引用尚未初始化的指針
例子1-2:return語句返回指向“棧內存”的指針
- char *p;
- *p = 'A';//error,p指向未定義
- char *GetString1(void)
- {
- char p[] = "hello world!";
- //p在棧區,常量字符串在常量字符區
- return p;//error,返回棧內存的地址
- }
例子1-3:使用了被釋放的內存
注意:free()釋放的是指針指向的內存!不是指針變量!這點非常非常重要!指針是一個變量,只有程序結束時才被銷燬。釋放了內存空間後,原來指向這塊空間的指針還是存在!只不過現在指針指向的內容的垃圾,是未定義的,所以說是垃圾。因此,前面我已經說過了,釋放內存後把指針指向NULL,防止指針在後面不小心又被解引用。
- char *pstr = (char *)malloc(sizeof(char)*100);
- free(pstr); //pstr所指的內存被釋放
- if (NULL !=pstr)//沒起到作用
- {
- strcpy(pstr,"string!");//error,有時候程序不會提示有誤,但還是不允許
- }
對比下面的例子,加深理解
例子1-4:函數返回值傳遞動態內存
- char* GetMemory(int num)
- {
- char *p = (char *)malloc(sizeof(char) * num);
- return p ;//ok,返回堆區的地址值
- }
例子1-5:
- char *GetString(void)
- {
- char *p = "hello world!";
- //指針變量p在棧區,指向文字常量區的字符
- return p;//ok,返回字符串的地址
- }
2.內存泄漏
概念:用動態內存分配函數動態開闢的空間,在使用完畢後未釋放,結果導致一直佔據該內存單元,直到程序結束。
注意:內存泄漏是指堆內存的泄漏。它的一般表現方式是程序運行時間越長,佔用內存越多,最終用盡全部內存,整個系統崩潰。
例子2-1:內存泄漏,共9*100字節發生泄漏
- void Test(void)
- {
- char *p = NULL;
- for ( int i = 0; i<10; i++)
- {
- p = (char*)malloc(100);//沒循環一次內存泄漏一塊,最後一次得到正確使用
- }
- strncpy(p,"string!");
- free(p);
- }
3.內存溢出
概念:系統分配的內存不足以放下數據,稱爲內存溢出。
例子3-1:運行時提示出錯
- char str[10]={0};
- strcpy(str,"hello world!");//error!