C:清除STDIN

基本上在每个printf之前的windows的代码块我有“fflush(stdin);” 哪个有效。 当我将我的代码复制到Linux时,它不起作用,也没有“fflush(stdin);”的替代方案。 我发现了。 无论我采用哪种方式,输入似乎都没有在缓冲区中清除,或者我的代码中的某些内容不正确。

#include  #include  #include  #include  int main() { char pbuffer[10], qbuffer[10], kbuffer[10]; int p=0, q=0, k=0; int r, i, Q, count, sum; char a[3]; a[0]='y'; while(a[0]=='y' || a[0]=='Y') { printf("Enter ap value: \n"); fgets(pbuffer, sizeof(pbuffer), stdin); p = strtol(pbuffer, (char **)NULL, 10); printf("Enter aq value: \n"); fgets(qbuffer, sizeof(qbuffer), stdin); q = strtol(qbuffer, (char **)NULL, 10); printf("Enter ak value: \n"); fgets(kbuffer, sizeof(kbuffer), stdin); k = strtol(kbuffer, (char **)NULL, 10); while(p0) { count++; r = Q%10; sum = sum + pow(r,k); Q = Q/10; } if ( p == sum && i>1 && count==k ) { printf("%d\n",p); } p++; a[0]='z'; } while((a[0]!='y') && (a[0]='Y') && (a[0]!='n') && (a[0]!='N')) { printf("Would you like to run again? (y/n) "); fgets(a, sizeof(a), stdin); } } return 0; } 

调用fflush(stdin)不是标准的,因此行为未定义(有关更多信息,请参阅此答案 )。

你可以调用scanf ,传递一个格式字符串,指示函数读取所有内容,包括换行符'\n' ,如下所示:而不是在stdin上调用fflush

 scanf("%*[^\n]%1*[\n]"); 

星号告诉scanf忽略结果。

另一个问题是调用scanf将字符读入变量a ,格式说明符为" %s" :当用户输入非空字符串时,null终止符会创建缓冲区溢出,导致未定义的行为( char a是一个字符的缓冲区) ;字符串"y"有两个字符 – {'y', '\0'} ,第二个字符写在缓冲区的末尾。 您应该将a更改a具有多个字符的缓冲区,并将该限制传递给scanf

 char a[2]; do { printf("Would you like to run again? (y/n) \n") scanf("%1s", a); } while(a[0] !='y' && a[0] !='Y' && a[0]!='n' && a[0]!='N' ); } 

我认为你要做的事情比看起来更难。

我对你要做的事情的解释是禁用提前类型,这样如果用户在你的程序处理其他东西时键入一些字符,它们就不会出现在提示符下。 这实际上很难做到,因为它是一个操作系统级别的function。

在打印提示之前,您可以在设备上执行非阻塞读取,直到您在errno中获得EWOULDBLOCK。 或者tcsetattr函数系列可能有所帮助。 看起来有一种方法可以在那里消耗文件描述符的输入,但它可能与fgets / fscanf交互不良

更好的想法是不要担心它。 Unix用户习惯于预先输入类型,你想要的是他们想要的意外行为。

不需要刷新输入缓冲区。

OP使用fgets()而不是scanf()进行输入正确,OP应继续使用以下方法:

 char a; while(a !='y' && a !='Y' && a!='n' && a!='N' ) { printf("Would you like to run again? (y/n) \n"); if (fgets(kbuffer, sizeof(kbuffer), stdin) == NULL) Handle_EOForIOerror(); int cnt = sscanf(kbuffer, " %c", &a); // Use %c, not %s if (cnt == 0) continue; // Only white-space entered } 

最好不要使用scanf()因为它试图一次性处理用户IO和解析,并且做得不好。


某些现有OP的困境源于scanf(" %s", &a);之后的fgets() scanf(" %s", &a); (这是UB,因为它应该是scanf(" %c", &a); scanf()scanf()fgets()混合通常会出现scanf(" %c", &a);离开Enter'\n'在输入缓冲区中强制代码要在下一个fgets()之前调用输入缓冲区。否则fgets()会得到陈旧的'\n'而不是新的信息行。

通过仅对用户IO使用fgets() ,需要否定刷新。


示例fgets()包装器

 char *prompt_fgets(const char *prompt, char dest, long size) { fputs(prompt, stdout); char *retval = fgets(dest, size, stdin); if (retval != NULL) { size_t len = strlen(dest); if (len > 1 && dest[len-1] == '\n') { // Consume trailing \n dest[--len] = '\0'; } else if (len + 1 == dest) { // Consume extra char int ch; do { ch == fgetc(stdin); } while (ch != '\n' && ch != EOF); } return retval; }