Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Since the Standard C committee did not standardize a simple replacement for gets(), what should it be?

The gets function was first deprecated in C99 and finally removed in C11. Yet there is no direct replacement for it in the C library.

fgets() is not a drop-in replacement because it does not strip the final '\n', which may be absent at the end of file. Many programmers get it wrong too.

There is a one-liner to remove the linefeed: buf[strcspn(buf, "\n")] = '\0';, but it is non-trivial and often calls for an explanation. It may be inefficient as well.

This is counter-productive. Many beginners still use gets() because their teachers are lame or their tutorials obsolete.

Microsoft proposed gets_s() and many related functions, but it does not silently truncate overlong lines, the behavior on this constraint violation is not exactly simple.

Both BSD and the GNU libc have getline, standardized in POSIX, that allocates or reallocates a buffer via realloc...

What is the best way to teach beginners about this mess?

like image 469
chqrlie Avatar asked Dec 01 '15 22:12

chqrlie


People also ask

What to use instead of gets () in C?

To avoid Buffer Overflow, fgets() should be used instead of gets() as fgets() makes sure that not more than MAX_LIMIT characters are read.

Why was the gets () function removed from the library?

So: gets is fundamentally unsafe. It's not just that it can be misused (the way, say, strcpy or C++'s std::copy can be misused); it's that it cannot be used at all without giving the user control over your process. Therefore, the function gets was removed from the C standard library in 2011. The C11 version of <stdio.

Why gets () must be used with care?

gets() is dangerous because it is possible for the user to crash the program by typing too much into the prompt.

Why you should not use gets in C?

However, gets() is inherently unsafe, because it copies all input from STDIN to the buffer without checking size. This allows the user to provide a string that is larger than the buffer size, resulting in an overflow condition. Ban the use of dangerous functions. Use their safe equivalent.


2 Answers

The nature of the question is such that there's going to be speculations and opinions. But we could find some information from the C99 rationale and C11 standard.

The C99 rationale, when gets() was deprecated, states the following reason for the deprecating it:

Because gets does not check for buffer overrun, it is generally unsafe to use when its input is not under the programmer’s control. This has caused some to question whether it should appear in the Standard at all. The Committee decided that gets was useful and convenient in those special circumstances when the programmer does have adequate control over the input, and as longstanding existing practice, it needed a standard specification. In general, however, the preferred function is fgets (see §7.19.7.2).

I don't think gets_s() can be considered as an alternative either. Because gets_s() is an optional interface. C11 actually recommends fgets() over gets_s():

§K.3.5.4.1, C11 draft

The fgets function allows properly-written programs to safely process input lines too long to store in the result array. In general this requires that callers of fgets pay attention to the presence or absence of a new-line character in the result array. Consider using fgets (along with any needed processing based on new-line characters) instead of gets_s.

So that leaves us with fgets() as the only real replacement for gets() in ISO C. fgets() is equivalent to gets() except it would read in the newline if there's buffer space. So is it worth introducing a new interface that has a minor improvement over a longstanding and widely used (fgets()) one? IMO, no.

Besides, a lot of real world applications are not restricted to ISO C alone. So there's an opportunity to use extensions and POSIX getline() etc as a replacement.

If it becomes necessary to find write a solution within ISO C, then it's quite easy to write a wrapper around fgets() anyway such as my_fgets() that would remove the newline, if present.

Of course, teaching fgets() to newcomers involves explaining about the potential newline issue. But IMO, it's not that hard to understand and someone intending to do learn C should be able to grasp it quickly. It (finding the last character and replace it if it's character "X") could even be considered as a good exercise for a beginner.

So in light of the above stated reasons, I would say there's no overwhelming necessity for a new function in ISO C as a true replacement for gets().

like image 185
P.P Avatar answered Oct 27 '22 00:10

P.P


This question largely calls for speculation short of a citation from committee minutes or something, but as a general principle, the committee (WG14) generally avoids inventing new interfaces and prefers to document and make rigorous existing practice (things like snprintf, long long, the inttypes.h types, etc.) and sometimes adopt from other standards/interface definitions outside of C (e.g. complex math from IEEE floating point, atomic model from C++, etc.). gets has no such replacement to adopt, probably because fgets is generally considered superior (it's non-lossy when the file ends without a newline). If you really want a direct replacement, something like this works:

char buf[100];
scanf("%99[^\n]%*1[\n]", buf);

Of course it's klunky to use, especially when the buffer size is variable.

like image 35
R.. GitHub STOP HELPING ICE Avatar answered Oct 27 '22 01:10

R.. GitHub STOP HELPING ICE