同步阅读进度,多语言翻译,过滤屏幕蓝光,评论分享,更多完整功能,更好读书体验,试试 阅读 ‧ 电子书库
8.6 输入确认
在实际情况中,程序的用户并不总是遵循指令,在程序所期望的输入与其实际获得的输入之间可能存在不匹配。这种情况能导致程序运行失败。然而,通常您可以预见可能的输入错误,而且,经过进行一些额外的编程努力,可以让程序检测到这些错误并对其进行处理。
一个可能有输入错误的例子是,假设您正在编写一个程序,该程序提示用户输入一个非负整数。另一种类型的错误是用户输入了对程序正在执行的特定任务无效的值。
例如,假设有一个处理非负数的循环。用户可能犯的一类错误是输入一个负数。您可以使用一个关系表达式来检测这类错误:
另一个潜在的易犯错误是用户可能输入错误类型的值,例如字符q。检测这类错误的一种方式就是检查scanf()的返回值。回忆一下,这一函数返回其成功读入的项目个数;因此仅当用户输入一个整数时,下列表达式为真:
据此就可以提出前面那段代码的下面这种改进方法:
从字面上来看,while循环的条件就是“当输入是一个整数且该整数为正”。
上面这个例子中,如果用户输入错误类型的值,则终止输入。然而,您可以选择方法使程序对用户更加友好,给用户尝试输入正确类型的值的机会。如果要那样做,您首先需要剔除那些有问题的输入;如果scanf()没有成功读取输入,就会将其留在输入队列中。这里,输入实际上是字符流这一事实就派上了用场,您可以使用getchar()来逐个字符地读取输入。您甚至可以将所有这些想法合并在下面这样的一个函数中:
这一函数试图将一个int值读入变量input。如果没有成功,则该函数进入外层while循环的语句体。然后内层while循环逐个字符地读取那些有问题的输入字符。注意该函数选择丢弃该行中余下的所有输入,您也可以选择只丢弃下一个字符或单词。然后该函数提示用户重新尝试。外层循环继续运行,直至用户成功地输入一个整数从而使scanf()返回值1。
克服了用户输入整数的障碍后,程序可以检查这些值是否有效。考虑一个例子,其中需要用户输入一个下界和一个上界来定义值域。这种情况下,您可能希望程序检查第一个值是否不大于第二个值(通常值域假设第一个值较小)。可能还需要检查这些值是否在可接受的范围内。例如,对档案进行搜索时可能要求年份不小于1958,并且不大于2004。这一检查也可以在一个函数中实现。
下面是一种可能,其中假定已经包括了stdbool.h头文件。如果您的系统上没有_Bool类型,可以使用int来代替bool,并用1代表true,0代表false。注意如果输入无效,则该函数返回true;因此函数名为bad_limits()。
程序清单8.7使用上面两个函数来向一个算术函数传送整数,该函数计算特定范围内所有整数的平方和。程序限制这个特定范围的上界不应大于1000,下界不应小于-1000。
下面是一个运行示例:
8.6.1 分析程序checking.c程序的计算机化核心部分(也就是sum_squares()函数)仍是简短的,但是对输入确认的支持使得它比我们前面给出的例子更为复杂。我们来看其中的一些元素,首先集中讨论程序的整体结构。
我们已经遵循了一种模块化方法,使用独立的函数(模块)来确认输入和管理显示。程序越大,使用模块化的方法进行编程就越重要。
main()函数管理流程,为其他函数指派任务。它使用get_int()来获取值,用while循环来处理这些值,用badlimits()函数来检查值的有效性,sum_squares()函数则进行实际的计算:
8.6.2 输入流和数值编写像程序清单8.7中所使用的代码来处理错误输入时,您应该对C输入的工作方式有一个清晰的理解。考虑如下所示的一行输入:
在您的眼中,该输入是一串字符后面跟着一个整数,然后是一个浮点值。对C程序而言,该输入是一个字节流。第1个字节是字母i的字符编码,第2个字节是字母s的字符编码,第3个字节是空格字符的字符编码,第4个字节是数字2的字符编码,等等。所以如果get_int()遇到这一行,则下面的代码将读取并丢弃整行,包括数字,因为这些数字只是该行中的字符而已:
虽然输入流由字符组成,但如果您指示了scanf O函数,它就可以将这些字符转换成数值。例如,考虑下面的输入:
如果您在scanf()中使用%c说明符,该函数将只读取字符4并将其存储在一个char类型的变量中。如果您使用%s说明符,该函数会读取两个字符,即字符4和字符2,并将它们存储在一个字符串中。如果使用%d说明符,则scanf()读取同样的两个字符,但是随后它会继续计算与它们相应的整数值为4×10+2,即42;然后将该整数的二进制表示保存在一个int变量中。如果使用%f说明符,则scanf()读取这两个字符,计算它们对应的数值42,然后以内部浮点表示法表示该值,并将结果保存在一个float变量中。
简言之,输入由字符组成,但scanf()可以将输入转换成整数或浮点值。使用像%d或%f这样的说明符能限制可接受的输入的字符类型,但getchar()和使用%c的scanf()接受任何字符。
请支持我们,让我们可以支付服务器费用。
使用微信支付打赏