什么是分段错误,为什么该程序显示分段错误?

时间:2018-07-31 05:10:42

标签: c string segmentation-fault scanf strtok

在这里,我尝试从字符串中获取令牌,并以空格分隔。 但是,如果我在没有while循环的情况下运行此程序,则会遇到分段错误。很好,但是为什么呢?


我的代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    char c[1000];
    int tnum, a, b, d;
    char *n;
    scanf("%d", &tnum);
    while(tnum != 0)
    {
        scanf("%[^\n]s", c);

        n = strtok(c, " ");
        a = atoi(n);

        n = strtok(NULL, " ");
        b = atoi(n);

        n = strtok(NULL, " ");
        d = atoi(n);

        printf("%d\n", a * b * d);
        tnum--;
    }
    return 0;
}

1 个答案:

答案 0 :(得分:0)

当程序尝试访问不允许使用的内存时,通常会导致分段错误。阅读What is a segmentation fault?

在您的情况下,可能是由于您使用字符数组c[]strtok()函数的方式引起的。

strtok()根据定界符修改其第一个自变量,形式为第二个自变量。

例如,如果您这样做

char s[]="hello world how are you?";
strtok(s, " ");
printf("\n%s", s);

输出将只是

hello

不是

hello world how are you?

因为定界符的位置被覆盖。这就是strtok()不能用于字符串文字的原因。

在没有while循环的情况下尝试运行时不会出错的原因可能是因为c[]在允许程序访问的部分内存中有一些空格。 strtok()会继续寻找定界符,直到找到\0表示字符串的结尾为止,因为c[]有垃圾,该结尾可能在任何地方。


您尚未初始化c[],它只是具有一些垃圾值。在您在中预留的1000个字符的空间中,strtok()可能被认为是分隔符的c[](空格)。并且如果在这1000个字节中没有,则strtok()的外观将超出数组c[]的范围,并且可能会修改程序无法访问的内存。

请注意,

scanf("%[^\n]s",c);

您要程序读取所有内容,直到\n,然后是's'。多余的s是不必要的。只需完成'%[^ \ n]`。

但是scanf()不适合此操作,因为它很容易导致溢出。阅读Disadvantages of scanf。您可以尝试使用fgets()代替

if( fgets(c, sizeof(c), stdin)==NULL )
{
    //something went wrong.
}

fgets()会在错误时返回NULL

但请记住,fgets()也会读入结尾的\n。阅读Removing trailing newline character from fgets input

因此,如该帖子中所建议的那样,做类似的事情

char *pos;
if( (pos=strchr(c, '\n'))!=NULL )
{
    *pos='\0';
}

用表示字符串结尾的nul字符替换\n

你做完了

scanf("%[^\n]", c);

相反,\n会在输入缓冲区中保持未消耗状态,如果以后不注意,可能会引起麻烦。

您可能还想检出How to convert a string to integer in C,因为atoi()不允许进行正确的错误检查。