2

I'm really confused about the usage of getchar() and scanf(). What's the difference between these two?

I know that scanf() [and family] get a character by character from the user [or file] and save it into a variable, but does it do that immediately or after pressing something (Enter)?

and I don't really understand this code, I saw many pieces of code using getchar() and they all let you type whatever you want on the screen and no response happen, but when you press enter it quits.

int j, ch;

printf("please enter a number : \n");

while (scanf("%i", &j) != 1) {
    while((ch = getchar()) != '\n') ;
    printf("enter an integer: ");
}

Here in this code can't I use scanf() to get a character by character and test it? Also, what does this line mean?

scanf("%i", &j) != 1

because when I pressed 1 it doesn't differ when I pressed 2? what does this piece do?

and when this line is gonna happen?

printf("enter an integer: ");

because it never happens.

Qantas 94 Heavy
  • 15,750
  • 31
  • 68
  • 83
Salahuddin
  • 1,617
  • 3
  • 23
  • 37

6 Answers6

4

Well, scanf is a versatile utility function which can read many types of data, based on the format string, while getchar() only reads one character.

Basically,

char someCharacter = getchar();

is equivalent to

char someCharacter;
scanf("%c", &someCharacter);

I am not 100% sure, but if you only need to read one character, getchar() might be 'cheaper' than scanf(), as the overhead of processing the format string does not exist (this could count to something if you read many characters, like in a huge for loop).

For the second question.

This code:

scanf("%i", &j) != 1

means you want scanf to read an integer in the variable 'j'. If read successfully, that is, the next input in the stream actually is an integer, scanf will return 1, as it correctly read and assigned 1 integer.

See the oldest answer to this SO question for more details on scanf return values.

Community
  • 1
  • 1
nestedloop
  • 2,596
  • 23
  • 34
  • "If read successfully, that is, the next input in the stream actually is an integer, scanf will return 1" here is a question, I read that scanf() returns the number of character it read, and not if it read integer return 1, I tried it and it really happened that when entered an integer, it returned 1 and when I entered a character "string" returned 0. so how it returns the number of characters it read? I'm confused – Salahuddin Jan 07 '14 at 12:11
  • @Salahuddin It returns "the number of input items successfully matched and assigned", whatever they are. Say this call receives correct input: scanf("%i%c%s", &someInt, &someChar, &someString), it will return 3. – nestedloop Jan 07 '14 at 12:13
  • @nestedloop `getchar()` returns `int` not `char`. How should we known otherwise when EOF is encountered. – hetepeperfan Jan 07 '14 at 12:15
  • @hetepeperfan Yes, getchar() returns an unsigned char converted to an int, unless EOF occurs. But then, I was talking about what scanf returns, not getchar. – nestedloop Jan 07 '14 at 12:17
  • @nestedloop I think code examples in an answer should promote good style and prevent errors. The `char c = getchar();` does not promote good style in my opinion. – hetepeperfan Jan 07 '14 at 12:20
  • @Salahuddin If you make a call like scanf("%i", &someInteger), it means scanf will expect to get an integer as input. If you enter a non-numeric string, it will not get its expected integer, therefore 0(zero) values will have been correctly read and assigned, so it will return 0(zero). – nestedloop Jan 07 '14 at 12:23
  • @hetepeperfan Edited. We exist only to serve (or please). – nestedloop Jan 07 '14 at 12:25
  • @nestedloop I may be here just to bother you, now I understood that the first while loop will not happen until I enter a string (not a number), OK so I entered a character (c for example) then pressed enter, now we are in the while loop meeting the second while loop which means (if you don't hit enter stay still and do nothing) right? so why when I didn't hit anything, the "enter an integer" string appear?? I think it hasn't to appear till I hit enter to get out of the second while loop, right? Please explain and be patient.. thanks – Salahuddin Jan 07 '14 at 12:35
  • @Salahuddin I can't know exactly what you entered, but that is indeed odd. I will try to reproduce this and come back if I find an explanation. In the mean time try again carefully. – nestedloop Jan 07 '14 at 12:46
  • @Salahuddin Did you not press 'enter' after you wrote the string? Cause from your code it is not necessary to hit enter twice. By this I mean you input some string "blahblah" then if you press enter that is taken into consideration, as you do getchar. Try to print something in the second loop, like the value of ch, see when it gets out of it. – nestedloop Jan 07 '14 at 12:51
  • @nestedloop yeah I pressed enter after printing the string, so it entered the first loop, starting executing the second while loop, so I think that I have to hit "enter" again to get out of the second while loop, right? – Salahuddin Jan 07 '14 at 12:54
  • @Salahuddin Did you put a printf in the second loop as I suggested earlier? Thing is... it might have entered the first loop when you FIRST pressed enter (after the integer), then you entered the string and pressed enter AGAIN, thus exiting the second loop. The first enter counts as well, and is not an integer for scanf. I think this is the answer to this new problem. – nestedloop Jan 07 '14 at 13:45
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/44710/discussion-between-salahuddin-and-nestedloop) – Salahuddin Jan 07 '14 at 13:59
3

