久久ER99热精品一区二区-久久精品99国产精品日本-久久精品免费一区二区三区-久久综合九色综合欧美狠狠

博客專欄

EEPW首頁 > 博客 > C語言常見內存錯誤及解決方法

C語言常見內存錯誤及解決方法

發布人:電子禪石 時間:2020-08-12 來源:工程師 發布文章
常見的錯誤      

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

類型 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:引用尚未初始化的指針

[cpp] view plain copy


  1. char *p;  

  2. *p = 'A';//error,p指向未定義  

 

 

例子1-2:return語句返回指向“棧內存”的指針

 

[cpp] view plain copy


  1. char *GetString1(void)  

  2. {  

  3.     char p[] = "hello world!";  

  4.     //p在棧區,常量字符串在常量字符區  

  5.   

  6.     return p;//error,返回棧內存的地址  

  7. }  

char p[] =
一個數組,這個數組是局部變量。

char* p =
一個指針,這個指針指向一個字符串常量

區別在于:數組的話,字符串是存在于這個數組里的,因為這個數組屬于局部變量,所以你就算把數組的地址返回給主函數,主函數也沒有辦法再訪問這個地址了。
但是如果是指向字符串常量的指針,這個字符串是放在程序的常量區而不是放在局部變量中,那么你把這個常量的地址返回給主函數,主函數也還是可以訪問它的。

char* p是一個指針,根本沒分配內存,他指向的"hello world" 是一個地址,而且地址不用加“”
而char p[]是一個數組,已經分配內存,是將"hello world" 復制到該內存里面,這個內存是可讀寫的

 

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

[cpp] view plain copy


  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:函數返回值傳遞動態內存

[cpp] view plain copy


  1. char* GetMemory(int num)  

  2. {  

  3.     char *p = (char *)malloc(sizeof(char) * num);  

  4.     return p ;//ok,返回堆區的地址值  

  5. }  

 

例子1-5:

[cpp] view plain copy


  1. char *GetString(void)  

  2. {  

  3.     char *p = "hello world!";  

  4.     //指針變量p在棧區,指向文字常量區的字符  

  5.   

  6.     return p;//ok,返回字符串的地址  

  7. }  

2.內存泄漏

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

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

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

[cpp] view plain copy


  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:運行時提示出錯

 

[cpp] view plain copy


  1. char str[10]={0};  

  2.   

  3. strcpy(str,"hello world!");//error!  

  4.  


https://blog.csdn.net/qq_38211852/article/details/80085591

*博客內容為網友個人發布,僅代表博主個人觀點,如有侵權請聯系工作人員刪除。



關鍵詞:

相關推薦

技術專區

關閉