在 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 已移動至陣列末尾,讀取無效記憶體
}
int *pa; 未指向有效記憶體,直接解參考寫入會導致段錯誤。getnum(*pstr) 傳入的是字元值,而函式宣告為 char *pstr,型別不匹配。char str[80] 導致外部輸入的字串無法被處理。pa 導致讀取錯誤位置。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;
}
此版本無需額外陣列,直接列印,適合簡單需求。