Search code examples
cloopsioscanf

Skipping scanf for character input with %d


  int valid = 0;
  while (!valid) {

    printf("\nEnter number of characters (1-30)> ");
    scanf("%d", & n);
    printf("\nInclude numbers (Y/N)> ");
    scanf(" %c", & nf);
    printf("\nInclude symbols (Y/N)> ");
    scanf(" %c", & sf);
    //cond1 and cond2 initialized here
    if (cond1 && cond2)
      valid = 1;
    else
      printf("Invalid input");
  }

I need to implement a faulty input detection functionality for the first integer scan. If the user enters a character instead of an integer the second scanf is skipped and it goes directly to the 3rd scanf. How can I stop this from happening in case of a character input on %d? I want to ask for the input again if the user enters a character instead of a number


Solution

  • Just check the return value of scanf(), in your case:

    if ((scanf("%d", &n) != 1) /* should return 1 if 1 int is read */
    { 
      fprintf(stderr,"Input not a number\n");
      exit(EXIT_FAILURE) /* include stdlib or just use return */
    }
    

    Note that scanf() doesn't provide any protection from arithmetic overflow, in the case of a big number. You might want to use fgets() and later parse that string with a function such as strtol() for safety.

    Example: https://godbolt.org/z/oaMhac983

    If you want to ask for input again, I would suggest that you use fgets() instead and later check that string for non-digit characters.

    You can use strspn(),it returns the number of characters from the first argument that are present in the second argument.

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define MAX_N 13 /* save space \0 and \n */
    
    int main(void) {
      int num = 0;
      char n[MAX_N] = {0};
      char *numbers = "-+0123456789";
    
      while (1) {
        if (fgets(n, MAX_N, stdin) == NULL) /* check return value of fgets() */
        {
          exit(EXIT_FAILURE);
        }
        if (strspn(n, numbers) ==
            strlen(n) - 1) /* only numbers were read (exclude '\n')*/
        {
          if (sscanf(n, "%d", &num) != 1) /* check return value of scanf() */
          {
            exit(EXIT_FAILURE);
          }
          break;
        }
      }
    
      printf("%d\n", num);
    
      return 0;
    }
    

    Example: https://godbolt.org/z/d5KTrTGGE