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 th
getchar
(common, easily comprehensible)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
(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 '\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
(likely uncommon, easily comprehensible)/*
* 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
(likely uncommon, difficult)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);
Of course, all of these methods assume you want to handle things that happen on EOF/error differently than with \n
, 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 \n
was read or EOF
on EOF/error, or even 0
on \n
, EOF
on EOF, and 1
on error.
Things worth noting:
getchar
and fgets
methods are 100% cross-platform. I prefer the getchar
method for its simplicity.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).You can use:
fscanf(stdin, "%*[^\n]%*c");
There's a few ways of doing this. Effectively, what you're trying to do is consume a line of text up to a \n character (or an EOF.) To do this properly, you should use sscanf (or fscanf.)
sscanf("%*[^\n]\n");
This uses the regular expression [^\n]*\n (Any number of characters that are NOT \n, followed by a \n) and consumes everything matching that.
Edit: Because I'm dumb and forgot that scanf regex's use a slightly different syntax.