SungJin Park
SungJin Park

Reputation: 51

Difference between %d and %c when using scanf funcion and input 'enter' in C

I have question about %d and %c and 'enter' in C language.

Example code is very simple:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main(void) {
    int i;
    scanf("%d", &i);
    printf("%d", i);
    return 0;
}

input [enter space 3] -> output [3]

%d doesn't get enter or space.

But when input [q enter] -> output is trash value.

Why just 'enter' doesn't exit program unlike %c?

Upvotes: 1

Views: 582

Answers (6)

Steve Summit
Steve Summit

Reputation: 47925

As you've noticed, the behavior of %d and %c is quite different. We know that %d is for entering integers, and %c is for entering characters. But besides that, there are other, more subtle but perhaps more interesting differences.

Depending on how you count, scanf with %d does something like six sifferent things:

  1. Skip over any "whitespace" characters it finds on the input stream (basically: space, tab, newline, and a few others).
  2. Look for a sequence of digit characters (possibly preceded by + or -) coming up next on the input stream.
  3. If it finds them, convert those digits to an integer.
  4. If it finds them (and unless instructed not to), store the converted integer into the user-supplied variable (in your case, i).
  5. (important) if there were no digit characters, or if the digit characters were followed by some non-digit characters, leave the non-digit characters on the input stream, ready for some other input function to read later.
  6. Return 1 if there were digit characters to convert, 0 if there were no digit characters to convert, or EOF if an end-of-fie or error condition was encountered while reading.

But by contrast, what %c does is much, much simpler. Basically it is:

  1. Look for one character (any character) coming up next on the input stream.
  2. If it finds one (and unless instructed not to), store the character into the user-supplied variable.
  3. Return 1 if there was a character to store, or EOF if an end-of-fie or error condition was encountered while reading.

Notice that %c does not skip leading whitespace characters before reading. If the next character available on the input stream is a whitespace character, %c will read and return it.

Also, %c will read and return any character. It's not fussy. It doesn't limit itself to just digit characters like %d does. If there's an input character at all, %c will read it. I think it ends up being impossible for %c to return 0 if it couldn't read a character, because the only condition under which it wouldn't be able to is end-of-file, and that returns EOF.

So, to your questions:

input [enter space 3] -> output [3]
%d doesn't get enter or space.

More precisely, %d is willing to skip over those whitespace characters, looking for a digit like 3, which it is then able to successfully convert and return.

But when input [q enter] -> output is trash value.

More precisely, scanf fails to convert as requested, so it fills nothing into i, but in this case it will also have returned 0, which is supposed to alert you the fact that scanf failed to convert, and that you need to be careful, because no new value has been stored into i.

You need to check for this yourself, by doing something like

if(scanf("%d", &i) != 1) {
    fprintf(stderr, "failed to read integer\n");
    exit(1);
}
/* ... rest of program ... */

Why just 'enter' doesn't exit program unlike %c?

Im not sure what you mean by "just exit program". No correctly-written call to scanf should cause your program to exit. Maybe you can show your code, or explain, what caused your program to exit.

As I said earlier, there is a difference between %c and %d in terms of what they accept as "correct" input, and whether or not they're willing to automatically skip leading whitespace.

Upvotes: 0

anastaciu
anastaciu

Reputation: 23792

input [enter space 3] -> output [3] ... %d doesn't get enter or space

The %d specifier is for integers, other inputed characters will not be read by scanf and will remain in the buffer. Whitespace characters and conditionally '-', '+' will be ignored and discarded, scanf will keep waiting for the expected input in this case.


But when input [q enter] -> output is trash value

As stated, any non digit characters, with the exception of the described above, will not be read by scanf and will remain in the buffer, i will remain uninitialized. What normaly happens is that the value previously stored in i, which will be any garbage value stored in the memory where i now lives, will be printed. However, the behavior of passing uninitialized variables to printf is undefined.


Why just 'enter' doesn't exit program unlike %c?

scanf with %c specifier has a different behavior it will read exactly one character and will store it in i, enter is a non printable control character so scanf will read it and store it in i, in fact you will note that printf with %d will print 10 (for ASCII encoding), which is the ASCII code for line feed, aka new line character.

With the %d specifier, as stated before, scanf will ignore and discard white space characters, it will keep waiting for an input until you input a non white space character.

Upvotes: 2

Clifford
Clifford

Reputation: 93456

Because Enter inserts a character ('\n') into the stream. The %c format specifier matches any character including \n, but it is not a decimal digit so in your example i remains unassigned (and the newline remains buffered).

If you have %c thus: char c = 0 ; scanf("%c", &c); printf("%c", c);

and press Enter it does not "just exit", as you suggest- it outputs a blank newline. If you entered multiple spaces and newline, the first space would be assigned to c and printed. The rest would remain buffered. This output is of course largely invisible. In the first instance you would that an extra blank line, which you might only notice by the position of any following output.

Note that scanf() returns the number of formatters validly matched, so for:

int x = scanf("%d", &i);

x will be zero, if you simply press Enter and i will be undefined (in practice it would likely be unchanged, but that is not defined behaviour), but for:

char c ;
int x = scanf("%c", &c);

x will have value 1, while c will contain a newline character \n (typically ASCII LF - value 10).

Upvotes: 0

Clifford
Clifford

Reputation: 93456

Because Enter inserts a <newline> character ('\n') into the stream. The %c format specifier matches any character including '\n', but it is not a decimal digit so in your example i remains unassigned (and the newline remains buffered) because it does not match the %d format specifier.

Upvotes: 0

Eric Postpischil
Eric Postpischil

Reputation: 222302

Why just 'enter' doesn't exit program unlike %c?

With %d, scanf reads characters from input while expecting them to match the following in order:

  • Zero or more white-space characters (which may include the new-line character).
  • An optional “+” or “-” sign character.
  • One or more digit characters, from “0” to “9”.

scanf stops reading for %d when it reads a character that does not match the expected sequence (and the non-matching character is left in the stream). When you press the Enter key, a new-line character is generated in the stream, and scanf reads it. Since it is a white-space character at a time when scanf expects it, scanf continues reading. So the program does not stop; scanf continues waiting for more input.

In contrast, with a %c conversion, scanf does not expect white-space characters before the character to be read. It reads exactly one character and stores it. %d allows initial white-space in what it matches, but %c does not.

But when input [q enter] -> output is trash value.

When you press the Q key (and then Enter), scanf reads “q”. Since it does not expect a “q” at this time, it stops reading. Then it returns to your main routine. Since scanf did not read any digit characters, it did not make a conversion and assign a value to i. So i remains uninitialized.

Upvotes: 1

Yun
Yun

Reputation: 3812

The behavior of scanf can be read here. The function skips leading whitespace for %d, but not for %c:

All conversion specifiers other than [, c, and n consume and discard all leading whitespace characters (determined as if by calling isspace) before attempting to parse the input.

When the character q is input while scanf is looking for a digit, it doesn't find one and hence doesn't set the value pointed to. The value pointed to will be indeterminate.

When not entering a number, %d will look for one and not initialize the value pointed to, whereas %c will read the newline character (i.e. \n, or decimal integer value 10).

Upvotes: 1

Related Questions