I have very frequently seen people discouraging others from using scanf
and saying that there are better alternatives. However, all I end up seeing is either "don't use scanf
" or "here's a correct format string", and never any examples of the "better alternatives" mentioned.
For example, let's take this snippet of code:
scanf("%c", &c);
This reads the whitespace that was left in the input stream after the last conversion. The usual suggested solution to this is to use:
scanf(" %c", &c);
or to not use scanf
.
Since scanf
is bad, what are some ANSI C options for converting input formats that scanf
can usually handle (such as integers, floating-point numbers, and strings) without using scanf
?
The most common ways of reading input are:
using fgets
with a fixed size, which is what is usually suggested, and
using fgetc
, which may be useful if you're only reading a single char
.
To convert the input, there are a variety of functions that you can use:
strtoll
, to convert a string into an integer
strtof
/d
/ld
, to convert a string into a floating-point number
sscanf
, which is not as bad as simply using scanf
, although it does have most of the downfalls mentioned below
There are no good ways to parse a delimiter-separated input in plain ANSI C. Either use strtok_r
from POSIX or strtok
, which is not thread-safe. You could also roll your own thread-safe variant using strcspn
and strspn
, as strtok_r
doesn't involve any special OS support.
It may be overkill, but you can use lexers and parsers (flex
and bison
being the most common examples).
No conversion, simply just use the string
Since I didn't go into exactly why scanf
is bad in my question, I'll elaborate:
With the conversion specifiers %[...]
and %c
, scanf
does not eat up whitespace. This is apparently not widely known, as evidenced by the many duplicates of this question.
There is some confusion about when to use the unary &
operator when referring to scanf
's arguments (specifically with strings).
It's very easy to ignore the return value from scanf
. This could easily cause undefined behavior from reading an uninitialized variable.
It's very easy to forget to prevent buffer overflow in scanf
. scanf("%s", str)
is just as bad as, if not worse than, gets
.
You cannot detect overflow when converting integers with scanf
. In fact, overflow causes undefined behavior in these functions.