You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:30:52