- C51单片机高效入门(第2版)
- 徐玮
- 3619字
- 2021-04-01 23:03:23
4.4 循环控制
4.4.1 概述
几乎每个程序都会用到循环语句,它的作用就是用来实现语句多次的反复执行操作。如一个频率为12MHz的51单片机应用电路中,要求实现1ms的延时,那它就要执行1000次空语句才可以达到延时的目的(当然可以使用定时器来做,我们将在后面介绍定时器的使用),如果手工写1000条空语句那是非常麻烦的事情,难以想象,其次就是要占用很多的存储空间。我们知道这1000条空语句,都是一样的语句——即一条空语句重复执行1000次,因此我们就可以用循环语句去写,这样不但使程序结构简洁,查看代码显示直观,而且使编译的效率大大提高。在C语言中构成循环控制的语句有goto,while,do-while,for语句。这些语句都能起到循环作用,但其具体的用法会有一些区别,我们根据具体的情况来选用哪种循环语句。
C语言提供了多种循环语句,可以组成各种不同形式的循环结构。
1)goto语句和if语句构成循环;
2)while语句;
3)do-while语句;
4)for语句。
4.4.2 goto语句以及用goto语句构成循环
goto语句在很多高级语言中都会有,和BASIC语言中的一样,这个并不陌生。它是一个无条件的转向语句,只要执行到这个语句,程序指针就会跳转到goto后的标号所在的程序段。
goto语句的使用格式为
其中标号是一个有效的标识符,这个标识符与一个“:”相连接,一起出现在函数内某处,执行goto语句后,程序将跳转到该标号处并执行其后的语句。另外标号必须与goto语句同处于一个函数中,但可以不在一个循环层中。通常goto语句与if条件语句连用,当满足某一条件时,程序跳到标号处运行。
结构化程序设计应尽量不用goto语句,主要因为它将使程序层次不清,不易读懂,但在程序多层嵌套退出时,使用goto语句则比较合理、方便。
【例4-11】
例4-11中说明了goto语句的用法,实际编写很少使用这样的手法,在此我们仅用它来说明语句的用法。这段程序的意思是在程序开始处用标识符“loop:”标识,表示程序的开始,“end:”标识程序的结束,标识符的定义应遵循C语言标识符定义原则,不能用C语言系统中的关键字,也不能和其他变量或函数名相同,否则编译时将出现错误提示。程序执行a++,a的值加1,当a等于100时,程序就会跳到end标识处,即执行一条空语句后,结束程序运行,否则跳回到loop标识处继续执行a++语句,直到a等于100才结束程序运行。例4-11说明goto不但可以无条件的转向,也可以和if语句构成一个循环结构,不过这样的用法并不太常见,goto语句用的最多的是用它来跳出多重循环,不过它只可以从内层循环跳到外层循环,不能从外层循环跳到内层循环。过多的使用goto语句会使程序结构不清晰,过多的跳转就使程序变得又像汇编语言的风格,而失去了C程序模块化的优点。
4.4.3 while语句
while语句的意思很容易理解,其英语单词解释的意思是“当…的时候”,在这里我们可以理解为“当条件为真的时候就执行后面的语句”。
while语句的一般形式为
其中表达式是循环条件,语句为循环体。
while语句的语义是:计算表达式的值,当值为真(非0)时,执行循环体语句。
使用while语句时要注意当条件表达式为真时,它执行后面的语句,执行一次完成之后再次回到while执行条件判断,如果为真,则重复执行语句,为假时退出循环体。当条件一开始就为假时,那么while后面的循环体一次都不会被执行就退出整个循环。
While语句的执行过程如图4-6所示。
图4-6 while语句的执行过程
【例4-12】用while语句求
用传统流程图和N-S结构流程图表示算法,如图4-7所示。
图4-7 程序流程图
【例4-13】编写程序,求1~100累加和。
这是一个求100个数的累加和问题。所加的加数从1变化到100,可以看到加数是有规律变化的,后一个加数比前一个加数增1,第一个加数为1,最后一个加数为100。因此,可以在循环中使用一个整型变量i,每循环一次,使i增1,一直循环到i的值超过100,用这个办法就解决了所需的加数问题。但是要特别注意的是变量i需要有一个正确的初值,在这里它的初值应当设定为0。
下一个要解决的是求累加和。设用一个变量sum来存放这100个数的和值,可以先求0+1的和并将其放在sum中,然后把sum中的数加上2再放在sum中,依次类推。这和人们心算的过程没有什么区别,sum代表着人们脑中累加的那个和数,不同的是心算的过程由人们自己控制。在这里,sum累加的过程要放在循环中,由计算机来判断所加的数是否已经超过100,加数则放在变量i中,并在循环过程中一次次增1。
以下就是求累加和的典型程序。
main()
程序运行后的输出结果;
sum=5050
注意:
1)如果在第一次进入循环时,while后圆括号内表达式的值为0,循环一次也不执行。在本程序中,如果i的初值大于100,将使表达式i<=100的值为0,循环体也不执行。
2)在循环体中一定要有使循环趋向结束的操作,以上循环体内的语句i++使i不断增1,当i>100时,循环结束.如果没有i++;这一语句,则a的值始终不变,循环将无限进行。
3)在循环体中,语句的先后位置必须符合逻辑,否则将会影响运算结果,例如,若将上例中的while循环体改写成:
运行后,将输出:
sum=5150
运行的过程中,少加了第一项的值1,而多加了最后一项的值101。
【单片机C语言设计小实例1】程序显示从1到10的累加和,读者可以修改一下
while中的条件看看结果会如果,从而体会一下while的使用方法。
4.4.4 do-while语句
do-while语句的一般形式为
do
语句
while(表达式);
1)do是C语言的关键字,必须和while联合使用。
2)do-while循环由do开始,用while结束;必须注意的是:在while(表达式)后的“;”不可丢,它表示do-while语句的结束。
3)while后一对圆括号中的表达式,可以是C语言中任意合法的表达式,由它控制循环是否执行。
do-while语句可以说是while语句的补充,while是先判断条件是否成立再执行循环体,而do-while则是先执行循环体,再根据条件判断是否要退出循环。这样就决定了循环体无论在任何条件下都会至少被执行一次。其执行过程如图4-8所示。
图4-8 do-while语句的执行过程
【例4-14】求1~100之间的累加和。
程序如下:
}
可以看到:对同一个问题可以用while语句处理,也可以用do-while语句处理。do-while结构可以转换成while结构。
由do-while构成的循环与while循环十分相似,它们之间的主要区别是:while循环的控制,出现在循环体之前,只有当while后表达式的值为非零时,才可能执行循环体;在do-while构成的循环中,总是先执行一次循环体,然后再求表达式的值,因此,无论表达式的值是0还是非0,循环体至少执行一次。和while循环一样,在do-while循环体中,一定要有能使while后表达式的值变为0的操作,否则,循环将会无限制地进行下去。
【例4-15】while和do-while循环比较。
【单片机C语言设计小实例2】
4.4.5 for语句
在C语言中,for语句使用最为灵活,它完全可以取代while语句。在明确循环次数的情况下,for语句比以上说的循环语句都要方便简单。它的一般形式为
它的执行过程如下:
1)先求解初值设定表达式。
2)求解循环条件表达式,若它的值为真(非0),则执行for语句中指定的内嵌语句,然后执行下面第3)步;若值为假(0),则结束循环,转到第5)步。
3)条件更新表达式。
4)转回上面第2)步继续执行。
5)循环结束,执行for语句下面的一个语句。
其执行过程如图4-9所示。
for语句最简单的应用形式也是最容易理解的形式如下
图4-9 for语句的执行过程
初值设定表达式总会是一个赋值语句,用来给循环变量赋初值;循环条件表达式是一个关系表达式,由它决定什么条件下执行循环,什么时候退出循环;条件更新表达式,循环变量每循环一次后,都会进行相应的自增或自减运算。这三个部分之间用“;”隔开。
例如:
for(i=1;i<=50;i++)sum=sum+i;
先给变量i赋初值1,判断i是否小于或等于50,如果为真,则执行语句“sum=sum+i”,然后i自增1。然后再重新判断,直到条件为假,即i>50时,循环结束。
相当while语句:
如果将for循环语句的表现形式转换成while语句形式,则如下所示:
注意:
1)省略了“初值设定表达式”,表示不对循环变量赋初值。
2)省略了“循环条件表达式”,如程序中不做相应的处理,则将变成为死循环。
例如:
for(j=1;;j++)sum=sum+j;
相当于:
3)如果不写“条件更新表达式”,则不对循环变量进行操作,这时可在语句体中加入修改循环变量的语句。
例如:
4)如果不写“初值设定表达式”和“条件更新表达式”。
例如:
相当于:
while(j<=100)
5)for语句中的3个表达式全部省略不写。
例如:
for(;;)语句
相当于:
while(1)语句 即条件永远为真,形成死循环。
6)初值设定表达式可以是设置循环变量初值的赋值表达式,也可以是其他表达式。
7)“初值设定表达式”和“条件更新表达式”可以是一个简单的表达式,也可以是逗号表达式。
for(j=0,i=1;i<=50;i++)j=j+i;
或:
for(i=0,j=100;i<=50;i++,j--)k=i+j;
8)“循环条件表达式”一般我们使用关系表达式或逻辑表达式,但也可是数值或字符的表达式,只要其最终的值为非零,即逻辑“真”,那么就执行循环体。
【单片机C语言设计小实例3】
4.4.6 循环的嵌套
一个循环体内又完整地包含了另一个循环,称为循环嵌套,前面介绍的3种循环都可以互相嵌套,这就是多重循环。但要注意循环层次要清楚,不能交叉。
【例4-16】求2~10000以内的完全数。
完全数:一个数如果恰好等于它的因子(除开自身)和,该数称为完全数。例如,6的因子为1、2、3,而且1+2+3,因此6是“完全数。
程序如下:
程序包含了一个两重循环j。其中外层循环变量为i,控制数据的取值范围、求出因子和,如i等于因子和s,则输出这个数。内层循环变量为j,内层循环的循环体只有一条语句用于求对应每一个i所有的因子和(s)(当i能被j整除时,j就是i的一个因子)。
几种循环的比较:
前面介绍的各种循环语句,虽然格式不同,但它们有着共同的特点,都实用于循环结构的程序设计。在程序设计的过程中,都具有以下三条内容:
(1)循环体的设计。
(2)循环条件的设计。
(3)循环入口的初始化工作。
从前面所举的几个例子中可以看出,循环体语句的正确执行,依赖于循环的条件,循环的条件依赖循环入口时的初始化工作,一环紧扣一环。
循环体中安排哪些语句,要从分析具体问题入手,前后呼应,合乎逻辑。并且能确保循环能够终止。而且结论正确。
While,do-while语句的使用,它的循环条件的改变,要靠程序员在循环体中去有意安排某些语句。而for语句却不必。使用for语句时,若在循环体中想去改变循环控制变量,以期改变循环条件,无异于画蛇添足。
While循环,do-while循环适用于未知循环的次数的场合,而for循环适用于已知循环次数的场合。使用哪一种循环又依具体的情况而定。
凡是能用for循环的场合,都能用While,do-while循环实现,反之则未必。
4.4.7 break和continue语句
1.break语句
break语句通常用在循环语句(for,while,do-while)和switch语句中。当break用于switch语句中时,可使程序跳出switch程序体而执行switch语句后面的语句;如果没有break语句,则将成为一个死循环。break在switch中的用法非常简单,加上一句“break;”即可。
当break语句用于do-while、for、while循环语句中时,可使程序终止循环,跳出循环体而执行后面的语句,通常break语句与if语句一起使用,当满足条件时便跳出循环。
【例4-17】计算半径r=1~10时的圆面积,直到面积area大于100为止。
程序如下:
从上面的for循环可以看到当area>100时,执行break语句,提前终止执行循环,即不再继续执行其余的几次循环。
2.continue语句
continue语句是用于中断的语句,通常使用在循环中,它的作用是结束本次循环,跳过循环体中还没有执行到的语句,而跳转到下一次循环周期。
语法为:continue;
continue同时也是一个无条件跳转语句,但功能和前面说到的break语句有所不同,continue执行后不是跳出循环体,而是跳到循环的开始部分并执行下一次的循环。
continue语句只用在for、while、do-while等循环体中,通常与if语句一起使用。
Continue语句与break语句的区别及其执行过程如图4-10所示。
图4-10 break,continue语句的执行过程比较
1)while(表达式1)
}
2)while(表达式1)
【例4-18】
这个程序是将1~20之间不能被2整除的数输出到屏幕上。当变量i对2取模为0时,则为i能整除2,此时执行continue语句,程序将跳到for语句继续执行,输出函数在此时将不会被执行。这个程序是针对for语句的。如果在其他两种循环中使用了continue语句,程序将跳过剩余的循环体内的语句,直接转到条件表达式处开始判断表达式是否成立,然后继续执行程序。
3.程序举例
【例4-19】用公式求π。
N-S流程如图4-11所示。
图4-11 N-S流程图
【例4-20】判断m是否为素数。
N-S流程如图4-12所示
图4-12 N-S流程图
【例4-21】求100~200间的全部素数。