Can cause buffer overruns
scanf and fscanf are dangerous functions if misused when reading strings, because they are prone to buffer overruns.
Buffer overruns leads to undefined behavior and causes both security risks and serious bugs in applications.
To learn more about buffers overruns, see buffer overrun.
It is strongly advised to read about undefined behavior to fully understand why it is important not to create buffer overruns.
To solve buffer overruns, the size of the buffer passed to scanf/fscanf must be passed to avoid the functions reading more data than there is room for.
However, these functions do not take an argument specifying the buffer size, so it must be done explicitly in the arguments you pass indicating what type of input is trying to be read.
The correct way to call scanf/fscanf, when reading strings, is:
scanf("%BufferSizeHere - 1s", ...);
Doing that will pass along the size of the buffer to the function (or rather tell it how many chars to read maximum), so that buffers overruns won't occur.
Note that the size passed to scanf must be size of buffer - 1. So if the size of the buffer is 10, 9 should be passed to scanf. This is to accommodate for the null char ('\0').
This may not always yield the result the programmer wants, but it is better than undefined behavior which occurs if and when there is a buffer overrun.
Another solution is to use fgets. fgets takes among other arguments an argument that takes the size of the buffer, preventing buffers overruns.
scanf and fscanf also stops reading at the first blank space, so if a user inputs something like "Hello World" (which will be stored as "Hello World\n" [\n is a newline character] in the input) - it will only read "Hello ", leaving the rest - "Hello\n" in the input buffer, which will be read on a subsequent call to read some input from the user or from the file, leading to undesired behavior.
One solution is to tell scanf to actually read spaces, as well. This is done via format list, like so:
char buffer; scanf("%99[^\n]", buffer);
(Again, do not forget to pass the size of the buffer to avoid the problem mentioned above.)
The code will read up until it finds a new line character ('\n'), the same as fgets solution (see below).
Another solution is to use fgets. fgets does not suffer from reading only one word. It reads entire lines at once, which makes it a robust alternative. However, one must remember that fgets also stores the '\n' (the newline) in the buffer, which usually needs to be stripped before use. An example of fgets:
char buffer; fgets(buffer, sizeof(buffer), stdin);
To get rid of the unwanted newline, the following code can be used:
buffer[strlen(buffer) - 1] = '\0';
The advantage of using fgets over scanf is that the size does not need to be hardcoded. A simple sizeof can be used with fgets, and the compiler will automatically pass the correct size of the buffer, even if the size of the buffer is changed sometime in the future.
fgets also takes into mind the null char ('\0'), so the entire size of the buffer should be passed, unlike the scanf solution (see above).
Leaves data in input buffer
scanf and fscanf can leave data in the input buffer if it tries to read non-string type data (such as int). It does this because it cannot convert the newline character (\n) to a non-string type data (again, such as int).
For more information, see Leaves data in input buffer.