在这里,我尝试从字符串中获取令牌,并以空格分隔。
但是,如果我在没有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;
}
答案 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()
不允许进行正确的错误检查。