6.1 再探while循环

您已经多少有点熟悉while循环了。让我们用一个程序来回顾一下,这个程序对从键盘输入的整数进行求和(请参见程序清单6.1)。这个例子使用了scanf()的返回值来结束输入。

程序清单6.1 summing.c程序

阅读 ‧ 电子书库

广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元

阅读 ‧ 电子书库

程序清单6.1使用类型long来允许较大的数。尽管C的自动转换允许您简单地使用0,但程序为了保持一致性,把sum初始化为OL(类型为long的零)而不是0(类型为int的零)。

下面是一个运行示例:

Please enter an integer to be summed(q to quit): 44

Please enter next integer(q to quit): 33

Please enter next integer(q to quit): 88

Please enter next integer(q to quit): 121

Please enter next integer(q to quit): q

Those integers sum to 286.

6.1.1 程序注解

我们首先看一下while循环。这个循环的判断条件是以下表达式:

status == 1

==运算符是C的相等运算符(equality operator);也就是说,这个表达式判断status是否等于1。不要把它与status=1相混淆,后者把值1赋给status。使用status= =1作为判断条件,那么只要status等于1,循环就会重复执行。在每次循环中,循环体把num的当前值加到sum上,这样sum就始终保持为总和。当status的值不为1时循环终止,然后程序报告sum的最终结果。

要使程序正确运行,在每次循环中应该为num获取一个新值,并且重置status。程序使用scanf()的两个不同功能来做到这一点。首先,使用scanf()来尝试为num读入新值。然后,使用scanf()的返回值来报告执行是否成功。回忆一下第4章“字符串和格式化输入/输出”,scanf()返回成功读入的项目的个数。如果scanf()成功读入了一个整数,就把这个整数放在num中并返回值1,随后值1被赋给status(请注意输入值赋给num,而不是status)。这样就更新了num和status的值,while循环也经过了另一个周期。如果您输入的不是数字,例如输入q,那么scanf()就不能读入一个整数,所以它的返回值和status都为0。这将使循环终止。因为输入的字符q不是数字,所以它又被放回到输入队列中,不能被读取(实际上,不仅仅是q,任何非数字的输入都将使循环终止,但是提示用户输入q比提示用户输入一个非数字字符要简单一些)。

如果scanf()在尝试转换一个数值前遇到了问题(例如,检测到文件的尾部或者遇到一个硬件问题),它就会返回一个特殊值EOF,这个值一般被定义为-1。这个值同样也会导致循环终止。

scanf()的双重用法避免了在循环中进行交互式输入时的一个棘手的问题:您如何告诉循环什么时候停止?例如,假定scanf()没有返回值,那么在每次循环中惟一改变的就是num的值。您可以使用num的值来终止循环,比如使用num>0(num大于0)或num!=0(num不等于0)来作为判断条件,但是这使您不能输入特定的值,例如-3或0。您也可以在循环中添加新的代码,例如在每次循环中询问“Do you wish to continue?<y/n>”,然后进行判断来看用户是否输入了y。这有些笨拙,而且也减慢了输入。使用scanf()的返回值避免了这些问题。

现在我们更仔细地看一下程序结构。可以进行总结如下:

initialize sum to O

prompt use

read input

while the input is an integer,

add the input to sum,
prompt user,
then read next input

after input completes, print sum

顺便说一下,这是个伪代码(pseudocode)的例子,伪代码是一种用简单的英语来表示程序的方法,它与计算机语言的形式相对应。伪代码有助于设计程序的逻辑。在认为逻辑正确之后,就可以把伪代码翻译成实际的编程代码。伪代码的一个好处是它可以使您专注于程序的逻辑与组织,使您不必同时担心如何用计算机语言来表达您的想法。例如,您可以使用缩排来代表一块代码而不用担心要求花括号的C语言语法。另一个好处是伪代码不与某一特定的语言相联系,这样同一伪代码可以被翻译为多种计算机语言。

总之,因为while循环是一个入口条件循环,所以程序必须在进入循环体之前获取输入并检查status的值。这就是程序在while之前有一个scanf()调用的原因。要使循环继续执行,在循环中需要一个读语句,这样程序才可以得出下一个输入的状态。这就是程序在while循环的结尾处还有一个scanf()的原因,它为下一次循环做准备。可以把如下用法作为循环的标准格式:

get first value to be tested

while the test is successful

process value
get next value
6.1.2 C风格的读循环

按照伪代码中显示的设计方法,程序清单6.1也可以用Pascal、BASIC或FORTRAN书写。然而C提供了更快捷的形式。下面的结构:

阅读 ‧ 电子书库

可以用下列形式代替:

阅读 ‧ 电子书库

第二种形式同时使用了scanf()的两种不同用法。首先,如果调用成功,函数会把一个值放在num中;第二,函数的返回值(1或0,而不是num的值)用来控制循环。因为在每次重复过程中都对循环条件进行判断,所以在每次循环中都调用scanf()来提供新的num值和新的判断。换句话说,C的语法特性使您可以用以下的精简版本来代替标准的循环格式:

while getting and testing the value succeeds

process the value

现在我们更为正式地看一下while语句。