赞
踩
在实际应用中,用户不一定会按照程序的指令行事。
用户的输入和程序期望的输入不匹配时常发生,这会导致程序运行失败。作为程序员,除了完成编程的本职工作,还要事先预料一些可能的输入错误,这样才能编写出能检测并处理这些问题的程序。例如,假设我们编写了一个处理非负数整数的循环,但是用户很可能输入一个负数。
你可以使用关系表达式来排除这种情况:
long n;scanf("%ld", &n); // get first valuewhile (n >= 0) // detect out-of-range value{ // process n scanf("%ld", &n); // get next value}
另一类潜在的陷阱是,用户可能输入错误类型的值,如字符q。排除这种情况的一种方法是,检查scanf()的返回值。回忆一下,scanf()返回成功读取项的个数。因此,下面的表达式当且仅当用户输入一个整数时才为真:
scanf("%ld", &n) == 1
结合上面的while循环,可改进为:
long n;while (scanf("%ld", &n) == 1 && n >= 0){ // process n}
while循环条件可以描述为“当输入是一个整数且该整数为正时”。
对于最后的例子,当用户输入错误类型的值时,程序结束。
然而,也可以让程序友好些,提示用户再次输入正确类型的值。在这种情况下,要处理有问题的输入。如果scanf()没有成功读取,就会将其留在输入队列中。这里要明确,输入实际上是字符流。可以使用getchar()函数逐字符地读取输入,甚至可以把这些想法都结合在一个函数中,如下所示:
long get_long(void){ long input; char ch; while (scanf("%ld", &input) != 1) { while ((ch = getchar()) != '') putchar(ch); // dispose of bad input 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个值是较小的那个值),除此之外还要检查这些值是否在允许的范围内。例如,当前的档案查找一般不会接受1949年以前和2020年以后的查询任务。这个限制可以在一个函数中实现。
假设程序中包含了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.", begin, end); not_good = true; } if (begin < low || end < low) { printf("Values must be %ld or greater.", low); not_good = true; } if (begin > high || end > high) { printf("Values must be %ld or less.", high); not_good = true; } return not_good;}
下面的程序清单8使用了上面的两个函数为一个进行算术运算的函数提供整数,该函数计算特定范围内所有整数的平方和。程序限制了范围的上限是10000000,下限是-10000000。
Listing 8.7 The checking.c Program
// checking.c -- validating input#include #include // validate that input is an integerlong get_long(void);// validate that range limits are validbool bad_limits(long begin, long end, long low, long high);// calculate the sum of the squares of the integers// a through bdouble sum_squares(long a, long b);int main(void){ const long MIN = -10000000L; // lower limit to range const long MAX = +10000000L; // upper limit to range long start; // start of range long stop; // end of range 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 andnthe 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 %gn", 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); // dispose of bad input 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.
虽然checking.c程序的核心计算部分(sum_squares()函数)很短,但是输入验证部分比以往程序示例要复杂。接下来分析其中的一些要素,先着重讨论程序的整体结构。
程序遵循模块化的编程思想,使用独立函数(模块)来验证输入和管理显示。程序越大,使用模块化编程就越重要。
main()函数管理程序流,为其他函数委派任务。它使用get_long()获取值、while循环处理值、bad_limits()函数检查值是否有效、sum_squres()函数处理实际的计算:
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 %gn", 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();}
在编写处理错误输入的代码时,应该很清楚C是如何处理输入的。考虑下面的输入:
is 28 12.4
在我们眼中,这就像是一个由字符、整数和浮点数组成的字符串。但是对C程序而言,这是一个字节流。第1个字节是字母i的字符编码,第2个字节是字母s的字符编码,第3个字节是空格字符的字符编码,第4个字节是数字2的字符编码,等等。所以,如果get_long()函数处理这一行输入,第1个字符是非数字,那么整行输入都会被丢弃,包括其中的数字,因为这些数字只是该输入行中的其他字符:
while ((ch = getchar()) != 'n') ptchar(ch); // dispose of bad input
虽然输入流由字符组成,但是也可以设置scanf()函数把它们转换成数值。例如,考虑下面的输入:
: 42
如果在scanf()函数中使用%c转换说明,它只会读取字符4并将其存储在char类型的变量中。
如果使用%s转换说明,它会读取字符4和字符2这两个字符,并将其存储在字符数组中。
如果使用%d转换说明,scanf()同样会读取两个字符,但是随后会计算出它们对应的整数值:4×10+2,即42,然后将表示该整数的二进制数存储在int类型的变量中。
如果使用%f转换说明,scanf()也会读取两个字符,计算出它们对应的数值42.0,用内部的浮点表示法表示该值,并将结果存储在float类型的变量中。
简而言之,输入由字符组成,但是scanf()可以把输入转换成整数值或浮点数值。使用转换说明(如%d或%f)限制了可接受输入的字符类型,而getchar()和使用%c的scanf()接受所有的字符。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。