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:

  1. scanf read Character0
  2. scanf skipped Character1
  3. scanf read Character2
  4. 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.

  1. Character0: is printed out.
  2. The scanf function started to wait for a key hit since the buffer is empty.
  3. The 'a' character is hit with a following \n (enter) key.
  4. At this moment, in the buffer there are 'a' and \n characters respectively; 'a' being at the first index.
  5. The scanf stores the 'a' to the character0 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.
  6. Character1: is printed out.
  7. When the second scanf is executed, it consumes the \n character off of the buffer and then stores it into the character1 variable since its formatter is also %c. After all, the \n is an ASC2 character as well. This is what makes us think that the scanf is broken.
  8. Character2: is printed out.
  9. The third scanf is executed but entered into the waiting state since the input buffer is empty.
  10. 'b' character is hit with a following \n key.
  11. The third scanf consumed the 'b' character off of the buffer and again, the \n character remains in the buffer.
  12. When the forth scanf is executed, it consumes the \n character and stores it into the character3 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 🫡🙋🏻‍.

comments powered by Disqus

Translations: