Scanf将不会执行第二次
我正在尝试: – 如果用户input无效值,则重新读取值。 但问题是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)
但没有任何工作。
编辑:我知道使用goto不推荐,但我必须这样做。 (使用循环不是一个选项)。 M是我在编译时使用gcc命令行定义的一个macros。
警告: fflush(stdin);
可能是未定义的行为。 阅读: 为什么fflush(stdin)
是错误的?
int fflush(FILE *ostream);
ostream
指向一个输出stream或一个更新stream,其中没有input最近的操作,fflush
函数会导致该stream的任何未写入的数据被传送到主机环境以写入文件; 否则,behavior
是Undefined
。
你可以尝试一个循环,并阅读,直到EOF
或\n
给出这个FAQ条目,而不是fflush(stdin)
如我在我的答案中所build议的。
编辑:感谢@ Jonathan Leffler :
有平台
fflush(stdin)
完全定义(作为该平台上的非标准扩展)。 主要的例子是一个众所周知的Windows系统。 微软的int fflush( FILE *stream );
规范int fflush( FILE *stream );
如果该stream
打开input,fflush
清除缓冲区的内容 。
我对你的代码有额外的怀疑; expression式M
是什么? unsigned int b = pow(2,M-1);
? 如果你没有定义它,那应该是一个错误。 你是否发布完整的代码?
关于你的错误检测逻辑:
如果用户input无效,则重新读取该值
不, scanf()
不返回错误代码。 它返回成功转换的次数。
int scanf(const char * format,…);
返回值
成功时,函数返回成功填充的参数列表项数。 此计数可以匹配预期的项目数量,或者由于匹配失败,读取错误或文件结束的范围而减less(甚至为零)。如果发生读取错误或在读取时达到文件结束,则设置适当的指示符(
feof
或ferror
)。 而且,如果在任何数据可以被成功读取之前发生,则返回EOF
。如果发生编码错误解释宽字符,函数将
errno
为EILSEQ
。
所以实际上取决于遇到的错误返回值可能是零,EOF。 你应该使用int ferror ( FILE * stream );
和errno
macros来检测错误(检查链接中给出的例子)。
由于无效input可能导致的错误可能是:
EILSEQ
:input字节序列不构成有效字符。
EINVAL
:没有足够的论据; 或格式为NULL。
ERANGE
:整数转换将超过可存储在相应整数types中的大小。
检查scanf手册的完整列表。
无限循环的原因:
系统跟踪到目前为止已经看到的input。 每次调用scanf
都会从最后一个停止匹配input的地方开始。 这意味着如果前一个scanf
发生错误,那么它未匹配的input仍然是未读,就像用户在前面input一样。 如果不小心丢弃错误input,并且使用循环读取input,则程序可能陷入无限循环。
所以例如在你的代码中:
x = scanf("%u", &a); // ^ // need a number to be input
但是,假设你不input一个数字,但input了一个无效的string,例如"name"
(而不是数字,正如你所说的)。 这将导致scanf()
函数在尝试匹配无符号整数( "%u"
)时失败,单词"name"
保持未读。 所以下一次循环, scanf()
不会等待新的用户input,它会尝试再次转换“name”。
类似地,如果input是29.67
,那么“ %u
”将只匹配前两个字符( 29
),留下.67
作为下一次调用scanf()
未读input。
即使input正确,如29
,结束input的换行仍然是未读。 通常情况下,这不是一个问题,因为大多数转换会自动跳过前一行的前导空格,例如后面的换行符。 但是,有些转换( "%c"
和"%["
)不会跳过任何前导空格,因此您必须手动执行。
为了避免这个无限循环一个build议:
(请记住:因为我推荐使用ferror()
,所以error-value更适合检测无效input。此外,它只是用于学习的目的,如果你需要实现一个严重的应用程序,你应该使用fgets(str)
而不是scanf()
然后是parsingstr
input以validationinput是否有效)
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; }
这只是一个build议,可能会与您的代码(为我工作,你的代码+ gcc)工作。 但是,如果您错误地使用这种技术,可能会在代码中留下一个错误:
阅读如何刷新input缓冲区?
如果您确定inputstream中有不需要的数据,则可以使用以下某些代码片段将其删除。 但是,如果在inputstream中没有数据时调用这些数据,程序将一直等到出现这种情况,这会给您带来不希望的结果。
这是避免无限循环的解决方法。 请使用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);