0

When you run this code, it somehow works as well as the number of characters entered by scanf after the first operation. What's the problem?

I filled in the blank space before %c because I thought it might be a buffer problem, but the error still occurs.

void EX18() {
    float x, y;
    char op;
    int i = 0;
    while (1) {
        /*
        printf("\n******************** \n");
        printf("A ---- Add \n");
        printf("S ---- Subtract \n");
        printf("M ---- Multiply \n");
        printf("D ---- Divide \n");
        printf("Q ---- Quit \n");
        printf("******************** \n");
        */
        i++;
        printf("\n%dth iteration \n",i);
        printf("Select an operation: ");
        scanf(" %c", &op);

        if (op == 'Q') break;
        else {
            switch (op) {
            case 'A':
                printf("Enter two numbers separated by a space: ");
                scanf("%f %f", &x, &y);
                printf("%.2f \n", x + y);
                break;
            case 'S':
                printf("Enter two numbers separated by a space: ");
                scanf("%f %f", &x, &y);

                printf("%.2f \n", x - y);
                break;
            case 'M':
                printf("Enter two numbers separated by a space: ");
                scanf("%f %f", &x, &y);

                printf("%.2f \n", x * y);
                break;
            case 'D':
                printf("Enter two numbers separated by a space: ");
                scanf("%f %f", &x, &y);

                printf("%.2f \n", x / y);
                break;
            default:
                printf("\nUnknown command. Please try again.\n");
            }
        }
    }
}

int main()
{
    EX18();
    //TEST5();
    return 0;
}

Result Screen :

1th iteration Select an operation: 00

Unknown command. Please try again.

2th iteration Select an operation: Unknown command. Please try again.

3th iteration Select an operation: 000

Unknown command. Please try again.

4th iteration Select an operation: Unknown command. Please try again.

5th iteration Select an operation: Unknown command. Please try again.

6th iteration Select an operation:

  • Unrelated: The prompting for the numbers and well as reading them is done the same in all cases. Why not move it outside of the `switch`? Also, it's almost no use in `float` these days. Unless you have very specific requirements, use `double` for your floating point numbers instead. – Some programmer dude Apr 19 '23 at 12:28
  • As for your error, what *is* your error? Please [edit] your question to tell us the input you give, and the actual as well as expected output. – Some programmer dude Apr 19 '23 at 12:28
  • I'm sorry. I accidentally forgot the picture of the result screen. – Gongback Kim Apr 19 '23 at 12:29
  • 1
    Please, [don't post images of text](https://meta.stackoverflow.com/questions/285551/why-should-i-not-upload-images-of-code-data-errors). Copy-paste *all* text as actual text into your question. – Some programmer dude Apr 19 '23 at 12:30
  • 2
    Without checking the return value of your various `scanf()`'s, you don't know whether `x` and `y` are ever actually initialized. *Never use `scanf()` without checking its return value.* – DevSolar Apr 19 '23 at 12:33
  • 1
    The advice by @DevSolar is a good one. Even better might be to forget that `scanf` even exists. Use `fgets` to read whole lines. Then you can use `sscanf` to parse the input. But again listen to owhat @DevSolar is saying, and check the return value of `sscanf`. – Some programmer dude Apr 19 '23 at 12:36
  • **Don't post pictures of text**. Output is text. Copy paste the output and post it as properly formatted text. – Jabberwocky Apr 19 '23 at 12:37
  • Your problem is that you're asking the user to enter 'A', 'S', 'M', or 'D' to specify an operation, but then you're typing things like "OO" and "OOO". Why are you doing that? If you enter single characters, as requested, the program works fine, at least for me. – Steve Summit Apr 19 '23 at 12:41
  • Doing user input using `scanf` has certain limitations. One of the limitations is that it is difficult or impossible to recover from bad input. So, when you're testing a program that uses `scanf`, you should always give it correct inputs, not incorrect inputs. If you want to write a program that can deal gracefully with improper inputs (like "OOO" when a single character was expected), you'll be far better off writing it using [something other than `scanf`](https://stackoverflow.com/questions/58403537). – Steve Summit Apr 19 '23 at 12:43

2 Answers2

2

The problem is that you read the "command" character by character. If you input two invalid characters the first scanf(" %c", &op) call will read the first, but the second invalid input is still in the buffer to be read by the next call.

As I advised in a comment, use fgets to read whole lines, and then e.g. sscanf to parse the input:

char buffer[256];  // No need to skimp on space

if (!fgets(buffer, sizeof buffer, stdin))
{
    // Failed to read input
    // TODO: Handle this case
}

if (sscanf(" %c", &op) != 1)
{
    // Invalid input
    // TODO: Handle this case
}

It's more code, but it will be more robust and safer than your current code.

Do something similar for the numeric input.

I also suggest you put these in separate functions, which makes it easier to read the code, to test it and to debug it when needed.


Please note that while the code describe above will make your input handling better and safer, it's not perfect.

An obnoxious user could input a line longer than 255 characters, in which case we're basically back where we started, where you get left over input in the buffers.

To be really safe from it you should check if the last character in the input from fgets is a newline, and if not then tell the user about the invalid input and use fgets (of perhaps even just fgetc) in a loop until you have read the newline.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
1

The key part of your program is the two lines

printf("Select an operation: ");
scanf(" %c", &op);

Suppose you type A. scanf reads the one character, assigns it to op, the later part of your program recognizes A for addition and does its thing.

Suppose you type O. scanf reads the one character, assigns it to op, but the later part of your program doesn't recognize the character and so prints "Unknown command".

Suppose you type XYZ. scanf reads the first character, X, and assigns it to op. But, again, the later part of your program doesn't recognize the character and so prints "Unknown command". But this time, when the program loops back to the beginning, those two unread characters YZ are still sitting on the input stream. So scanf can immediately read the next character, Y, and assign it to op. Which the later part of your program doesn't recognize. And then when the program loops a third time, again, it's already got that Z on the input stream to read.

The key things to understand are:

  1. scanf does not read lines of input.
  2. Unread or unrecognized input is left on the input stream.

So it's very common for a program that uses scanf to get confused when some unread or unrecognized input, typed on what you thought was the "previous line", is actually still hanging around in the input buffer, where it gets read by a later call to scanf, seemingly immediately, without even waiting for you to type anything.

Although scanf is reasonably simple to use for simple inputs, it's actually a pretty strange function and, as you've seen, can be very confusing. In particular, if you're thinking that the user is typing a line of text and hitting Return, it's often better to have your program work that way too, by reading input a line at a time using something like fgets, as suggested in several of the comments. See this answer for more about reading input using something other than scanf.

See also this previous question for some more discussion of how scanf actually works.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103