Home > Net >  How to check for non-number inputs in calculator in C
How to check for non-number inputs in calculator in C

Time:08-19

Just started learning C and tried to make a calculator to test myself. I thought it would be a fun challenge to make it so:

  1. the program prints an error message to the user if the input(s) is not a number
  2. the user can input a number again, without shutting down the program

What I've learned in C so far is:

  • printf, scanf
  • data types
  • if statements
  • loops
  • functions

My question is, is it possible to accomplish the task with the knowledge mentioned above. If it is, what is that solution? (I've been stuck on this for quite a while now, so I hope me giving up on doing it myself is acceptable). If it's not, what do I need to learn to be able to do it?

Here's my code

#include <stdio.h>

float num1;
float num2;
float answer;
char operation;
int isNumber;           //1 means true, 0 means false
char restart;


int main ()
{
  printf ("Please enter the first number: ");
  isNumber = scanf("%f", &num1);
  while (isNumber == 0)
    {
       printf("Please enter a valid number: ");
       isNumber = scanf("%f", &num1);
    }
    
    //This just keeps reapeating the printf message.
    //Also, I just wrote the code for the first input.
    //If it doesn't work for this one, no point in writing it for other inputs.

  printf ("Please enter an operation: ");
  scanf (" %c", &operation);
  
  printf ("Please enter the second number: ");
  scanf ("%f", &num2);

  if (operation == ' ')
    {
      answer = num1   num2;
    }

  else if (operation == '-')
    {
      answer = num1 - num2;
    }

  else if (operation == '*')
    {
      answer = num1 * num2;
    }

  else if (operation == '/')
    {
      while (num2 == 0)
    {
      printf ("Cannot divide by 0. ");
      printf ("Please enter another number\n");
      scanf ("%f", &num2);
    }
      answer = num1 / num2;
    }


  printf ("\nThe answer is: %f", answer);
  printf ("\n\nEnter 1 to do another calculation. Enter anything else to quit: ");
  scanf(" %c", &restart);

  if(restart == '1')
      main();
  else
      return 0;
}

CodePudding user response:

scanf() only reads input that matches the format specifier (in your case this is %f). Characters that do not match the format specifier causes scanf() to stop scanning and causes scanf() to leave the invalid characters in the stdin buffer.

In your while loop if a invalid character is entered it will get stuck in the stdin buffer. This invalid character will then get read by the next scanf() call in the loop, which will also leave it in the stdin buffer. This will continue, again and again, resulting in an infinite loop.

As you might be able to tell scanf() is a unreliable and quick - yet not very robust way to take input.

To fix it you could use a hacky solution like this:

while ((scanf("%f", &num1)) != 1)
{ 
       printf("Please enter a valid number: ");
     
       int c; 
       while((c = getchar()) != '\n' && c != EOF);
}

// while loop "eats up" any characters
// that scanf has left in stdin buffer

Instead of scanf() i reccomend you get familiar with a function such as fgets() to take input. Then you can use a function like sscanf() to parse the input to see if it is a float.

As a beginner, while you are learning C, it is fine to use scanf(). But as you delve deeper into C and write more complicated pieces of software you must consider using safer and more robust alternatives to unreliable functions like scanf().

CodePudding user response:

To well handle user input, consider dropping all scanf() calls. To read a line of user input, use fgets().

How to check for non-number inputs

Create a helper function.

Read a line of text into a buffer and parse with sscanf() or strod(). sscanf() is OK and used below. strod() is better, yet some corner cases are beyond what a learner may appreciate.

#define LINE_LENGTH_MAX 400

// Return 1 on success, EOF on end-of-file, 0 on failure
int read_double(double *dest, const char *prompt) {
  if (prompt) {
    fputs(prompt, stdout);
  }

  char buffer[LINE_LENGTH_MAX   1];
  if (fgets(buffer, sizeof buffer, stdin) == NULL) {
    return EOF;
  }

  int n = 0; 
  sscanf(buffer, "%f %n", dest, &n);
  if (n == 0) {
    // Scanning failed
    return 0;
  }

  if (dest[n]) {
    // Yet there was extra junk at the end
    return 0;
  }

  return 1;
}

More advance code would used strtod() and detect lines longer than LINE_LENGTH_MAX.

  • Related