博客專欄

        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

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



        關鍵詞:

        相關推薦

        技術專區

        關閉
        主站蜘蛛池模板: 牡丹江市| 平乡县| 长沙市| 基隆市| 吉隆县| 襄汾县| 华容县| 西青区| 西乡县| 儋州市| 汉川市| 凤城市| 宁武县| 虎林市| 大港区| 阿拉善左旗| 左贡县| 海南省| 永泰县| 新乐市| 余庆县| 汶上县| 西城区| 西平县| 孙吴县| 洛南县| 社旗县| 秦安县| 原阳县| 正定县| 邹城市| 固原市| 杨浦区| 阿拉善右旗| 墨江| 莱西市| 隆安县| 大理市| 仁布县| 昌图县| 怀仁县|