C語言中常見的內存錯誤與解決方法

常見的錯誤      

關於內存的一些知識已在內存分配中提及,現記錄與分享常見的內存錯誤與對策。

類型 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. char *p;  
  2. *p = 'A';//error,p指向未定義  
例子1-2:return語句返回指向“棧內存”的指針
  1. char *GetString1(void)  
  2. {  
  3.     char p[] = "hello world!";  
  4.     //p在棧區,常量字符串在常量字符區  
  5.   
  6.     return p;//error,返回棧內存的地址  
  7. }  

例子1-3:使用了被釋放的內存

  1. char *pstr = (char *)malloc(sizeof(char)*100);  
  2. free(pstr); //pstr所指的內存被釋放  
  3. if (NULL !=pstr)//沒起到作用  
  4. {  
  5.     strcpy(pstr,"string!");//error,有時候程序不會提示有誤,但還是不允許  
  6. }  
注意:free()釋放的是指針指向的內存!不是指針變量!這點非常非常重要!指針是一個變量,只有程序結束時才被銷燬。釋放了內存空間後,原來指向這塊空間的指針還是存在!只不過現在指針指向的內容的垃圾,是未定義的,所以說是垃圾。因此,前面我已經說過了,釋放內存後把指針指向NULL,防止指針在後面不小心又被解引用。

對比下面的例子,加深理解

例子1-4:函數返回值傳遞動態內存

  1. char* GetMemory(int num)  
  2. {  
  3.     char *p = (char *)malloc(sizeof(char) * num);  
  4.     return p ;//ok,返回堆區的地址值  
  5. }  

例子1-5:

  1. char *GetString(void)  
  2. {  
  3.     char *p = "hello world!";  
  4.     //指針變量p在棧區,指向文字常量區的字符  
  5.   
  6.     return p;//ok,返回字符串的地址  
  7. }  

2.內存泄漏

    概念:用動態內存分配函數動態開闢的空間,在使用完畢後未釋放,結果導致一直佔據該內存單元,直到程序結束。

注意:內存泄漏是指堆內存的泄漏。它的一般表現方式是程序運行時間越長,佔用內存越多,最終用盡全部內存,整個系統崩潰

例子2-1:內存泄漏,共9*100字節發生泄漏

  1. void Test(void)  
  2. {  
  3.     char *p = NULL;  
  4.     for ( int i = 0; i<10; i++)  
  5.     {  
  6.         p = (char*)malloc(100);//沒循環一次內存泄漏一塊,最後一次得到正確使用  
  7.     }  
  8.       
  9.     strncpy(p,"string!");  
  10.     free(p);  
  11. }  

3.內存溢出

   概念:系統分配的內存不足以放下數據,稱爲內存溢出。

例子3-1:運行時提示出錯

  1. char str[10]={0};  
  2.   
  3. strcpy(str,"hello world!");//error! 
發佈了9 篇原創文章 · 獲贊 6 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章