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

时间:2014-06-06 02:15:54

标签: c gcc scanf

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

我在这里有一个函数调用来刷新输入。如果我在2q请求int时输入类似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();
}

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

{{1}}

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

3 个答案:

答案 0 :(得分:4)

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

int c;

while ((c = getchar()) != EOF && c != '\n'); /* <note the semicolon! */

if (c == EOF) {
    if (feof(stdin)) {
        /* Handle stdin EOF. */
    }
    else {
        /* Handle stdin error. */
    }
}

使用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的扫描集(可能不常见,易于理解)

/*
 * 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不同,甚至可能三个都是单独的情况。例如,通过将上述代码段中的一个放入自包含函数中,如果读取了0,则可能会返回\n或者在EOF /错误时返回EOF,甚至0\n上,EOF在EOF上,1出错。

值得注意的事情:

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

答案 1 :(得分:0)

您可以使用:

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

答案 2 :(得分:0)

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

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

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

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