As far as I understand, the getchar function will read your input one character at a time. scanf will read all types of data, and will be more useful to define a data group. However, as far as strings go, my teacher recommends using gets instead of scanf. This is because scanf will stop 'getting' the data at the first white space you put in, like in a sentence...

AnujaPL
  • 265
  • 1
  • 3
  • 10
3
while (scanf("%i", &j) != 1) {
    while((ch = getchar()) != '\n') ;
    printf("enter an integer: ");
}

Here's how this code breaks down.

  1. scanf() consumes individual characters from the input stream until it sees a character that does not match the %i conversion specifier1, and that non-matching character is left in the input stream;
  2. scanf() attempts to convert the input text into a value of the appropriate type; i.e., if you enter the string "1234\n", it will be converted to the integer value 1234, the converted value will be assigned to the variable j, and the '\n' will be left in the input stream;
  3. if there are no characters in the input string that match the conversion specifier (such as "abcd"), then no conversion is performed and nothing is assigned to j;
  4. scanf() returns the number of successful conversions and assignments.
  5. if the result of the scanf() call is not 1, then the user did not enter a valid integer string;
  6. since non-matching characters are left in the input stream, we need to remove them before we can try another scanf() call, so we use getchar() to consume characters until we see a newline, at which point we prompt the user to try again and perform the scanf() call again.


1. The %i conversion specifier skips over any leading whitespace and accepts optionally signed integer constants in octal, decimal, or hexadecimal formats. So it will accept strings of the form [+|-]{0x[0-9a-fA-F]+ | 0[0-7]+ | [1-9][0-9]*}
John Bode
  • 119,563
  • 19
  • 122
  • 198
2

The scanf can scan arbitrarily formatted data and parse it as multiple types (integers, floating point, strings, etc). The getchar function just gets a single character and returns it.

The expression

scanf("%i", &j) != 1

reads a (possibly signed) integer from the standard input, and stores it in the variable j. It then compares the return value of the scanf function (which returns the number of successfully scanned conversions) and compares it to 1. That means the expression will be "true" if scanf didn't read or converted an integer value. So the loop will continue to loop as long as scanf fails.

You might want to check this scanf reference.

That the printf doesn't happen might be either because it never happens (use a debugger to find out), or it just seemingly doesn't happen but it really does because the output needs to be flushed. Flushing output is done either by printing a newline, or with the fflush function:

fflush(stdout);
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • "the return value of the scanf function (which returns the number of successfully scanned conversions)" This didn't really happened with me, scanf() returned 1 when I entered integers, and 0 when I entered strings – Salahuddin Jan 07 '14 at 12:13
  • 1
    @Salahuddin And that's how it's supposed to work. When you entered an integer it successfully scanned and converted the integer you asked it to, so it returns `1` because it scanned and converted one item. When you entered a string it could not convert it to an integer, and so returned `0` as it scanned and converted zero items. – Some programmer dude Jan 07 '14 at 12:17
  • I'm sorry, but all what I know is that scanf() scans the input and save it in some place, so what do you mean with "converting", and "When you entered an integer it successfully scanned and converted the integer you asked it to", I didn't ask it to convert it to an integer – Salahuddin Jan 07 '14 at 12:22
  • 1
    @Salahuddin The `scanf` reads *text* (a sequence of characters) and *converts* it depending on the format code you give it. With the format `"%i"` you ask `scanf` to read text and convert it to an integer. – Some programmer dude Jan 07 '14 at 12:26
0

As far as I know, scanf will read user input until the first whitespace, considering the input format specified. getchar, however, reads only a single character.

scanf will return the number of arguments of the format list that were successfully read, as explained here. You obtain the same result when pressing 1 or 2 because both of them are successfully read by the %i format specifier.

Mauren
  • 1,955
  • 2
  • 18
  • 28
0

getchar reads one char at a time from input. where as scanf can read more depending upon the data type u specify.

its not good practice to use scanf() try using fgets(), its much more efficient and safe than scanf.

KARTHIK BHAT
  • 1,410
  • 13
  • 23
  • fgets() can only be used to read strings/lines. So for reading numbers fgets() is rather useless. For reading strings it is more effective to use than scanf(). – the_jk Jan 07 '14 at 11:42
  • @JoelKlinghed, `fgets` is definitely safer then using scanf when reading strings. For other datatypes it's useless, or you'd have to use `sscanf` afterwards. – Devolus Jan 07 '14 at 11:44
  • `scanf("%a")` is usually better than `fgets` but it is as non-standard as `getline()` that I would call the best. – the_jk Jan 07 '14 at 11:47
  • @Devolus, yeah I mixed up `gets()` and `fgets()` and fixed my comment before I saw your comment. – the_jk Jan 07 '14 at 11:49
  • @JoelKlinghed, LOL, I made a similar mistake yesterday confusing fgets with fscanf. :) – Devolus Jan 07 '14 at 11:52