我正在尝试: - 如果用户输入无效值,则重新读取该值。但问题是scanf()
只执行一次,并且不会执行任何其他时间,程序会陷入无限循环。
#include<stdio.h>
#include<math.h>
main()
{
unsigned int a;
unsigned int b = pow(2,M-1);
unsigned int c;
int x;
printf("b = %i",b);
input:
fflush(stdin);
fflush(stdout);
printf("\nEnter any integer: ");
x = scanf("%u",&a);
printf("%u",a);
if(x==0)
goto input;
printf("\na = %i",a);
c = a & b;
printf("\nc = %i",c);
if(c)
printf("\nthe bit %i is set",M);
else
printf("\nthe bit %i is not set",M);
}
我尝试在%u
之前添加空格,并尝试fflush(stdin)
但没有任何效果。
答案 0 :(得分:10)
警告:fflush(stdin);
可能是未定义的行为。阅读:Why fflush(stdin)
is wrong?
<强>
int fflush(FILE *ostream);
强>
ostream
指向输出流或更新流 最近的操作没有输入,fflush
函数导致任何操作 要传递到主机环境的该流的未写入数据 写入文件;否则,behavior
为Undefined
。
您可以尝试循环并阅读EOF
或\n
给定this FAQ entry而不是fflush(stdin)
,如我在下面的回答中所建议的那样。
编辑:感谢@ Jonathan Leffler:
有些平台
fflush(stdin)
已完全定义(作为该平台上的非标准扩展)。主要的例子是一个众所周知的系统系统,统称为Windows。 Microsoft的int fflush( FILE *stream );
规范如果stream
已打开输入,fflush
将清除缓冲区的内容。
我的代码还有其他疑问;表达式M
中的unsigned int b = pow(2,M-1);
是什么?如果不定义它应该是一个错误。你发布完整的代码吗?
关于错误检测的逻辑:
如果用户输入无效
,则重新读取该值
不,scanf()
不会返回错误代码。它返回成功转换的次数。
int scanf ( const char * format, ... );
返回值
成功时,该函数返回成功填充的参数列表的项数。这个数量可以匹配 由于匹配,预期的项目数或更少(甚至为零) 失败,读数错误或文件结束的范围。如果发生读取错误或达到文件结尾 阅读时,设置了正确的指标(
feof
或ferror
)。而且,如果有的话 在成功读取任何数据之前,会返回EOF
。如果解释宽字符时发生编码错误,则 函数集
errno
为EILSEQ
。
所以实际上根据遇到的错误,返回值可能为零,EOF。您应该使用int ferror ( FILE * stream );
和errno
宏进行错误检测(请查看链接中给出的示例)。
因无效输入而导致的错误可能是:
EILSEQ
:输入字节序列不构成有效字符EINVAL
:论证不够;或格式为NULLERANGE
:整数转换将超过可存储在相应整数类型中的大小。
检查scanf manual以获取完整列表。
无限循环的原因:
系统会跟踪到目前为止看到的输入。每次对scanf
的调用都会从最后一个停止匹配输入的位置开始。这意味着如果前一个scanf
发生错误,则无法匹配的输入仍未读取,就像用户提前输入一样。如果不小心丢弃错误输入,并且使用循环来读取输入,则程序可能会陷入无限循环。
例如,在您的代码中:
x = scanf("%u", &a);
// ^
// need a number to be input
但是假设您没有输入数字,但输入的字符串无效,例如"name"
(而不是你所说的数字)。这将导致scanf()
函数在尝试匹配无符号整数("%u"
)时失败,并且单词"name"
未被读取。因此,下一次循环,scanf()
不等待新的用户输入,它会再次尝试转换“名称”。
同样,如果输入为29.67
,则“%u
”将仅匹配前两个字符(29
),将.67
作为未读输入下次致电scanf()
。
即使输入正确,如29
,结束输入的换行仍然未读。通常这不是问题,因为大多数转换会自动跳过前导空格,例如前一行的尾随换行符。但是,某些转化("%c"
和"%["
)不会跳过任何前导空格,因此您必须手动执行此操作。
避免这种无限循环一个建议:
(记住:正如我建议使用ferror()
,错误值更适合检测无效输入。此外,它仅用于学习目的,如果您需要实现严肃的应用程序,则应使用{{1而不是fgets(str)
后跟那个解析scanf()
输入来验证输入是否有效)
str
这只是一个可能与你的代码一起工作的建议(为我工作,你的代码+ gcc)。但如果您使用此技术不正确,可能会在您的代码中留下错误:
阅读How do I flush the input buffer?
如果您确定输入流中包含不需要的数据,则可以使用 以下一些代码段删除它们。但是,如果你 当输入流中没有数据时调用这些,程序将 等到有,这会给你带来不良后果。
答案 1 :(得分:1)
这是一种避免无限循环的解决方法。 请使用do while循环代替goto:
do {
printf("\nEnter any integer: ");
x = scanf("%u",&a);
printf("%u",a);
if( x == 0)
{
char c;
printf("hit any key \n");
c = getchar();
}
} while(x==0);