• 正文
  • 相關(guān)推薦
申請入駐 產(chǎn)業(yè)圖譜

10種初學者最常見的c語言段錯誤實例及原因分析

05/27 10:40
491
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點資訊討論

段錯誤相信是每一個C語言初學者都會遇到的一個問題,很多初學者看到這個錯誤就開始抓狂。

但是沒寫過段錯誤的程序員不是個合格的程序員!

一口君寫了這么多年代碼,有時候還是會出現(xiàn)段錯誤。

下面給大家整理了一些C 語言典型的段錯誤(Segmentation Fault)實例及代碼示例,按常見場景分類說明:

1. ?引用空指針?

#include?<stdio.h>
int?main()?{
? ??int?*p =?NULL;
?
? ??printf("%dn", *p);?// 解引用空指針
? ??return?0;
}

?原因?:p 未指向有效內(nèi)存地址。

2. ?訪問受保護的內(nèi)存地址?

int?*p = (int*)1; ?// 強制將指針指向地址 0x1
*p =?100; ? ? ? ? ?// 訪問系統(tǒng)保護的內(nèi)存區(qū)域

?原因?:嘗試操作內(nèi)核或系統(tǒng)保留的內(nèi)存區(qū)域。

3. ?修改字符串常量?

char?*str =?"hello"; ?// 字符串常量存儲在只讀區(qū)
str[0] =?'H'; ? ? ? ??// 嘗試修改常量區(qū)數(shù)據(jù)

?原因?:字符串字面量存儲在只讀內(nèi)存段,不可被修改6。

4. ?棧溢出?

void?infinite_loop()?{
? ? infinite_loop(); ?// 無限遞歸導致棧空間耗盡
}
int?main()?
{?
?infinite_loop();?
}

?原因?:無限遞歸導致棧內(nèi)存溢出6。

5. ?數(shù)組越界訪問?

int?arr[5];
arr[5] =?10; ?// 合法索引為 0~4,越界訪問無效內(nèi)存

?原因?:訪問超出數(shù)組定義大小的內(nèi)存區(qū)域。

#include?<stdio.h>
?
int?main()?{?
? ??int?arr[5] = {0,?1,?2,?3,?4};
?
? ??printf("%dn", arr[10]);?// 訪問不存在的元素
? ??return?0;
}

執(zhí)行結(jié)果:未定義行為,可能會導致程序崩潰或打印出垃圾值。

數(shù)組越界是一些新手最容易出錯的地方,經(jīng)常因為數(shù)組下標控制不好,導致訪問越界,而這種情況可能99%幾率不是立刻報段錯誤,也可能程序運行幾年都不報錯, 但是它一旦報了錯,就會特別隱蔽,非常難查。

剛工作的時候在zte,曾經(jīng)有2位大佬追一個德國運營商現(xiàn)場報的bug,花了一個月時間,最后發(fā)現(xiàn)是數(shù)組越界導致。

6. ?使用未初始化的指針?

int?*p; ? ? ? ?// 未初始化指針
*p =?42; ? ? ??// 野指針指向無效地址

?原因?:指針未指向有效內(nèi)存空間。

7. ?訪問已釋放的內(nèi)存?

int?*p =?malloc(sizeof(int));
free(p);
*p =?10; ? ? ??// 內(nèi)存釋放后繼續(xù)使用

?原因?:操作已被釋放的動態(tài)內(nèi)存區(qū)域。

8. ?緩沖區(qū)溢出?

char?buffer[5];
strcpy(buffer,?"HelloWorld"); ?// 超出 buffer 容量

?原因?:字符串操作超過目標緩沖區(qū)大小。

9. ?雙重釋放內(nèi)存?

int?*p =?malloc(sizeof(int));

free(p);
free(p); ?// 重復釋放同一塊內(nèi)存

?原因?:多次釋放同一內(nèi)存導致堆管理器異常。

