《C程序设计语言(第2版新版)典藏版》 —3.5 while循环与for循环
3.5 while循环与for循环
我们在前面已经使用过while与for循环语句。在while循环语句
while(表达式)
语句
中,首先求表达式的值。如果其值为真非0,则执行语句,并再次求该表达式的值。这一循环过程一直进行下去,直到该表达式的值为假(0)为止,随后继续执行语句后面的部分。
for循环语句
for(表达式1;表达式2;表达式3)
语句
等价于下列while语句:
表达式1;
while(表达式2){
语句
表达式3;
}
但当while或for循环语句中包含continue语句时,上述二者之间就不一定等价了。我们将在3.7节中介绍continue语句。
从语法角度看,for循环语句的3个组成部分都是表达式。最常见的情况是,表达式1与表达式3是赋值表达式或函数调用,表达式2是关系表达式。这3个组成部分中的任何部分都可以省略,但分号必须保留。如果在for语句中省略表达式1与表达式3,它就退化成了while循环语句。如果省略测试条件,即表达式2,则认为其值永远是真值,因此,下列for循环语句
是一个“无限”循环语句,这种语句需要借助其他手段(如break语句或return语句)才能终止执行。
在设计程序时到底选用while循环语句还是for循环语句,主要取决于程序设计人员的个人偏好。例如,在下列语句中:
因为其中没有初始化或重新初始化的操作,所以使用while循环语句更自然一些。
如果语句中需要执行简单的初始化和变量递增,使用for语句更合适一些,它将循环控制语句集中放在循环的开头,结构更紧凑、更清晰。通过下列语句可以很明显地看出这一点:
这是C语言处理数组前n个元素的一种习惯性用法,它类似于Fortran语言中的DO循环或Pascal语言中的for循环。但是,这种类比并不完全准确,因为在C语言中,for循环语句的循环变量和上限在循环体内可以修改,并且当循环因某种原因终止后循环变量i的值仍然保留。因为for语句的各组成部分可以是任意表达式,所以for语句并不限于通过算术级数进行循环控制。尽管如此,牵强地把一些无关的计算放到for语句的初始化和变量递增部分是一种不好的程序设计风格,该部分放置循环控制运算更合适。
作为一个较大的例子,我们来重新编写将字符串转换为对应数值的函数atoi。这里编写的函数比第2章中的atoi函数更通用,它可以处理可选的前导空白符以及可选的加(+)或减(-)号。(第4章将介绍函数atof,它用于对浮点数执行同样的转换。)
下面是程序的结构,从中可以看出输入的格式:
如果有空白符的话,则跳过
如果有符号的话,则读取符号
取整数部分,并执行转换
其中的每一步都对输入数据进行相应的处理,并为下一步的执行做好准备。当遇到第一个不能转换为数字的字符时,整个处理过程终止。
标准库中提供了一个更完善的函数strtol,它将字符串转换为长整型数。有关函数strtol的详细信息请参见附录B.5。
把循环控制部分集中在一起,对于多重嵌套循环优势更为明显。下面的函数是对整型数组进行排序的Shell排序算法。Shell排序算法是D. L. Shell于1959年发明的,其基本思想是:先比较距离远的元素,而不是像简单交换排序算法那样先比较相邻的元素。这样可以快速减少大量的无序情况,从而减轻后续的工作。被比较的元素之间的距离逐步减小,直到减小为1,这时排序变成了相邻元素的互换。
该函数中包含一个三重嵌套的for循环语句。最外层的for语句控制两个被比较元素之间的距离,从n/2开始,逐步进行对折,直到距离为0。中间层的for循环语句用于在元素间移动位置。最内层的for语句用于比较各对相距gap个位置的元素,当这两个元素逆序时把它们互换过来。由于gap的值最终要递减到1,因此所有元素最终都会位于正确的排序位置上。注意,即使最外层for循环的控制变量不是算术级数,for语句的书写形式仍然没有变,这就说明for语句具有很强的通用性。
逗号运算符“,”是C语言中优先级最低的运算符,在for语句中经常会用到它。被逗号分隔的一对表达式将按照从左到右的顺序进行求值,各表达式右边的操作数的类型和值即为其结果的类型和值。这样,在for循环语句中,可以将多个表达式放在各个语句成分中,比如同时处理两个循环控制变量。我们可以通过下面的函数reverse(s)来举例,该函数用于倒置字符串s中各个字符的位置。
某些情况下的逗号并不是逗号运算符,比如分隔函数参数的逗号、分隔声明中变量的逗号等,这些逗号并不保证各表达式按从左至右的顺序求值。
应该慎用逗号运算符。逗号运算符最适用于关系紧密的结构中,比如上面的reverse函数内的for语句,对于需要在单个表达式中进行多步计算的宏来说也很适合。逗号表达式还适用于reverse函数中元素的交换,这样,元素的交换过程便可以看成是一个单步操作。
练习3-3 编写函数expand(sl,s2),将字符串sl中类似于a-z一类的速记符号在字符串s2中扩展为等价的完整列表abc…xyz。该函数可以处理大小写字母和数字,并可以处理a-b-c、a-z0-9与-a-z等类似的情况。作为前导和尾随的-字符原样排印。
- 点赞
- 收藏
- 关注作者
评论(0)