输入无效输入时刷新scanf缓冲区的好方法

我一直在考虑如何刷新scanf函数中的错误条目,以允许循环提示完成它们的工作。

我在这里有一个函数调用来刷新输入。 这可行,但如果我在输入int时输入2q这样的东西,它仍然是错误的。

 void flushKeyBoard() { int ch; //variable to read data into while((ch = getc(stdin)) != EOF && ch != '\n'); } 

然后我会在另一个函数中有这样的东西:

 printf("Enter a value: "); check = scanf("%f", &b); while(check == 0) { printf("Invalid number entered. Please re-enter: "); check = scanf("%f, &b"); flushKeyBoard(); } 

还有更好的想法? 有人建议fflush(); 但在这里使用它并不是真正的标准..

使用getchar (常见,易于理解)

 int c; while ((c = getchar()) != EOF && c != '\n'); /*  

使用fgets (不太常见,不易理解)

 char buf[8]; while (fgets(buf, sizeof buf, stdin) != NULL) { size_t len = strlen(buf); /* * Exit the loop if either EOF was encountered before '\n', or * if '\n' is detected. */ if (len + 1 != sizeof(buf) || memchr(buf, '\n', len)) break; } if (feof(stdin)) { /* Handle stdin EOF. */ } else { /* Handle stdin error. */ } 

使用带scanf的scanset(可能不常见,易于理解)

 /* * Combining the scanset with assignment suppression (the '*' before the * scanset) will return EOF on EOF/error and 0 if '\n' was read. */ if (scanf("%*[^\n]") == EOF) { if (feof(stdin)) { // Handle stdin EOF. } else { // Handle stdin error. } } getchar(); // Flush the '\n'. 

使用getline (可能不常见,很难)

 char *buf = NULL; size_t bufsize = 0; ssize_t len; /* getline() will stop reading on '\n' or EOF. */ len = getline(&buf, &bufsize, stdin); /* No bytes read and EOF encountered, or there was an error. */ if (len == -1) { if (feof(stdin)) { /* Handle stdin EOF. */ } else if (ferror(stdin)) { /* Handle stdin error. */ } else { /* Handle errno error, if desired. */ } /* * The value of "buf" is indeterminate here, so you likely * just want to return from the function/program at this point * rather than continuing and potentially freeing an invalid * buffer. */ } free(buf); 

当然,所有这些方法都假设您希望处理EOF /错误发生的事情与\n不同,甚至可能所有三个都是单独的情况。 例如,通过将上面的一个片段放入一个自包含的函数中,如果读取了\n或者EOF /错误时为EOF,或者在\n上为0EOF上为EOF,并且在出错时为1 ,则可能返回0

值得注意的事情:

  • getcharfgets方法是100%跨平台的。 我更喜欢getchar方法,因为它简单。
  • scanset方法的跨平台性较差,因为并非所有编译器都实现了扫描集(因此不符合C99)。
  • getline方法也不是跨平台的:它主要在GNU / Linux和其他一些POSIX操作系统上实现; 目前不包括Windows。 一旦你有一些管理内存和使用指针的经验,你自己编写一个并不是非常困难,但你最好使用前两种方法中的一种,因为编写getline的实现可能最终会使用fgetcfgets无论如何( fgetc(stdin)getchar()应该表现相同)。

您可以使用:

 fscanf(stdin, "%*[^\n]%*c"); 

有几种方法可以做到这一点。 实际上,你要做的就是消耗一行文字直到\ n字符(或EOF)。要做到这一点,你应该使用sscanf(或fscanf。)

 sscanf("%*[^\n]\n"); 

这使用正则表达式[^ \ n] * \ n(任意数量的字符不是\ n,后跟一个\ n)并使用与之匹配的所有内容。

编辑:因为我愚蠢而且忘了scanf正则表达式使用稍微不同的语法。