user3290727
user3290727

Reputation: 11

How to prevent input using scanf from overflowing?

I'm relatively new to C and would like to know how to prevent an overflow from input...

So for example, I have:

scanf("%d", &a);

Where a is an integer.

So what I could I do to prevent someone from entering a number that's larger than max integer? Due to the constraints of the problem I'm working on, you HAVE to use scanf. How do I go about restricting the input?

Upvotes: 1

Views: 3826

Answers (1)

chux
chux

Reputation: 153498

It is very challenging to prevent user input.
There is no magic hand to reach out and stop the user from beating away at the keyboard.

But code can limit what it reads.

  1. scanf() is tough to limit. It may not set errno on overflow. Code can limit the number of char to say 9. That's a first step but one can not enter values like "1000000000" or "00000000000000001".

    // Assume INT_MAX = 2,147,483,647.
    scanf("%9d", &a);
    
  2. A pedantic method would use fgetc(). An unsigned method follows. int takes a bit more.

    unsigned a = 0;
    int ch = fgetc(stdin);
    while (isspace(ch)) {
      ch = fgetc(stdin);
    }
    while (isdigit(ch)) {
      ch -= '0';
      if (a >= UINTMAX/10 && (a > UINTMAX/10 || ch > UINTMAX%10)) {
        a = UINTMAX;
        break;  // overflow detected.
      }
      a = a*10 + ch;
      ch = fgetc(stdin);
    }
    ungetc(ch, stdin);  // Put back `ch` as it was not used.
    
  3. But I prefer to change the goal and simply tell the user again, even if it means reading in more characters.

    // 0:success or EOF
    int Read_int(const char *prompt, int *dest, int min, int max) {
      for (;;) {
        char buf[(sizeof(int)*3 + 3)*2];  // 2x generous buffer
        fputs(prompt, stdout);
        if (fgets(buf, sizeof buf, stdin) == NULL) {
          return EOF;
        }
        char *endptr;
        errno = 0;
        long l = strtol(buf, &endptr, 10);
        // no conversion or junk at the end ....
        if (buf == endptr || *endptr != '\n') {
          continue;
        }
        if (!errno && l >= min && l <= max) {
         *dest = (int) l;
         return 0; // success
        }
      }
    }  
    
    // Sample usage
    int a;
    Read_int("Enter an `int`\n", &a, INT_MIN, INT_MAX);
    

Upvotes: 1

Related Questions