首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

C語言輸出字串中的數字群:Segmentation Fault 錯誤分析與修正

     編輯:程式設計綜合問答

問題背景

在 C 語言中,若要從字串中提取連續的數字(數字群)並統計個數,例如輸入 89cy129 應輸出 89、129 共 2 組,許多初學者會編寫類似以下的程式碼,卻在執行時遇到 Segmentation fault(段錯誤)。

常見錯誤程式碼分析

#include <stdio.h>

int main() {
    int a[80], i=0, *pa, an=0;
    char str[80], *pstr=str;
    void getnum(char *pstr);
    gets(str);
    getnum(*pstr);  // 錯誤:傳入字元而非指標
    return 0;
}

void getnum(char *pstr) {
    int a[80], i=0, *pa, ndigit=0, digit=0;
    char str[80];  // 區域陣列未初始化,遮蔽外部 str
    for(i=0; *(pstr+i)!='\0'; i++) {
        if(*(pstr+i)>='0' && *(pstr+i)<='9')
            digit = digit*10 + (*(pstr+i)-48);
        if(*(pstr+i)<'0' || *(pstr+i)>'9') {
            *pa = digit;  // pa 未初始化,導致野指標寫入
            pa++;
            ndigit++;
            digit=0;
        }
    }
    for(i=0; i<ndigit; i++)
        printf("%d,", *pa);  // pa 已移動至陣列末尾,讀取無效記憶體
}

核心錯誤原因

  1. 指標未初始化:int *pa; 未指向有效記憶體,直接解參考寫入會導致段錯誤。
  2. 參數傳遞錯誤:getnum(*pstr) 傳入的是字元值,而函式宣告為 char *pstr,型別不匹配。
  3. 區域變數遮蔽:函式內重新宣告 char str[80] 導致外部輸入的字串無法被處理。
  4. 邏輯缺陷:數字群結束判斷只檢查非數字字元,若字串以數字結尾,最後一組不會被存入;輸出迴圈使用已遞增過的 pa 導致讀取錯誤位置。
  5. 使用危險函式:gets() 不檢查緩衝區長度,易造成緩衝區溢出,C11 標準已移除。

修正版程式碼

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

void extract_numbers(const char *str, int *numbers, int *count) {
    int num = 0;
    *count = 0;
    while (*str) {
        if (isdigit(*str)) {
            num = num * 10 + (*str - '0');
        } else if (num != 0) {
            numbers[(*count)++] = num;
            num = 0;
        }
        str++;
    }
    if (num != 0) {  // 處理字串以數字結尾的情況
        numbers[(*count)++] = num;
    }
}

int main() {
    char input[256];
    int numbers[100];
    int count = 0;

    printf("請輸入字串: ");
    if (fgets(input, sizeof(input), stdin)) {
        // 移除換行符
        input[strcspn(input, "\n")] = '\0';
        extract_numbers(input, numbers, &count);
        printf("共找到 %d 組數字: ", count);
        for (int i = 0; i < count; i++) {
            printf("%d%s", numbers[i], (i == count-1) ? "\n" : ", ");
        }
    }
    return 0;
}

最佳實踐建議

  • 使用 fgets() 替代 gets(),並指定緩衝區大小。
  • 指標使用前必須初始化,指向有效記憶體(如陣列首址)。
  • 函式參數傳遞指標時,確保型別匹配。
  • 避免區域變數與外部變數同名造成遮蔽。
  • 處理字串結尾邊界條件,確保最後一組數字能被捕獲。
  • 善用 ctype.h 中的 isdigit() 等函式提高可讀性與可移植性。

簡化版邏輯(僅輸出不儲存)

若僅需直接輸出數字群,可採用更簡潔的單遍歷邏輯:

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

int main() {
    char s[] = "123ss456w7";
    int in_number = 0;
    for (int i = 0; i < (int)strlen(s); i++) {
        if (isdigit(s[i])) {
            putchar(s[i]);
            in_number = 1;
        } else if (in_number) {
            putchar('\n');
            in_number = 0;
        }
    }
    if (in_number) putchar('\n');  // 結尾換行
    return 0;
}

此版本無需額外陣列,直接列印,適合簡單需求。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved