What can I use for input conversion instead of scanf?

S.S. Anne picture S.S. Anne · Oct 16, 2019 · Viewed 11.9k times · Source

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?

Answer

S.S. Anne picture S.S. Anne · Oct 16, 2019

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.