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的任何未写入的数据被传送到主机环境以写入文件; 否则, behaviorUndefined

你可以尝试一个循环,并阅读,直到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(甚至为零)。

如果发生读取错误或在读取时达到文件结束,则设置适当的指示符( feofferror )。 而且,如果在任何数据可以被成功读取之前发生,则返回EOF

如果发生编码错误解释宽字符,函数将errnoEILSEQ

所以实际上取决于遇到的错误返回值可能是零,EOF。 你应该使用int ferror ( FILE * stream );errnomacros来检测错误(检查链接中给出的例子)。

由于无效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()然后是parsingstrinput以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);