How can I fix the scanf to take data into the array?

[Answer adapted from a now-deleted former question.]

scanf seems like a nice, simple, easy, convenient way to read input. And in some ways it is, but it turns out that using it correctly can be surprisingly difficult, and it’s chock-full of pitfalls.

You’re probably not going to want to learn about all of scanf‘s intricacies at first. So for now, here are some guidelines for using a subset of scanf‘s functionality, safely. (For reasons I fail to understand, everybody tells beginners to use scanf, but nobody ever teaches rules like these along with it.)

  1. Remember to always use & in front of the variables you’re trying to read. (This is a special rule, for scanf only. Don’t try to use that & on the variables you pass to printf, for example.)
  2. Exception to rule 1: Do not use the & when you are reading strings with %s.
  3. If you are reading strings using %s, make sure the variable you read into is either a character array that’s big enough for what the user is likely to type, or a pointer to malloc‘ed memory that’s big enough for what the user is likely to type. (See also note below about avoiding overflow.)
  4. Be aware that %s reads strings that don’t contain space characters. You can’t use %s to read strings (like full names) that might contain spaces. (For now, please don’t worry about how you might read a string that might contain spaces. See also rule 14.)
  5. Don’t try to use scanf and fgets together in the same program.
  6. Don’t try to use scanf and getchar together in the same program.
  7. Try to limit yourself to only the format specifiers %d, %s, %f, and %lf, to read into variables of type int, string (see rule 3), float, and double, respectively.
  8. If you want to read a character into a variable of type char, you can use " %c", but the mysterious extra explicit space character there is vital.
  9. Use only one % sign in the format string, to read one variable. Don’t try to read two or more variables in one scanf call.
  10. Always check scanf‘s return value. If it returns 0, or the negative value EOF, that means it didn’t successfully read anything. If it returns 1, that means it successfully read one value. (And if you break rule 9, and try to read multiple values, it’ll return the number of values it did successfully read, anywhere between 0 and the number you asked for.)
  11. If scanf returns 0 or EOF, indicating that the user did not type a valid value, just print an error message and exit. Don’t try to write code that asks the user to try again, because the user’s wrong input is still sitting on the input stream, and there’s no good, simple way to get rid of it. (If you really want to write user-friendly code that re-prompts in case of error, scanf is not the right tool for the job.)
  12. Never put whitespace after the format string. That includes the newline character \n. (That is, use "%d", not "%d " or "%d\n".)
  13. Don’t try to use the %[…] specifier.
  14. If you break rule 13 (perhaps because someone told you that %[…] might be a way to read a string containing spaces, or a whole line), do not put an s after it. The format is %[…], not %[…]s.

These rules may seem restrictive, but if you follow these rules, you should be able to simply and easily and reliably get simple inputs into your simple programs, which is the goal here. scanf is otherwise remarkably hard to use, and experience has shown that there are something like 17 different horribly frustrating problems that tend to come up, and trying to solve them is a completely unnecessary distraction from your goal of learning C by writing simple C programs.

When you’re reading strings with %s or %[…], there’s a danger: no matter how big the array or malloc‘ed buffer you’re reading into is, the user might type more than that. To avoid overflow, you can use a format like %19s to explicitly tell scanf how many characters it’s allowed to read. (And remember to subtract 1, to leave room for the terminating '\0'. That is, you’d use %19s to read into char str[20]; or char *p = malloc(20);.)

These rules are somewhat numerous. For a simpler set of rules, see this answer. Putting rules 7, 8, 9, 12, and 13 together, there are really only five complete format strings you want to use with scanf: "%d", "%s", "%f", "%lf", or " %c". (But no commas, no fixed strings, no whitespace other than the explicit space in " %c", nothing else.) Exception: as mentioned above, it’s fine to use something like %19s to limit the length of a string being read.

If you need to do something more complicated, that you can’t do while staying within these rules, it’s time to either:

  1. Learn enough about how scanf really works (and doesn’t work) so that you can try to do the thing you want, but without getting stuck on one of those 17 problems, or
  2. Learn how to do input using better and more powerful methods than scanf, perhaps by reading whole lines using fgets and then parsing them.

Leave a Comment