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).
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…