alternative can I use instead of gets()
char str[MAX_SIZE]; gets()
has problems when reading a line of N
characters. (N
also counts the '\n'
).
When N > MAX_SIZE
, the result is undefined behavior (UB). Too much input and no place to go. Often this UB writes into places used by other objects. Bad - very bad.
C11 eliminated gets()
and is not a standard function since then.
The usual fgets()
solution is well suggested by @Stephan Lechner. fgets()
has some short comings listed below.
str[MAX_SIZE]
now needs to be str[MAX_SIZE + 1]
as fgets()
also saves the '\n'
, unlike gets()
. Sometimes adding + 1 is not practical.
fgets()
retains the potential '\n'
. See Removing trailing newline character from fgets()
When input is excessive, fgets()
simply does not read it, unlike gets()
. This is well behaved (not UB) yet we are still stuck with that problem: how to detect excessive input and what to do about it?
If code can live with these, use fgets()
. Otherwise, read on.
mygets()
alternative
This function does not need a +1 to the size of the s
buffer.
Excessively long input returns NULL
. All the line is read. The s
buffer is filled with the initial characters.
char *mygets(char *s, size_t n) {
char *dest = s;
// Pathological case of n==0
char dummy[1];
if (n == 0) {
n = sizeof dummy;
dest = dummy;
}
size_t i = 0;
int ch;
n--;
while ((ch = fgetc(stdin)) != '\n' && ch != EOF) {
if (i < n) {
dest[i++] = (char) ch;
} else {
s = NULL; // Not enough room
}
}
if (ch == EOF) {
if (feof(stdin)) { // end-of-file
if (i == 0) {
s = NULL;
}
} else { // input error
i = 0;
s = NULL;
}
}
dest[i] = '\0';
return s;
}
Subtle bonuses:
s
buffer is well defined on rare input error. With gets/fgets
buffer contents are then undefined.
Pathological size of 0 is well defined. fgets()
is a bit iffy on that.
Buffer size is the idiomatic size_t
rather than int
as with fgets()
.
Usage
str[MAX_SIZE];
if (mygets(str, sizeof str)) {
printf("Success <%s>\n", str);
} else {
if (feof(str)) printf("End of file detected. <%s>\n", str);
else if (ferror(str)) printf("End of file detected. <%s>\n", str);
else printf("Input too long <%s>.", str);
}