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:引用尚未初始化的指針
[cpp] view plain copy
char *p;
*p = 'A';//error,p指向未定義
例子1-2:return語句返回指向“棧內存”的指針
[cpp] view plain copy
char *GetString1(void)
{
char p[] = "hello world!";
//p在棧區,常量字符串在常量字符區
return p;//error,返回棧內存的地址
}
char p[] =
一個數組,這個數組是局部變量。
char* p =
一個指針,這個指針指向一個字符串常量
區別在于:數組的話,字符串是存在于這個數組里的,因為這個數組屬于局部變量,所以你就算把數組的地址返回給主函數,主函數也沒有辦法再訪問這個地址了。
但是如果是指向字符串常量的指針,這個字符串是放在程序的常量區而不是放在局部變量中,那么你把這個常量的地址返回給主函數,主函數也還是可以訪問它的。
char* p是一個指針,根本沒分配內存,他指向的"hello world" 是一個地址,而且地址不用加“”
而char p[]是一個數組,已經分配內存,是將"hello world" 復制到該內存里面,這個內存是可讀寫的
例子1-3:使用了被釋放的內存
[cpp] view plain copy
char *pstr = (char *)malloc(sizeof(char)*100);
free(pstr); //pstr所指的內存被釋放
if (NULL !=pstr)//沒起到作用
{
strcpy(pstr,"string!");//error,有時候程序不會提示有誤,但還是不允許
}
注意:free()釋放的是指針指向的內存!不是指針變量!這點非常非常重要!指針是一個變量,只有程序結束時才被銷毀。釋放了內存空間后,原來指向這塊空間的指針還是存在!只不過現在指針指向的內容的垃圾,是未定義的,所以說是垃圾。因此,前面我已經說過了,釋放內存后把指針指向NULL,防止指針在后面不小心又被解引用。
對比下面的例子,加深理解
例子1-4:函數返回值傳遞動態內存
[cpp] view plain copy
char* GetMemory(int num)
{
char *p = (char *)malloc(sizeof(char) * num);
return p ;//ok,返回堆區的地址值
}
例子1-5:
2.內存泄漏[cpp] view plain copy
char *GetString(void)
{
char *p = "hello world!";
//指針變量p在棧區,指向文字常量區的字符
return p;//ok,返回字符串的地址
}
概念:用動態內存分配函數動態開辟的空間,在使用完畢后未釋放,結果導致一直占據該內存單元,直到程序結束。
注意:內存泄漏是指堆內存的泄漏。它的一般表現方式是程序運行時間越長,占用內存越多,最終用盡全部內存,整個系統崩潰。
例子2-1:內存泄漏,共9*100字節發生泄漏
3.內存溢出[cpp] view plain copy
void Test(void)
{
char *p = NULL;
for ( int i = 0; i<10; i++)
{
p = (char*)malloc(100);//沒循環一次內存泄漏一塊,最后一次得到正確使用
}
strncpy(p,"string!");
free(p);
}
概念:系統分配的內存不足以放下數據,稱為內存溢出。
例子3-1:運行時提示出錯
[cpp] view plain copy
char str[10]={0};
strcpy(str,"hello world!");//error!
https://blog.csdn.net/qq_38211852/article/details/80085591
*博客內容為網友個人發布,僅代表博主個人觀點,如有侵權請聯系工作人員刪除。