-2

In an effort to get back into the flow of C programming, I've been typing up some simple test programs. I've ran into a strange problem with the scanf function. I have 3 in the following code, but only the first 2 are initialized; the third scanf is ignored. Is this normal, or am I doing something wrong? I've been staring at this code for the last half an hour and I can't find any errors.

#include <stdio.h>

int math(int a, int b, char selection) {

    int result;

    switch (selection) {
        case 'a':
        result = a + b;
        break;
        case 's':
        result = a - b;
        break;
        case 'm':
        result = a * b;
        break;
        case 'd':
        result = a / b;
        break;
    }

    return result;
}

int main() {
    int num1 = 0;
    int num2 = 0;
    int result = 0;
    char selection;

    printf("Enter first number: ");
    scanf("%i", &num1);

    printf("Enter second number: ");
    scanf("%i", &num2);

    printf("\n[a] Add\n[s] Subtract\n[m] Multiply\n[d] Divide\n\nWhich one: ");
    scanf("%c", &selection);

    result = math(num1, num2, selection);
    printf("%i", result);

    return 0;
}
subtlearray
  • 1,251
  • 1
  • 11
  • 23
  • 1
    The scanf isn't ignored, it's consuming a leftover newline character. – Mike Dec 17 '13 at 19:24
  • For getting character-by-character input, use `fgetc()` or `getc()`. For getting line-by-line user input, use `fgets()`. For reading from a binary file, use `fread()` (or `read()` from the POSIX C library, if necessary/available). –  Dec 17 '13 at 19:46
  • @JanD - If you see many of his answers, @H2CO3 is biased against the use of `scanf()` because of the hidden nuances of this function that trip everyone up. I don’t argue that it can be tricky, but using the documentation and good debugging skills and its really not such a bad little function – Mike Dec 17 '13 at 19:50
  • 1
    @Mike well, except for its consistent tendency to cause buffer overruns, you mean? – John Dvorak Dec 17 '13 at 19:50
  • @JanD - again, that's just in the case you don't use a limiter. To H2CO3's comment: `scanf("%9s", now_were_ok_if_our_buffer_is_10);`. Limiting your input and using correct input types and the return codes, etc is all in the man pages or the C spec – Mike Dec 17 '13 at 19:53
  • 1
    @Mike yeah. And you then change the buffer size to 5, and you forget to update the hard-coded size. Happens all the time. Why bother, when you could as well just use `fgets(buf, sizeof buf, stdin)`? –  Dec 17 '13 at 19:54
  • Note: With `scanf("%i"`, entering values like "013" will result in a `int` value of `11` as leading zeros imply octal. With `scanf("%d"`, the input string is only view as decimal. – chux - Reinstate Monica Dec 17 '13 at 20:25

1 Answers1

7

To answer your over all question:
Is there a limit to how many times the scanf function can be used?

No, no there is not.

but that's not what is happening here anyway.

When you do something like this:

printf("Enter second number: ");
scanf("%i", &num2);

You're actually entering two values on stdin, first a number, second an invisible newline character.

                     you can't see that, but it's there
                         V
> Enter second number: 3\n    

The way scanf() works, it will read and store input from stdin to your variables until they are all filled, then it will leave the rest. In my example 3 got stored to num2 and '\n' is left on stdin Then when this code runs:

scanf("%c", &selection);

It will look on stdin and find the newline character ('\n') sitting there. This can be stored to a character type, so it will fill selection with it.

One way to fix this is to change your code to:

scanf(" %c", &selection);

The space before the % tells scanf to ignore any white space (including newlines) that are at the start of the stdin buffer.


Side note on debugging:

When you think something is going wrong, either use a debugger or print some values to give you confidence and understanding. For example, I would update your code as such:

printf("\n[a] Add\n[s] Subtract\n[m] Multiply\n[d] Divide\n\nWhich one: ");
int ret = scanf("%c", &selection);

printf("Scanf I think failed. Return value is: %d. Selection is: %c (%d)\n", 
        ret, selection, selection);

You can find the meaning of return values from man pages. In this case the return code here will tell you how many items were successfully matched and assigned. You'd see 1 here, so you know the call worked. Your output would look like:

Scanf I think failed. Return value is: 1. Selection is:
(10)

This tells you that scanf did indeed get something, you don't see a character printed, but the output skipped a line (suspicious) and the ASCII value of what was printed was 1010, looking that up you'll see it's a newline character.

Mike
  • 47,263
  • 29
  • 113
  • 177