0

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

#include <stdio.h>
#include <math.h>
#include <limits.h>
#include <ctype.h>

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 a p value: \n");
      fgets(pbuffer, sizeof(pbuffer), stdin);
      p = strtol(pbuffer, (char **)NULL, 10);

      printf("Enter a q value: \n");
      fgets(qbuffer, sizeof(qbuffer), stdin);
      q = strtol(qbuffer, (char **)NULL, 10);

      printf("Enter a k value: \n");
      fgets(kbuffer, sizeof(kbuffer), stdin);
      k = strtol(kbuffer, (char **)NULL, 10);

      while(p<q+1)
      {
         Q=p;
         sum=0;
         count=0;
         while(Q>0)
         {
            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;
}
4

3 回答 3

2

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

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

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

星号scanf表示忽略结果。

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

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' );
}
于 2014-09-23T14:53:12.567 回答
0

不再需要刷新输入缓冲区。

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 的问题源于fgets()之后scanf(" %s", &a); (它应该是 UB scanf(" %c", &a);。混合通常会scanf()出现fgets()问题,即在输入缓冲区中scanf(" %c", &a);留下Enteror'\n'导致代码在下一个之前要刷新输入缓冲区fgets()。否则会fgets()变得陈旧'\n'而不是新的信息行。

通过用于fgets()用户 IO,不需要刷新。


样品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;
  }  
于 2014-09-23T15:39:12.953 回答
0

我认为你正在尝试做的事情比看起来更困难。

我对您尝试做的事情的解释是禁用提前输入,这样如果用户在您的程序处理其他内容时输入了一些字符,它们就不会出现在提示符处。这实际上很难做到,因为它是操作系统级别的功能。

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

一个更好的主意是完全不用担心它。Unix 用户习惯于提前输入,而您想要的是他们意想不到的行为。

于 2014-09-23T15:46:34.420 回答