Windows运行正常的C程序在Linux下触发Segmentation fault求助
解决Linux下Segmentation Fault问题的分步方案
嘿,我看了你的代码,问题主要出在几个内存管理和逻辑错误上——Windows的内存保护机制比较宽松,所以没触发错误,但Linux对内存越界的检测更严格,直接给你报了段错误。下面咱们一步步拆解修复:
1. 输入缓冲区分配完全错了
你给str分配内存的计算逻辑完全不对:
str=(char*)malloc(sizeof(int)*(size+1) + (size-1)*sizeof(char));
sizeof(int)是整数类型的字节数(一般是4),但数字的字符串长度和这个没关系啊!比如-2147483648要占11个字符,远大于4。这种错误会导致str的空间不够,fgets写入时直接越界破坏堆结构,Linux立刻就会触发段错误。
修复方法:
直接分配一个足够大的固定缓冲区就行,比如1024字节,完全能覆盖你的测试场景:
str = malloc(1024); // 替换原来的malloc行
2. Token解析的循环逻辑混乱
你处理输入token的代码逻辑有大问题:
token=strtok(str," "); while(token!=NULL){ for(int i=0;i<size;i++){ sscanf(token,"%d",&numbers[i]); token=strtok(NULL," "); } }
这会导致两种严重情况:
- 如果输入的数字数量超过
size,for循环会把数据写到numbers数组外面的内存(数组越界),直接破坏堆; - 如果输入的数字数量少于
size,token会提前变成NULL,后续sscanf读空指针,直接触发段错误。
修复方法:
用计数器控制最多读size个数字,同时判断token是否为空:
token = strtok(str, " "); int count = 0; while (token != NULL && count < size) { sscanf(token, "%d", &numbers[count]); count++; token = strtok(NULL, " "); } // 可选:如果数字不够,提示错误并退出 if (count < size) { printf("Insufficient numbers entered\n"); free(numbers); free(str); return 0; }
3. 处理scanf后的残留换行
scanf读取size后,输入缓冲区里会留下换行符,直接用fgets会读到空行。咱们加一行代码清理缓冲区:
// 在fgets前加这行 int c; while ((c = getchar()) != '\n' && c != EOF);
另外,fgets会把换行符读进来,咱们可以用strcspn去掉它,避免后续token解析出空字符串:
fgets(str, 1024, stdin); str[strcspn(str, "\n")] = '\0';
4. 负数的逻辑优化
你的checkPowerOfTwo函数虽然不会死循环,但2的幂次都是正整数,直接在开头排除负数和0更高效:
int checkPowerOfTwo(int x) { int exponent=0; if (x <= 0){ // 直接排除非正整数 return -1; } if (x==1){ return 0; } while( x != 1) { if(x % 2 != 0){ return -1; } x /= 2; exponent++; } return exponent; }
完整修复后的代码
#include <stdio.h> #include <stdlib.h> #include <string.h> int checkPowerOfTwo(int x); int main() { int exp, size, sum = 0, *numbers; char term, *str = NULL, *token; printf("Enter size of input:\n"); if (scanf("%d%c", &size, &term) != 2 || term != '\n') { printf("Invalid Size\n"); return 0; } if (size <= 0) { printf("Invalid size\n"); return 0; } numbers = (int*)malloc(size * sizeof(int)); str = malloc(1024); if (numbers == NULL || str == NULL) { printf("Out of memory\n"); free(numbers); free(str); return 0; } printf("Enter numbers:"); // 清理scanf后的换行符 int c; while ((c = getchar()) != '\n' && c != EOF); fgets(str, 1024, stdin); // 去掉末尾换行 str[strcspn(str, "\n")] = '\0'; token = strtok(str, " "); int count = 0; while (token != NULL && count < size) { sscanf(token, "%d", &numbers[count]); count++; token = strtok(NULL, " "); } if (count < size) { printf("Insufficient numbers entered\n"); free(numbers); free(str); return 0; } for (int j = 0; j < size; j++) { exp = checkPowerOfTwo(numbers[j]); if (exp >= 0) { printf("The number %d is a power of 2: %d=2^%d\n", numbers[j], numbers[j], exp); sum += exp; } } printf("Total exponent sum is %d\n", sum); free(numbers); free(str); return 0; } int checkPowerOfTwo(int x) { int exponent = 0; if (x <= 0) { return -1; } if (x == 1) { return 0; } while (x != 1) { if (x % 2 != 0) { return -1; } x /= 2; exponent++; } return exponent; }
测试结果
用你提供的测试输入8 5 9 -1 4 20 256 -32 17 32,输入size=10后,程序会输出:
The number 8 is a power of 2: 8=2^3 The number 4 is a power of 2: 4=2^2 The number 256 is a power of 2: 256=2^8 The number 32 is a power of 2: 32=2^5 Total exponent sum is 18
现在在Linux下编译运行完全正常,不会触发Segmentation fault。
内容的提问来源于stack exchange,提问作者Eliran Turgeman
相关产品推荐
相关产品推荐

