当前位置:嗨网首页>书籍在线阅读

12-输入验证

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

8.6 输入验证

在实际应用中,用户不一定会按照程序的指令行事。用户的输入和程序期望的输入不匹配时常发生,这会导致程序运行失败。作为程序员,除了完成编程的本职工作,还要事先预料一些可能的输入错误,这样才能编写出能检测并处理这些问题的程序。

例如,假设你编写了一个处理非负数整数的循环,但是用户很可能输入一个负数。你可以使用关系表达式来排除这种情况:

long n;
scanf("%ld", &n);        // 获取第1个值
while (n >= 0)           // 检测不在范围内的值
{
     // 处理n
     scanf("%ld", &n);   // 获取下一个值
}

另一类潜在的陷阱是,用户可能输入错误类型的值,如字符 q 。排除这种情况的一种方法是,检查 scanf() 的返回值。回忆一下, scanf() 返回成功读取项的个数。因此,下面的表达式当且仅当用户输入一个整数时才为真:

scanf("%ld", &n) == 1

结合上面的 while 循环,可改进为:

long n;
while (scanf("%ld", &n) == 1 && n >= 0)
{
     // 处理n
}

while 循环条件可以描述为“当输入是一个整数且该整数为正时”。

对于最后的例子,当用户输入错误类型的值时,程序结束。然而,也可以让程序友好些,提示用户再次输入正确类型的值。在这种情况下,要处理有问题的输入。如果 scanf() 没有成功读取,就会将其留在输入队列中。这里要明确,输入实际上是字符流。可以使用 getchar() 函数逐字符地读取输入,甚至可以把这些想法都结合在一个函数中,如下所示:

long get_long(void)
{
     long input;
     char ch;
     while (scanf("%ld", &input) != 1)
     {
          while ((ch = getchar()) != '\n')
               putchar(ch); // 处理错误的输入
          printf(" is not an integer.\nPlease enter an ");
          printf("integer value, such as 25, -178, or 3: ");
     }
     return input;
}

该函数要把一个 long 类型的值读入变量 input 中。如果读取失败,函数则进入外层 while 循环体。然后内层循环逐字符地读取错误的输入。注意,该函数丢弃该输入行的所有剩余内容。还有一个方法是,只丢弃下一个字符或单词,然后该函数提示用户再次输入。外层循环重复运行,直到用户成功输入整数,此时 scanf() 的返回值为 1

在用户输入整数后,程序可以检查该值是否有效。考虑一个例子,要求用户输入一个上限和一个下限来定义值的范围。在该例中,你可能希望程序检查第1个值是否大于第2个值(通常假设第1个值是较小的那个值),除此之外还要检查这些值是否在允许的范围内。例如,当前的档案查找一般不会接受1958年以前和2014年以后的查询任务。这个限制可以在一个函数中实现。

假设程序中包含了 stdbool.h 头文件。如果当前系统不允许使用 _Bool ,把 bool 替换成 int ,把 true 替换成 1 ,把 false 替换成 0 即可。注意,如果输入无效,该函数返回 true ,所以函数名为 bad_limits()

bool bad_limits(long begin, long end,long low, long high)
{
     bool not_good = false;
     if (begin > end)
     {
          printf("%ld isn't smaller than %ld.\n", begin, end);
          not_good = true;
     }
     if (begin < low || end < low)
     {
          printf("Values must be %ld or greater.\n", low);
          not_good = true;
     }
     if (begin > high || end > high)
     {
          printf("Values must be %ld or less.\n", high);
          not_good = true;
     }
     return not_good;
}

程序清单8.7使用了上面的两个函数为一个进行算术运算的函数提供整数,该函数计算特定范围内所有整数的平方和。程序限制了范围的上限是 10000000 ,下限是 -10000000

程序清单8.7  checking.c 程序

// checking.c -- 输入验证
#include <stdio.h>
#include <stdbool.h>
// 验证输入是一个整数
long get_long(void);
// 验证范围的上下限是否有效
bool bad_limits(long begin, long end,
                   long low, long high);
// 计算a~b的整数平方和
double sum_squares(long a, long b);
int main(void)
{
     const long MIN = -10000000L;    // 范围的下限
     const long MAX = +10000000L;    // 范围的上限
     long start;                     // 用户指定的范围最小值
     long stop;                      // 用户指定的范围最大值
     double answer;
     printf("This program computes the sum of the squares of "
              "integers in a range.\nThe lower bound should not "
              "be less than -10000000 and\nthe upper bound "
              "should not be more than +10000000.\nEnter the "
              "limits (enter 0 for both limits to quit):\n"
              "lower limit: ");
     start = get_long();
     printf("upper limit: ");
     stop = get_long();
     while (start != 0 || stop != 0)
     {
          if (bad_limits(start, stop, MIN, MAX))
               printf("Please try again.\n");
          else
          {
               answer = sum_squares(start, stop);
               printf("The sum of the squares of the integers ");
               printf("from %ld to %ld is %g\n",
                        start, stop, answer);
          }
          printf("Enter the limits (enter 0 for both "
                   "limits to quit):\n");
          printf("lower limit: ");
          start = get_long();
          printf("upper limit: ");
          stop = get_long();
     }
     printf("Done.\n");
     return 0;
}
long get_long(void)
{
     long input;
     char ch;
     while (scanf("%ld", &input) != 1)
     {
          while ((ch = getchar()) != '\n')
               putchar(ch);            // 处理错误输入
          printf(" is not an integer.\nPlease enter an ");
          printf("integer value, such as 25, -178, or 3: ");
     }
     return input;
}
double sum_squares(long a, long b)
{
     double total = 0;
     long i;
     for (i = a; i <= b; i++)
          total += (double) i * (double) i;
     return total;
}
bool bad_limits(long begin, long end,
     long low, long high)
{
     bool not_good = false;
     if (begin > end)
     {
          printf("%ld isn't smaller than %ld.\n", begin, end);
          not_good = true;
     }
     if (begin < low || end < low)
     {
          printf("Values must be %ld or greater.\n", low);
          not_good = true;
     }
     if (begin > high || end > high)
     {
          printf("Values must be %ld or less.\n", high);
          not_good = true;
     }
     return not_good;
}

下面是该程序的输出示例:

This program computes the sum of the squares of integers in a range.
The lower bound should not be less than -10000000 and
the upper bound should not be more than +10000000.
Enter the limits (enter 0 for both limits to quit):
lower limit: low
low is not an integer.
Please enter an integer value, such as 25, -178, or 3: 3
upper limit: a big number
a big number is not an integer.
Please enter an integer value, such as 25, -178, or 3: 12
The sum of the squares of the integers from 3 to 12 is 645
Enter the limits (enter 0 for both limits to quit):
lower limit: 80
upper limit: 10
80 isn't smaller than 10.
Please try again.
Enter the limits (enter 0 for both limits to quit):
lower limit: 0
upper limit: 0
Done.