Character Reading Problem with scanf() in C
If you encountered this article and you are reading it, you are most likely
dealing with the same problem. You're doing a practice or an application
with C, where you need to get input from the keyboard successively, whoops, you
suddenly realize that you couldn't read some of the entries, some of the
variables just contains an unexpected \n
(new line) character.
So now what?
Let's illustrate the problem with an example snippet of code:
1#include <stdio.h>
2
3int main() {
4 char character0;
5 char character1;
6 char character2;
7 char character3;
8
9 printf("Character0: ");
10 scanf("%c", &character0);
11
12 printf("Character1: ");
13 scanf("%c", &character1);
14
15 printf("Character2: ");
16 scanf("%c", &character2);
17
18 printf("Character3: ");
19 scanf("%c", &character3);
20
21 putchar('\n');
22
23 printf("Characteres entered:\n");
24 printf("Character0: %c\n", character0);
25 printf("Character1: %c\n", character1);
26 printf("Character2: %c\n", character2);
27 printf("Character3: %c\n", character3);
28
29 return 0;
30}
If you compile the above code, you will see something like the following in the output:
1Character0: a
2Character1: Character2: b
3Character3:
4Characteres entered:
5Character0: a
6Character1:
7
8Character2: b
9Character3:
10
11 .
When we look at the output, we can see that the first entry is read, the second
entry however, looks like as if it skipped. The same thing happens for the
third and fourth entries. We see the result more clearly when we print the
entered characters for each variable, notice the empty lines after the
Character1:
and Character3:
. If we interpret what we saw in the output from
our point of view:
- scanf read Character0
- scanf skipped Character1
- scanf read Character2
- scanf skipped Character3
Does the scanf
function have a bug?, is it malfunctioning. Well, no.
It is not a bug of the scanf
, it just does what it is supposed to do.
It is worth to mention by the way that this problem does not occur when the
numeric formatters like %d and %f are used, but only the character
formatters like %c and %s are used (at least as far as I know).
Let's briefly take a look at how the scanf
function reads (according
to the format we instruct) the input from a keyboard before we dive into
analyzing the behaviour.
When a key is hit on the keyboard, the characters are buffered into a unsigned
character buffer of a special type called FILE. In most systems this file is
called standard input (stdin
). The scanf
function reads the characters from
this stream one by one, until it satisfies the requirements of the given format.
With this in mind, let's get back our code example, and analyze step by step
what happened when the scanf
lines are executed.
Character0:
is printed out.- The
scanf
function started to wait for a key hit since the buffer is empty. - The 'a' character is hit with a following
\n
(enter) key. - At this moment, in the buffer there are 'a' and
\n
characters respectively; 'a' being at the first index. - The
scanf
stores the 'a' to thecharacter0
variable since it reads the buffer with the %c formatter, hence the 'a' has been consumed off of the buffer. Now the buffer only contains the\n
character at this point. Character1:
is printed out.- When the second
scanf
is executed, it consumes the\n
character off of the buffer and then stores it into thecharacter1
variable since its formatter is also %c. After all, the\n
is an ASC2 character as well. This is what makes us think that thescanf
is broken. Character2:
is printed out.- The third
scanf
is executed but entered into the waiting state since the input buffer is empty. - 'b' character is hit with a following
\n
key. - The third
scanf
consumed the 'b' character off of the buffer and again, the\n
character remains in the buffer. - When the forth
scanf
is executed, it consumes the\n
character and stores it into thecharacter3
variable.
This situation is not unique to the scanf
. It applies all the functions like
getchar
, gets
etc. that read characters from the standard input. So why
does this problem occur when reading in characters but not when reading in
numerical format? This is because the numeric formatters like %d
, consumes
the \n
and \s
(white spaces) automatically. Therefore, no matter how many
consecutive readings are made with scanf
or similar, the problem with
character formatters does not occur.
Great, now we understand the reason behind that behaviour of the scanf
. But
being understood is not enough to overcome the problem, we need to overcome
this problem, but how? Well, actually the answer to this question is already in
the expalanations above. What was the problem? It was the \n
character that
remains in the buffer and get consumed by the next consumer (scanf
).
So either we will consume it manually before the next scanf
gets executed,
or somehow, we make it to be ignored using a formatting trick.
The Solution
Let's compile end execute our solution code and then go through it.
1#include <stdio.h>
2
3int main() {
4 char character0;
5 char character1;
6 char character2;
7 char character3;
8
9 printf("Character0: ");
10 scanf("%c", &character0);
11
12 while ((getchar()) != '\n'); // Solution 1
13 printf("Character1: ");
14 scanf("%c", &character1);
15
16 printf("Character2: ");
17 scanf(" %c", &character2); // Solution 2
18
19 printf("Character3: ");
20 scanf(" %c", &character3);
21
22 putchar('\n');
23
24 printf("Characteres entered:\n");
25 printf("Character0: %c\n", character0);
26 printf("Character1: %c\n", character1);
27 printf("Character2: %c\n", character2);
28 printf("Character3: %c\n", character3);
29
30 return 0;
31}
The output of the solution code:
1Character0: a
2Character1: b
3Character2: c
4Character3: d
5
6Characteres entered:
7Character0: a
8Character1: b
9Character2: c
10Character3: d
This time we've got what we want according to the output, we did assigned the
four characters to their variables without skipping any. You can see two
different methods for the solution in the above code. As a matter of fact,
they both do the same thing, which is consuming the unwanted \n
characters.
1while ((getchar()) != '\n'); // Solution 1
In this solution, the program keeps looping until all \n
characters are
consumed.
1scanf(" %c", &character2); // Solution 2
In this one, a formatting trick is doing the job. If you've noted, there is a
space before the %c
formatter. This space will consume the previous \n
character which left in the buffer, and will consume it too, by load the main
character into the character2
variable as expected.
But remember that when we hit the Enter key following the character, there
will still be a \n
character waiting to be consumed in the buffer.
Therefore, it is the programmers' responsibility to handle this situation when
using the standard reading functions like getchar
that read from the stdin
buffer.
Well that's all for this matter. Do you have different methods or suggestions to solve this problem? Why not leave it in a comment? Happy coding to everyone and I will see you the next time 🫡🙋🏻.