当预期值的类型为int如何验证用户输入和输入的值是int类型的呢? [英] How validate user input when the expected value is of type int and the entered value is not of type int?

查看:161
本文介绍了当预期值的类型为int如何验证用户输入和输入的值是int类型的呢?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下的code:

#include <stdio.h>

#define MIN 0
#define MAX 9 

int main()
{
    int n;

    while (1) {
        printf("Enter a number (%d-%d) :", MIN, MAX);
        scanf("%d", &n);

        if (n >= MIN && n <= MAX) {
            printf("Good\n");
        } else {
            printf("Damn you!\n");
            break;
        }
    }

    return 0;
}

以上code的工作原理,只要用户输入一个整数值的预期。例如,

The above code works as expected as long as the user inputs an integer value. For example,

$ ./a.out 
Enter a number (0-9) :15
Damn you!
$ ./a.out 
Enter a number (0-9) :5
Good
Enter a number (0-9) :3
Good
Enter a number (0-9) :-1
Damn you!
$ ./a.out 

但是,当用户输入任何意外的输入(如&LT;向上箭头&GT; - 这是 ^ [[A ,或者像 ABC ABC DEF 等),它出现故障并在一个无限循环。

But, when the user enters any unexpected input (like <up-arrow> - which is ^[[A, or any string like abc or abc def, etc), it fails and goes in to an infinite loop.

$ ./a.out 
Enter a number (0-9) :2
Good
Enter a number (0-9) :^[[A
Good
Enter a number (0-9) :Good
Enter a number (0-9) :Good
Enter a number (0-9) :Good
Enter a number (0-9) :Good
Enter a number (0-9) :Good
Enter a number (0-9) :Good
^C

有一点要注意:使用时进入&LT;向上箭头&GT; 首次,它工作正常!例如,

One thing to note: when the use enters <up-arrow> for the first time, it works as expected! For example,

$ ./a.out 
Enter a number (0-9) :^[[A
Damn you!
$ 

这是为什么奇怪的行为?我们应该如何在这里用户输入的东西是unappropriate处理案件?

Why is this odd behavior? How should we handle the case where user enters something that is unappropriate?

推荐答案

就个人而言,我建议抛弃 scanf函数完全交互式用户的输入,尤其是对数字输入。这只是没有足够能力去处理某些情况不好。

Personally, I advise ditching scanf altogether for interactive user input, especially for numeric input. It just isn't robust enough to handle certain bad cases.

%d个转换符告诉 scanf函数读取直到下一个非数字字符(忽略任何领先的空白)。假设呼叫

The %d conversion specifier tells scanf to read up to the next non-numeric character (ignoring any leading whitespace). Assume the call

scanf("%d", &val);

如果您的输入流看起来像{'\\ n','\\ T','','1','2','3','\\ n'}, scanf函数将跳过前导空白字符,读取和转换123,并在末尾换行符停止。该值 123 将被分配到 VAL scanf函数将返回值1,表示成功的分配的数目。

If your input stream looks like {'\n', '\t', ' ', '1', '2', '3', '\n'}, scanf will skip over the leading whitespace characters, read and convert "123", and stop at the trailing newline character. The value 123 will be assigned to val, and scanf will return a value of 1, indicating the number of successful assignments.

如果您的输入流看起来像{'A','B','C','\\ n'}, scanf函数将停止在<$ C阅读$ C> A ,不分配任何 VAL ,并返回0(表示没有成功的分配)。

If your input stream looks like {'a', 'b', 'c', '\n'}, scanf will stop reading at the a, not assign anything to val, and return 0 (indicating no successful assignments).

到目前为止,一切都很好,对不对?嗯,这里是一个丑陋的案例:假设你的用户在12w4。你可能想拒绝这个整个输入为无效。不幸的是, scanf函数将愉快地转换并分配12,并留下了输入流中的W4,污染了下阅读。它会返回一个1,表明一个成功的任务。

So far, so good, right? Well, here's an ugly case: suppose your user types in "12w4". You'd probably like to reject this entire input as invalid. Unfortunately, scanf will happily convert and assign the "12" and leave the "w4" in the input stream, fouling up the next read. It will return a 1, indicating a successful assignment.

下面是另一个丑陋的案例:假设你的用户类型在令人讨厌长的数字,比如1234567890123456789012345678901234567890。同样,你可能想直接拒绝该输入,但 scanf函数将继续前进,转换并分配给它,无论目标数据类型可以重新present该值或没有。

Here's another ugly case: suppose your user types in an obnoxiously long number, like "1234567890123456789012345678901234567890". Again, you'd probably like to reject this input outright, but scanf will go ahead and convert and assign it, regardless of whether the target data type can represent that value or not.

要妥善处理这种情况下,你需要使用不同的工具。更好的选择是使用读取输入文本与fgets (缓冲区溢出保护),并使用手动转换字符串与strtol 。优点:可以检测和拒绝坏串像12w4,你可以拒绝显然太长,超出范围的输入,你不要离开输入流中的任何垃圾。缺点:它有点更多的工作。

To properly handle those cases, you need to use a different tool. A better option is to read the input as text using fgets (protecting against buffer overflows), and manually convert the string using strtol. Advantages: you can detect and reject bad strings like "12w4", you can reject inputs that are obviously too long and out of range, and you don't leave any garbage in the input stream. Disadvantages: it's a bit more work.

下面是一个例子:

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
...
#define DIGITS ... // maximum number of digits for your target data type;
                   // for example, a signed 16-bit integer has up to 5 digits.
#define BUFSIZ (DIGITS)+3 // Account for sign character, newline, and 0 terminator
...
char input[BUFSIZ];

if (!fgets(input, sizeof input, stdin))
{
  // read error on input - panic
  exit(-1);
}
else
{
  /**
   * Make sure the user didn't enter a string longer than the buffer
   * was sized to hold by looking for a newline character.  If a newline 
   * isn't present, we reject the input and read from the stream until
   * we see a newline or get an error.
   */
  if (!strchr(input, '\n'))
  {
    // input too long
    while (fgets(input, sizeof input, stdin) && !strchr(input, '\n'))
    ;
  }
  else
  {
    char *chk;
    int tmp = (int) strtol(input, &chk, 10);

    /**
     * chk points to the first character not converted.  If
     * it's whitespace or 0, then the input string was a valid
     * integer
     */
    if (isspace(*chk) || *chk == 0)
      val = tmp;
    else
      printf("%s is not a valid integer input\n", input);
  }
}

这篇关于当预期值的类型为int如何验证用户输入和输入的值是int类型的呢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