user13077054
user13077054

Reputation:

How to check input with scanf?

I have the below code :

#include <stdio.h>

void printMenu() {
    printf("********************************\n");
    printf("*Enter a number (-1 to exit):  *");
    printf("\n* 1 - Add new student          *");
    printf("\n* 2 - Delete a student         *");
    printf("\n* 3 - Update student           *");
    printf("\n* 4 - Print a student          *");
    printf("\n* 5 - Print all students       *");
    printf("\n********************************\n");
    printf("\nEnter: ");
}

int main (int argc, char **argv) {
    int a;

    printMenu();
    scanf("%d", &a);

    while(a != -1) {
        switch(a) {
            case 1:     
                printf("1\n");
                break;
            case 2:     
                printf("2\n");
                break;
            case 3:         
                printf("3\n");
                break;
            case 4:         
                printf("4\n");
                break;
            case 5:         
                printf("5\n");
                break;
            default:       
                printf("\nInvalid answer!\n");
                break;
        }
       
        puts("");
        printMenu();
        scanf("%d", &a);  
    }
    return 0;
} 

I would like to check the input of scanf. For example if user enters a number it works successfully, but if user enter something like a string or a char it print non-stop the menu again and again.

I would like to check if user enters a number or not. If not I would like to ask again about input. I have tried things like:

if(scanf("%d", &a)!=1) {
     printf("Enter again: ");
     scanf("%d", &a);
}

Or:

assert(scanf("%d", &a);

With assert function program stops executing but I want it to continue after while. Any ideas?

Upvotes: 0

Views: 310

Answers (2)

prog-fh
prog-fh

Reputation: 16910

When dealing with interactive input, I find convenient to always consume the input line, then analyse it afterwards.
This way, whatever has been given on input (conforming to expectations or not), it won't stay in the input stream blocking further analysis.

This generally looks like this

/**
  gcc -std=c99 -o prog_c prog_c.c \
      -pedantic -Wall -Wextra -Wconversion \
      -Wc++-compat -Wwrite-strings -Wold-style-definition -Wvla \
      -g -O0 -UNDEBUG -fsanitize=address,undefined
**/

#include <stdio.h>

int
main(void)
{
  for(;;)
  {
    printf("Please, provide something interesting: ");
    char input_line[0x100];
    if(!fgets(input_line, sizeof(input_line), stdin))
    {
      printf("no more input\n");
      break; // leave the loop
    }
    int answer;
    if(sscanf(input_line, "%d", &answer)!=1)
    {
      printf("an integer was expected.\n");
      continue; // go back to the prompt
    }
    printf("%d + %d = %d\n", // make use of the provided information
           answer, answer, answer+answer);
  }
  return 0;
}

Upvotes: 1

bruno
bruno

Reputation: 32596

but if user enter something like a string or a char (e.g. a or grebv) it print non-stop the menu again and again

this is because when scanf fails nothing is read, so you have to bypass the non number for instance reading up to the end of line with getchar/fgets. Warning you also have to manage the case of EOF for instance because the stdin is redirected in a file.

To do :

if(scanf("%d", &a)!=1) {
     printf("Enter again: ");
     scanf("%d", &a);
}

is not enough even adding the flush of the invalid input before the second scanf because you can have two or more consecutive errors (the second scanf fails too).

A way can be for instance :

#include <stdio.h>

void printMenu() {
  fputs("********************************\n"
        "*Enter a number (-1 to exit):  *\n"
        "* 1 - Add new student          *\n"
        "* 2 - Delete a student         *\n"
        "* 3 - Update student           *\n"
        "* 4 - Print a student          *\n"
        "* 5 - Print all students       *\n"
        "********************************\n"
        "\nEnter: ", stdout);
}

int main()
{
  int a;

  do {
    printMenu();

    if (scanf("%d", &a) != 1) {
      /* flush invalid input up to the end of line */
      while ((a = getchar()) != '\n') {
        if (a == EOF) {
          puts("...EOF...");
          return -1;
        }
      }
      a = 0; /* any 'invalid' value managed in the 'default' case of the 'switch'*/
    }

    switch (a) {
    case -1:
      break; /* or 'return 0;' and the 'do while' is a 'for(;;)' */
    case 1:     
      printf("1\n");
      break;
    case 2:     
      printf("2\n");
      break;
    case 3:         
      printf("3\n");
      break;
    case 4:         
      printf("4\n");
      break;
    case 5:         
      printf("5\n");
      break;
    default:
      puts("\nInvalid answer!");
      break;
    }
  } while (a != -1);

  return 0;
}

Compilation and executions:

/tmp % gcc -Wall a.c
/tmp % ./a.out
********************************
*Enter a number (-1 to exit):  *
* 1 - Add new student          *
* 2 - Delete a student         *
* 3 - Update student           *
* 4 - Print a student          *
* 5 - Print all students       *
********************************

Enter: 1
1
********************************
*Enter a number (-1 to exit):  *
* 1 - Add new student          *
* 2 - Delete a student         *
* 3 - Update student           *
* 4 - Print a student          *
* 5 - Print all students       *
********************************

Enter: aze

Invalid answer!
********************************
*Enter a number (-1 to exit):  *
* 1 - Add new student          *
* 2 - Delete a student         *
* 3 - Update student           *
* 4 - Print a student          *
* 5 - Print all students       *
********************************

Enter: 2
2
********************************
*Enter a number (-1 to exit):  *
* 1 - Add new student          *
* 2 - Delete a student         *
* 3 - Update student           *
* 4 - Print a student          *
* 5 - Print all students       *
********************************

Enter: -1
/tmp % 
/tmp % ( echo 1 ; echo aze ; echo 2 ) | ./a.out
********************************
*Enter a number (-1 to exit):  *
* 1 - Add new student          *
* 2 - Delete a student         *
* 3 - Update student           *
* 4 - Print a student          *
* 5 - Print all students       *
********************************

Enter: 1
********************************
*Enter a number (-1 to exit):  *
* 1 - Add new student          *
* 2 - Delete a student         *
* 3 - Update student           *
* 4 - Print a student          *
* 5 - Print all students       *
********************************

Enter: 
Invalid answer!
********************************
*Enter a number (-1 to exit):  *
* 1 - Add new student          *
* 2 - Delete a student         *
* 3 - Update student           *
* 4 - Print a student          *
* 5 - Print all students       *
********************************

Enter: 2
********************************
*Enter a number (-1 to exit):  *
* 1 - Add new student          *
* 2 - Delete a student         *
* 3 - Update student           *
* 4 - Print a student          *
* 5 - Print all students       *
********************************

Enter: ...EOF...
/tmp % 

Upvotes: 0

Related Questions