2

I started learning C and tried to code this math program using switch statements. The program runs and works just fine when I scan the operator first and then scan the numbers. But if I switch the order of the scanf functions to take the numbers first and then the operators, the program takes the number but after that it does not take the second input (the operator) and just prints the default value (invalid input). Why is this happening?

I have provided the code (if I run this code, the problem occurs with the program just taking the numbers and not taking the operators. But of the order is flipped, it works).

#include <stdio.h>

int main()
{

    float a, b, result;
    char operator;

    printf("Enter 2 numbers:");
    scanf("%f %f", &a, &b);
    printf("Choose a math operator (+, -, *, /):");
    scanf("%c", &operator);

    switch (operator)
    {
    case '+':
        result = a + b;
        break;
    case '-':
        result = a - b;
        break;
    case '*':
        result = a * b;
        break;
    case '/':
        result = a / b;
        break;
    default:
        printf("\nInvalid operator");
        return -1;
    }
    printf("%f", result);
    return 0;
}
Jabberwocky
  • 48,281
  • 17
  • 65
  • 115
  • newline is a character too. – G4143 Feb 03 '22 at 12:04
  • Note that you would make it easier for you to debug your problem if the error message reported on what character the invalid operator was: `fprintf(stderr, “invalid operator ’%c’\n”, operator);`. – Jonathan Leffler Feb 03 '22 at 13:47

2 Answers2

4

The format string "%c" will read the newline character from the first line of input. What you want instead is " %c" which will skip leading whitespace, so replace the line

scanf("%c", &operator);

with

scanf(" %c", &operator);

See also https://pubs.opengroup.org/onlinepubs/9699919799/

A directive composed of one or more white-space characters shall be executed by reading input until no more valid input can be read, or up to the first byte which is not a white-space character, which remains unread.

August Karlstrom
  • 10,773
  • 7
  • 38
  • 60
-6

you need to change

scanf("%c", &operator);

to

scanf("%s", &operator);

it will run.

Abhishek Chhabra
  • 120
  • 2
  • 14
  • It worked! Thanks for helping out. But why I had to use %s to scan a single character? Isn't it the format specifier for strings? – Labib Amir Salimi Feb 03 '22 at 12:13
  • it is because A String is an contiguous sequence of Characters, just as An Array is an contiguous sequence of Integers. A Character is a Single Symbol representing A Letter or Number. for symboles you need to use %s – Abhishek Chhabra Feb 03 '22 at 12:15
  • 5
    Don't do this! You are opening a security issue here! As you have said @LabibAmirSalimi `%s` should be used for **strings**. As a result the user can enter whatever string he/she wants!!! So you can write more than you should which will create undefined behaviour! – TornaxO7 Feb 03 '22 at 12:19
  • naah, it won't create undefined behaviour. – Abhishek Chhabra Feb 03 '22 at 12:21
  • What? Why shouldn't it create undefined behaviour??? – TornaxO7 Feb 03 '22 at 12:21
  • because in switch it is matching first character occurrence and performing that particular case statements... i have tested it then i am giving suggestion.. – Abhishek Chhabra Feb 03 '22 at 12:24
  • Ok, but you'll still be able overwrite some bytes which could manipulate some return adresses for example... Of course, most OS have an protection for that, but it's still not nice and not good to let the user be able to manipulate some bytes/adresses which are not dedicated to him/her.... – TornaxO7 Feb 03 '22 at 12:28
  • 1
    I got another solution in the comments of this post. Using fflush(stdin) fixes the problem. – Labib Amir Salimi Feb 03 '22 at 12:32
  • 6
    Look, folks, there is one simple answer: use `" %c"`. Using `"%s"` is **wrong**. Using `fflush(stdin)` is **wrong**. – Steve Summit Feb 03 '22 at 12:33
  • 1
    For `%s`, `scanf` has to write a null byte after reading the char input. Obviously can't write 2 chars into `operator` without UB. And `scanf` would happily accept arbitrary number of chars for `%s` is the extended version of the same issue. – P.P Feb 03 '22 at 12:37
  • 1
    @rAbhishekChhabra *naah, it won't create undefined behaviour* It absolutely is undefined behavior. When it comes to undefined behavior, saying "I have tested it" proves nothing, because sometimes, undefined behavior just happens to work. – Steve Summit Feb 03 '22 at 13:37
  • This is both an undefined behaviour and a security risk. `&s` with `scanf` doesn't do bounds checking. To represent a character in a string, you at least need 2 bytes. One for the character and one for the null termination. Here, we only have one and hence is undefined behaviour. Even if you have 2 bytes, what if the user enters 2 bytes? Then you'll need 3 bytes. Even if you have 1 million bytes, the user could enter more. This is simply undefined behaviour. – Shambhav Feb 03 '22 at 13:44
  • @AbhishekChhabra how do you want to make `scanf` not write a terminating 0 byte? Even if you only enter 1 character, you will write beyond the available buffer. – Gerhardh Feb 03 '22 at 14:21