注意: fflush(stdin);
可能是未定义的行为。阅读:为什么fflush(stdin)
错了?
int fflush(FILE *ostream);
ostream
指向未输入最近操作的输出流或更新流,该
函数fflush
导致该流的任何未写入数据被传递到主机环境以写入文件;否则,behavior
就是Undefined
。
您可以尝试循环并阅读直到EOF
或\n
给出此常见问题解答条目,而不是fflush(stdin)
按照我在下面的回答中建议的那样。
编辑:感谢@Jonathan Leffler:
有些平台fflush(stdin)
是完全定义的(作为该平台上的非标准扩展)。主要的例子是一个众所周知的系统家族,统称为 Windows。Microsoft 的规范If is open for input, clear the contents of the buffer。int fflush( FILE *stream );
stream
fflush
我对您的代码还有疑问;什么是M
表达unsigned int b = pow(2,M-1);
?如果你不定义它应该是一个错误。你发布完整的代码吗?
关于错误检测的逻辑:
如果用户输入无效,则重新读取该值
不,scanf()
不返回错误代码。它返回成功转换的次数。
int scanf ( const char * 格式, ... );
返回值
成功时,函数返回参数列表中成功填充的项目数。由于匹配失败、读取错误或到达文件结尾,此计数可以与预期的项目数匹配或更少(甚至为零)。
如果发生读取错误或读取时到达文件结尾,则设置正确的指示符(feof
或ferror
)。并且,如果在任何数据可以成功读取之前发生任何一种情况,EOF
则返回。
如果在解释宽字符时发生编码错误,则函数设置errno
为EILSEQ
.
所以实际上取决于遇到的错误,返回值可能为零,EOF。您应该使用int ferror ( FILE * stream );
和errno
宏进行错误检测(检查链接中给出的示例)。
由于无效输入而可能出现的错误可能是:
EILSEQ
: 输入字节序列没有形成有效字符。
EINVAL
: 没有足够的论据;或格式为 NULL。
ERANGE
: 整数转换将超过相应整数类型可存储的大小。
查看scanf 手册以获取完整列表。
无限循环的原因:
系统会跟踪到目前为止已看到哪些输入。每次调用scanf
都从最后一个停止匹配输入的地方开始。这意味着如果前一个发生错误scanf
,它未能匹配的输入仍然未读,就好像用户提前输入了一样。如果不注意丢弃错误输入,并且使用循环来读取输入,您的程序可能会陷入无限循环。
因此,例如在您的代码中:
x = scanf("%u", &a);
// ^
// need a number to be input
但是假设您没有输入数字,而是输入了无效的字符串,例如"name"
(而不是数字,如您所说)。这将导致scanf()
函数在尝试匹配无符号整数 ( "%u"
) 时失败,并且该单词"name"
未被读取。所以下一次循环时,scanf()
不等待新的用户输入,它会尝试再次转换“名称”。
类似地,如果输入是29.67
,“ %u
”将仅匹配前两个字符(the 29
),将.67
作为未读输入留给下一次调用scanf()
.
即使输入正确,如29
,结束输入的换行符仍然未读。通常这不是问题,因为大多数转换会自动跳过前导空格,例如前一行的尾随换行符。但是,某些转换 ("%c"
和"%["
) 不会跳过任何前导空格,因此您必须手动进行。
为了避免这种无限循环一个建议:
(记住:正如我推荐的那样ferror()
,错误值更适合检测无效输入。此外,它只是为了学习目的,如果你需要实现一个严肃的应用程序,你应该使用fgets(str)
而不是scanf()
后面跟着解析str
输入来验证输入是否已验证)
input:
//fflush(stdout); //use if needed, as \n used in printf no need of fflush-stdout
printf("\nEnter any integer: ");
x = scanf("%u", &a); // always wait for new symbols
printf("%u", a);
if(x == 0){ // x=0, if error occurred
// read all unread chars
while ((ch = getchar()) != '\n' && ch != EOF);
goto input;
}
这只是一个可能适用于您的代码的建议(对我有用,您的代码 + gcc)。但是如果你错误地使用了这种技术,它可能会在你的代码中留下一个错误:
阅读如何刷新输入缓冲区?
如果您确定输入流中有不需要的数据,您可以使用以下一些代码片段来删除它们。但是,如果您在输入流中没有数据时调用这些,程序将等待直到有数据,这会给您带来不希望的结果。