scanf has a number of problems, its %s format has the same problem that gets() has
--it's hard to guarantee that the receiving buffer won't overflow.
More generally, scanf is designed for relatively structured, formatted input (its
name is in fact derived from ``scan formatted''). If you pay attention,
it will tell you whether it succeeded or failed, but it can tell you only approximately
where it failed, and not at all how or why. You have very little opportunity to
do any error recovery.
Yet interactive user input is the least structured input there is. A well-designed
user interface will allow for the possibility of the user typing just about anything--not
just letters or punctuation when digits were expected, but also more or fewer characters
than were expected, or no characters at all (i.e. just the RETURN key), or premature
EOF, or anything. It's nearly impossible to deal gracefully with all of these
potential problems when using scanf; it's far easier to read entire lines (with
fgets or the like), then interpret them, either using sscanf or some other techniques.
(Functions like strtol, strtok, and atoi are often useful; If you do use any scanf
variant, be sure to check the return value to make sure that the expected number
of items were found. Also, if you use %s, be sure to guard against buffer overflow.