scanf() 系列函数是一种折磨测试,不应该对新手程序员施加。它们非常难以准确使用。
分析
即使忽略代码布局(完全令人震惊——这是专业评估)并假设您有这样的变量声明:
double value;
double *d = &value;
char newline;
char *c = &newline;
int val;
而不是更合理的:
double d;
char c;
int val;
你的片段有大量的问题塞进几行。
while(val = fscanf(stdin,"%lf%c",d,c) != EOF)
{if(val==0){//error}
else if(c='\n'){//error print char}
else{//print double}
}
您已将比较结果分配给val,而不是将fscanf() 的返回值分配给val 并将其与EOF 进行比较。
while ((val = fscanf(stdin, "%lf%c", d, c)) != EOF)
现在代码只是错误的; fscanf() 可以返回 EOF(通常,但不保证是 -1),或 0,或 1 或 2,其中只有 2 是您正在寻找的答案.所以,循环条件应该是:
while ((val = fscanf(stdin, "%lf%c", d, c)) == 2)
或者,如果你有更简单的定义,那么它应该是:
while ((val = fscanf(stdin, "%lf%c", &d, &c)) == 2)
现在您知道读取了两个值。循环内的if (val == 0) 检查现在是多余的;只有在val == 2 时才进入循环体。
您可以检查*c 中的值是否是换行符进行比较而不是赋值:
if (*c == '\n')
(或if (c == '\n');假设您有更简单的声明并忘记了原始代码中的& 字符。)但是,如果c 不是换行符,则它是一个错误,所以实际上它应该是一个!= 测试。
while ((val = fscanf(stdin, "%lf%c", &d, &c)) == 2)
{
if (c != '\n')
...print error...
else
printf("Number = %g\n", d);
}
循环之后,您可以测试val == EOF vs val == 0 vs val == 1。第一个意味着您已达到 EOF 或发生错误;第二个表示输入中的下一个字符既不是空格也不是有效数字的一部分(例如,.、+、- 以外的字母或标点符号)。 val == 1 案例是深奥的;它要求文件的结尾出现在后面没有换行符(或任何其他字符)的数字之后。
无限循环
顺便说一句,导致无限循环的最可能原因是输入中的无效(非数字、非空白)字符。而且,经过仔细检查,我发现输入的第二行有一个r;这将触发您的代码的无限循环。 fscanf() 将始终返回 0,这不是 EOF,因此循环继续。 (它无法读取r 和%c,因为它必须先成功读取一个数字。)
合成
%lf 格式将跳过任何前导空格,包括换行符,因此您的代码试图确保每行有一个数字,并且没有尾随空格。在这种情况下,您可能会更好地使用fgets() 和strtod(),尽管完全正确地使用strtod() 并非完全无关紧要。以下代码忽略了strtod() 的细节。
char line[4096];
double d;
while (fgets(line, sizeof(line), stdin) != 0)
{
char *end;
d = strtod(line, &end);
if (end == line || *end != '\n')
...incorrect format...
else
printf("Number = %g\n", d);
}
fgets() 返回空指针的唯一原因是您已达到 EOF 或发生错误。您可能希望在调用 strtod() 之前设置 errno = 0;,然后检查其值以发现超出范围的数字。