I am aware that there are numerous posts about why the trailing newline character problem occurs and how to fix it. However, of all the solutions out there, the use scanf(" %c", ch)
method is the most common one. Yet no one discusses why it works! What does the extra whitespace do differently in this case?
CodePudding user response:
Here is the explanation from the C Standard:
7.22.6.2 The
fscanf
functionSynopsis
#include <stdio.h> int fscanf(FILE * restrict stream, const char * restrict format, ...);
Description
2 The fscanf function reads input from the stream pointed to by
stream
, under control of the string pointed to byformat
that specifies the admissible input sequences and how they are to be converted for assignment, using subsequent arguments as pointers to the objects to receive the converted input. If there are insufficient arguments for the format, the behavior is undefined. If the format is exhausted while arguments remain, the excess arguments are evaluated (as always) but are otherwise ignored.3 The format shall be a multibyte character sequence, beginning and ending in its initial shift state. The format is composed of zero or more directives: one or more white-space characters, an ordinary multibyte character (neither
%
nor a white-space character), or a conversion specification. Each conversion specification is introduced by the character%
. After the%
, the following appear in sequence: [...]4 The
fscanf
function executes each directive of the format in turn. When all directives have been executed, or if a directive fails (as detailed below), the function returns. Failures are described as input failures (due to the occurrence of an encoding error or the unavailability of input characters), or matching failures (due to inappropriate input).5 A directive composed of white-space character(s) is executed by reading input up to the first non-white-space character (which remains unread), or until no more characters can be read. The directive never fails.
Hence the initial space in " %c"
consumes any pending whitespace characters in the input stream, including the newline left pending from a previous call to scanf
. Note that "\n%c"
would behave exactly the same way and would be just as confusing as unsuspecting readers might expect scanf()
to require a newline to be read and no other characters.
An alternative approach to ensure only a pending newline is consumed is this format: "%*1[\n]%c"
. scanf
will return 0
if the character pending in stdin
is not a newline, and this format allows for a whitespace character to be retrieved from the user such as ' '
and '\t'
. If the user hits the Enter key immediately, scanf
will get the newline character '\n'
into the char
variable destination of the %c
conversion, but there will be no pending newline in stdin
after scanf()
returns.
In spite of these considerations, it is recommended to read input from the user one line at a time with fgets()
and parse it with appropriate functions, sscanf()
or other more reliable functions such as strtol()
that provide better error detection.