10. ?強制類型轉(zhuǎn)換錯誤?

int?num =?42;

char?*p = (char*)num; ?// 將整數(shù)值強制轉(zhuǎn)換為地址
*p =?'A'; ? ? ? ? ? ? ?// 訪問非法地址

?原因?:將非指針類型強制轉(zhuǎn)換為指針并解引用。

11.格式化字符串與參數(shù)類型不匹配示例

int?data =?0;
sprintf(buf,"%s",data);

12、忘記字符串結(jié)尾的空字符示例:

#include?<stdio.h>
?
int?main()?{
?
? ??char?str[5] = {'H',?'e',?'l',?'l',?'o'};?// 缺少 ''
?
? ??printf("%sn", str);
? ??return?0;
}

執(zhí)行結(jié)果:未定義行為,可能會打印出亂碼直到遇到一個’’。

13、緩沖區(qū)溢出示例:

#include?<stdio.h>
#include?<string.h>

int?main()?{
? ??char?dest[5];
? ??
? ??strcpy(dest,?"Hello, World!");?// 目標緩沖區(qū)太小
? ??printf("%sn", dest);
? ??return?0;
}

執(zhí)行結(jié)果:未定義行為,可能會崩潰或覆蓋內(nèi)存。

14、未檢查類型大小示例:

#include?<stdio.h>
?
int?main()?{
? ??char?*p = (char?*)malloc(10?*?sizeof(int));
? ??int?*q = (int?*)p;?// 錯誤的假設(shè)char和int大小相同
?
? ??for?(int?i =?0; i <?10; ++i) {
? ? ? ? q[i] = i;?// 可能導致內(nèi)存越界
? ? }
?
? ??free(p);
? ??return?0;
}

執(zhí)行結(jié)果:未定義行為,可能會導致內(nèi)存越界。

15、變量未正確初始化示例:

#include?<stdio.h>
?
int?main()?{
? ??int?num =?123;
?
? ??printf("%sn", num);?// 錯誤的格式化字符串,應為%d
? ??return?0;
}

執(zhí)行結(jié)果:未定義行為,可能會打印出任意值。

16、忽視錯誤返回值示例:

#include?<stdio.h>
#include?<stdlib.h>

int?main()?{
?
? ? FILE *file = fopen("nonexistent.txt",?"r");
? ??if?(!file) {
? ? ? ??// 忽視錯誤,沒有處理
? ? }
?
? ??// 使用file...
? ? fclose(file);
? ??return?0;
}

執(zhí)行結(jié)果:如果文件不存在,程序會嘗試使用未初始化的指針,可能導致崩潰。

總結(jié)

段錯誤本質(zhì)是訪問了非法內(nèi)存地址,可通過以下方式避免:

    初始化指針并檢查有效性;避免越界操作數(shù)組或緩沖區(qū);謹慎處理動態(tài)內(nèi)存的分配與釋放;區(qū)分常量區(qū)與變量區(qū)的數(shù)據(jù)修改權(quán)限對一些庫函數(shù)返回值一定要判斷

相關(guān)推薦

登錄即可解鎖
  • 海量技術(shù)文章
  • 設(shè)計資源下載
  • 產(chǎn)業(yè)鏈客戶資源
  • 寫文章/發(fā)需求
立即登錄

公眾號『一口Linux』號主彭老師,擁有15年嵌入式開發(fā)經(jīng)驗和培訓經(jīng)驗。曾任職ZTE,某研究所,華清遠見教學總監(jiān)。擁有多篇網(wǎng)絡協(xié)議相關(guān)專利和軟件著作。精通計算機網(wǎng)絡、Linux系統(tǒng)編程、ARM、Linux驅(qū)動、龍芯、物聯(lián)網(wǎng)。原創(chuàng)內(nèi)容基本從實際項目出發(fā),保持原理+實踐風格,適合Linux驅(qū)動新手入門和技術(shù)進階。