这个程序的目标是扫描一个填充了数字和空格的字符串,并将每个数字插入一个数组然后将数组中的每个数字发送到checkPowerOfTwo函数,该函数确定发送的数字是否是2的幂,并打印计算结果。
当我在windows上运行这个程序时,一切正常。在Linux上运行会导致分段错误。
我正在Linux服务器上使用:gcc -std=c99 -Wall -pedantic-errors -Werror -DNDEBUG main.c -o mtm_tot编译代码。它编译成功,没有错误或警告当我试图运行测试仪时,问题就出现了:./mtm_tot< test1.in > tmpout在这一行上按回车键后,Segmentation fault上升。

test1.in contains : 8

5 9 -1 4 20 256 -32 17 32

代码:
#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;
    } else{
        numbers=(int*)malloc(size * sizeof(int));
        str=(char*)malloc(sizeof(int)*(size+1) + (size-1)*sizeof(char));
        if(numbers==NULL||str==NULL){
            printf("Out of memory\n");
            return 0;
        } //else{
        //printf("Memory allocated\n");
        //}
        printf("Enter numbers:");
        fgets (str, sizeof(int)*(size+1) + (size-1), stdin);
        //printf("%s",str);
        token=strtok(str," ");
        while(token!=NULL){
            for(int i=0;i<size;i++){
                //printf("token is %s\n",token);
                //numbers[i]=token;
                sscanf(token,"%d",&numbers[i]);
                //printf("Inserting %s to the array\n ",numbers[i]);
                token=strtok(NULL," ");
            }
        }
    }

    for(int j =0;j<size;j++)
    {
        //sscanf(numbers[j],"%d",&x);
        //printf("the number im sending is : %d ",x);
        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",sum);
    free(numbers);
    free(str);
}

int checkPowerOfTwo(int x)
{
    int exponent=0;
    //sscanf(n,"%d",&x);
    //printf("checking number %d\n",x);
    if (x==0){
        return -1;
    } if  (x==1){
        return 0;
    }
    while( x != 1)
    {
        if(x % 2 != 0){
            return -1;
        }
        x /= 2;
        exponent++;
    }
    return exponent;
}

最佳答案

如问题所示,输入文件test1.in指定8的大小并提供9个数字。
你的代码

        while(token!=NULL){
            for(int i=0;i<size;i++){
                //printf("token is %s\n",token);
                //numbers[i]=token;
                sscanf(token,"%d",&numbers[i]);
                //printf("Inserting %s to the array\n ",numbers[i]);
                token=strtok(NULL," ");
            }
        }

将进入外部while循环,并在内部for循环的第一次运行中处理8个数字。
当您输入了9个数字,token将不会NULL并且外部循环将重复并再次运行内部循环。这将部分覆盖数组中的数字在第一个循环中处理第9个数字后,token将变为NULL并且在第2个循环中sscanf将尝试使用可能导致分割错误的NULL指针。
你应该把计数器和循环中的NULL检查结合起来。
我还建议检查sscanf的返回值,因为值!= 1将指示无效输入。
        for(int i=0; (i<size) && (token!=NULL); i++) {
            if(sscanf(token,"%d",&numbers[i]) != 1) {
                /* invalid input */
                break;
            }
            token=strtok(NULL," ");
        }

当然,如果没有足够的值,循环后面的代码必须处理循环以i < size结尾的情况。
编辑:以下附加说明
注意:scanf的错误检查不完整。如果它不能转换整数,它将返回0,但是如果它转换了整数并且后面有任何东西,它也将返回1,例如对于123abc,它将转换123并返回1。要检查数字后面的内容,可以添加一个%c转换,如果返回值是2请检查转换后的字符。('\n''\r'在这里可以。)
我更喜欢在循环中使用strtol来解析str中的数字。
BTW:str分配的大小计算错误。sizeof intint值的内部二进制表示的大小,在许多系统上为4(4字节=32位)。它与数字的字符串表示需要多少字符无关。有效数字-2147483648需要11个字符。
(如果将剩余的数据移到开头,并在输入一个数字后追加新数据,直到读取结束的换行符,则可以使用一个对整行来说太小但足以容纳多个有效数字的缓冲区str。)

关于c - Windows上的linux上的段错误,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/58629090/

10-11 23:06
查看更多