Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.0k views
in Technique[技术] by (71.8m points)

c - Good way to flush scanf buffer when invalid entry entered

I have been thinking of ways to flush bad entries in scanf functions to allow for loop prompts to do their job.

I have a function call here that flushes the input. This works but it's still buggy if I enter something like 2q when I ask for an int.

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

And then I'll have something like this in another function:

printf("Enter a value: ");
check = scanf("%f", &b);

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

Any better ideas? Someone suggested fflush(); but it's not really standard to use that here..

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Using getchar (common, easily comprehensible)

int c;

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

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

Using fgets (less common, less comprehensible)

char buf[8];

while (fgets(buf, sizeof buf, stdin) != NULL) {
    size_t len = strlen(buf);

    /*
     * Exit the loop if either EOF was encountered before '
', or
     * if '
' is detected.
     */
    if (len + 1 != sizeof(buf) || memchr(buf, '
', len))
        break;
}
    
if (feof(stdin)) {
    /* Handle stdin EOF. */
}
else {
    /* Handle stdin error. */
}

Using a scanset with scanf (likely uncommon, easily comprehensible)

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

Using getline (likely uncommon, difficult)

char *buf = NULL;
size_t bufsize = 0;
ssize_t len;

/* getline() will stop reading on '
' 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);

Of course, all of these methods assume you want to handle things that happen on EOF/error differently than with , perhaps even all three being separate cases. For example, by placing one of the above snippets into a self-contained function, you might return 0 if was read or EOF on EOF/error, or even 0 on , EOF on EOF, and 1 on error.

Things worth noting:

  • The getchar and fgets methods are 100% cross-platform. I prefer the getchar method for its simplicity.
  • The scanset method is less cross-platform only because not all compilers implement scansets (and are therefore not C99-compliant).
  • The getline method is also not quite cross-platform: it's primarily implemented on GNU/Linux and on some other POSIX operating systems; this does not include Windows at this time. It isn't terribly difficult to write one yourself once you have some experience managing memory and working with pointers, but you'd be better off using one of the first two methods since writing an implementation of getline would likely end up using fgetc or fgets anyway (fgetc(stdin) and getchar() should behave identically).

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...