C: How to prevent input using scanf from overflowi

2019-01-27 08:32发布

问题:

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?

Thanks in advance.

回答1:

'Tis 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)) {
  unsigned newa = a*10 + ch - '0';
  if (newa < a) {
    break;  // overflow detected.
  }
  a = newa;
  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 mean 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];
    fputs(prompt, stdout);
    if (fgets(buf, sizeof buf, stdin) == NULL) {
      return EOF;
    }
    char *endptr;
    errno = 0;
    long l = strtol(buf, &endptr, 10);
    if (buf == endptr || *endptr != '\n') {
      continue; // only \n entered or invalid `chars` entered
    }
    if (!errno && l >= min && l <= max) {
     *dest = (int) l;
     return 0; // success
    }
  }
}  

int a;
Read_int("Enter an `int`\n", &a, INT_MIN, INT_MAX);