简体   繁体   English

在 windows 上工作的 linux 上的分段错误

[英]Segmentation fault on linux-working on windows

The goal of this program is to scan a string populated with numbers and white spaces between them and insert each number into an array.这个程序的目标是扫描一个填充了数字和它们之间的空格的字符串,并将每个数字插入到一个数组中。 Then each number from the array is sent to checkPowerOfTwo function which determines if the number sent is a power of two and prints the calculation.然后将数组中的每个数字发送到checkPowerOfTwo function 确定发送的数字是否为 2 的幂并打印计算结果。

When I run this program on windows everything is workingfine.当我在 windows 上运行此程序时,一切正常。 Running on Linux causes a segmentation fault.在 Linux 上运行会导致分段错误。

I'm compiling my code on a Linux server with: gcc -std=c99 -Wall -pedantic-errors -Werror -DNDEBUG main.c -o mtm_tot .我在 Linux 服务器上编译我的代码: gcc -std=c99 -Wall -pedantic-errors -Werror -DNDEBUG main.c -o mtm_tot It compiles successfully with no errors or warnings.它编译成功,没有错误或警告。 The problem arises when I try to run a tester: ./mtm_tot< test1.in > tmpout .当我尝试运行测试仪时出现问题: ./mtm_tot< test1.in > tmpout After pressing enter on this line Segmentation fault rises.在这条线上按回车后, Segmentation fault上升。

test1.in contains : 8

5 9 -1 4 20 256 -32 17 32

The code:编码:

#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;
}

With the input file test1.in as shown in the question you specify a size of 8 and provide 9 numbers.使用问题中所示的输入文件test1.in指定大小为 8 并提供 9 个数字。

Your code你的代码

        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," ");
            }
        }

will enter the outer while loop and process 8 numbers in the first run of the inner for loop.将进入外部while循环并在内部for循环的第一次运行中处理 8 个数字。 As you have entered 9 numbers, token will not be NULL and the outer loop will repeat and run the inner loop again.由于您输入了 9 个数字,因此token不会是NULL ,外循环将重复并再次运行内循环。 This will partially overwrite the numbers in the array.这将部分覆盖数组中的数字。 After processing the 9th number in the first cycle, token will become NULL and in the 2nd cycle sscanf will try to use the NULL pointer which may lead to a segmentation fault.在第一个周期处理第 9 个数字后, token将变为NULL ,在第二个周期中, sscanf将尝试使用NULL指针,这可能会导致分段错误。

You should combine the counter and the check for NULL in the loop condition.您应该在循环条件中结合计数器和NULL的检查。 I also recommend to check the return value of sscanf because a value != 1 will indicate invalid input.我还建议检查sscanf的返回值,因为值!= 1表示输入无效。

        for(int i=0; (i<size) && (token!=NULL); i++) {
            if(sscanf(token,"%d",&numbers[i]) != 1) {
                /* invalid input */
                break;
            }
            token=strtok(NULL," ");
        }

Of course the code following the loop must handle the case that the loop ends with i < size if not enough values were present.当然,如果没有足够的值,循环后面的代码必须处理循环以i < size结束的情况。

Edit: additional clarification below编辑:下面的附加说明

Note: The error checking for scanf is incomplete.注意: scanf的错误检查是不完整的。 It will return 0 if it couldn't convert an integer number, but it will also return 1 if it converted an integer number and anything is following it, eg for 123abc it will convert 123 and return 1 .如果它不能转换一个 integer 数字,它将返回0 ,但如果它转换一个 integer 数字并且它后面有任何东西,它也会返回1 ,例如对于123abc它将转换123并返回1 To check what may follow the number you could add a %c conversion and if the return values is 2 check the converted character.要检查数字后面可能出现的内容,您可以添加%c转换,如果返回值为2 ,请检查转换后的字符。 ( '\n' or '\r' may be OK here.) '\n''\r'在这里可能没问题。)

I would prefer to use strtol in a loop to parse the numbers in str .我宁愿在循环中使用strtol来解析str中的数字。

BTW: The size calculation for the allocation of str is wrong.顺便说一句: str分配的大小计算是错误的。 sizeof int is the size of the internal binary representation of an int value which is 4 (4 bytes = 32 bits) on many systems. sizeof intint值的内部二进制表示的大小,在许多系统上为 4(4 字节 = 32 位)。 It has nothing to do with how many characters are needed for a string representation of a number.它与数字的字符串表示需要多少个字符无关。 A valid number -2147483648 needs 11 characters.有效数字-2147483648需要 11 个字符。

(You could use a buffer str that is too small for the whole line but big enough for more than a valid number if you move the remaining data to the beginning and append new data after pasing a number until you have read the terminating newline.) (如果您将剩余的数据移到开头,并且在输入数字后将 append 新数据移动到您已读取终止的换行符,则您可以使用对于整行来说太小但对于超过有效数字的缓冲区str 。)

Your program logic is wrong:您的程序逻辑错误:

  for (int i = 0; i < size; i++) {
    sscanf(token, "%d", &numbers[i]);
    token = strtok(NULL, " ");

    // token may become NULL here
    // and sscanf will segfault right after
  }

There may be other problems though.不过可能还有其他问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM