0

`

switch(selectedOption){
  case 'B':
    printf("Please enter the first number\n");
    if (scanf("%f", &firstNumber) == 1){
       printf("Is a valid number\n");
    }
    else{
       printf("Is not a valid number\n");
    }
}

`

I have a school assignment where I have to program a calculator. One of the requirements is to ask for the user to input another number if they for example input a character instead of a number. I'm not sure how to go about this and I looked everywhere and no solutions made sense. I would appreciate it a ton if someone could help me out with this problem.

ddawgio
  • 13
  • 1
  • 1
    You put the `switch` inside a loop. If you were using `if` instead of `switch`, you'd do `break;` to exit the loop. But, `break;` inside a `case` just ends the case. So, you need an extra variable. Try: `int valid = 0; while (! valid) { switch (selectedOption) { case 'B': printf("Please enter the first number\n"); valid = (scanf("%f", &firstNumber) == 1); printf("Is %sa valid number\n",valid ? "" : "not "); break; } }` – Craig Estey Nov 16 '22 at 17:39
  • @CraigEstey `continue` inside the `switch` would also *continue* to the next loop iteration. But that's getting awfully complex and hard-to-maintiain. I'd delegate the "get a number" to a function that gets a valid number from the user. – Andrew Henle Nov 16 '22 at 17:41
  • I believe this has been answered [here](https://stackoverflow.com/questions/58399995/how-to-check-if-user-input-is-of-correct-data-type-in-c?rq=1) or [here](https://stackoverflow.com/questions/31633005/validate-the-type-of-input-in-a-do-while-loop-c) – emetsipe Nov 16 '22 at 19:09

2 Answers2

0

You do not need switch - case. You just need to do:

while (true) {
    char number = 0;
    scanf_s("%c", &number);
    if (number >= '0' && number <= '9') break;
    else printf("Is not a valid number\n");
}
Iulian St
  • 9
  • 1
  • This isn't sufficient. Just testing for range `0-9` isn't enough. User could enter `1Q` and it would pass your test. What about: `if (scanf("%f",&number) == 1) break;` instead? – Craig Estey Nov 16 '22 at 17:48
  • 1
    And the user could enter `foo` and it would go into an infinite loop. – Ian Abbott Nov 16 '22 at 17:49
  • Checking for a value between 48.00 and 57.00 (because `'0'` is 48 and `'9'` is 58) isn't all that plausible. I'm assuming `number` is a `float`; if it isn't, there's a mismatch between the conversion specification (`"%f"`) and the argument. You're missing a semicolon after `scanf()`. You must check that `scanf()` worked before using `number`. – Jonathan Leffler Nov 16 '22 at 17:56
  • That's true. I did not compiled it. Now should do the work if he want to enter a digit at a time – Iulian St Nov 16 '22 at 18:04
  • `scanf_s()`?!? That's *de facto* not portable, nor is it any "safer". Read this: [**Field Experience With Annex K — Bounds Checking Interfaces**](https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1967.htm) – Andrew Henle Nov 16 '22 at 18:21
  • Yes I know. My compiler does not let me use scanf(). I personally do not use any of them. – Iulian St Nov 16 '22 at 18:29
0

The simple answer is to loop until valid input has been read (assuming the input comes from an interactive agent such as a person sat at a terminal).

The following will not work:

switch(selectedOption){
  case 'B':
    while (1) {
      printf("Please enter the first number\n");
      if (scanf("%f", &firstNumber) == 1){
         printf("Is a valid number\n");
         break;
      }
      else{
         printf("Is not a valid number\n");
      }
    }
    /* ... */
    break;
}

The problem is that scanf will stop reading input when it sees a character that is not part of the number, and will push that character back onto the stream (c.f. ungetc). For example, if the input is -foo, scanf will read the spaces, then the - (which could be part of the number), then the f which is not part of the number. The f will be pushed back onto the stream and scanf will return 0. On the next iteration of the while loop, scanf will read the f, push it back onto the stream and return 0. Loop ad infinitum, et ultra.

To break the infinite loop, the code needs to read something from the stream and discard it. One option is to read and discard the next word by calling scanf("%*s");, or discard the next word and the following whitespace character by calling scanf("%*s%*c");, or discard the remainder of the line and the newline by calling scanf("%*[^\n]%*c");. E.g.:

switch(selectedOption){
  case 'B':
    while (1) {
      printf("Please enter the first number\n");
      if (scanf("%f", &firstNumber) == 1){
         printf("Is a valid number\n");
         break;
      }
      else{
         printf("Is not a valid number\n");
         scanf("%*s");
      }
    }
    /* ... */
    break;
}

Note that input such as 42foo will be considered valid by the above code. scanf will push the f back onto the stream and return 1 because it has read a valid number 42. You may want to read the next character and check that it makes sense. You can always push at least one character back onto the stream by calling ungetc(ch, stdin); so that it can be re-read later.

Ian Abbott
  • 15,083
  • 19
  • 33
  • Thank you! This helped me a ton. I haven't learned this at all in my class so it was pretty difficult to figure this problem out. Thank you again – ddawgio Nov 16 '22 at 19:10