4.3 do_while循环结构

上一节讲了while循环结构的格式及编程方法,while循环结构是先判断条件表达式,条件为真则执行循环体,条件为假则退出循环。如果第一次判断条件不成立,循环体一次也不会被执行,所以又称为“当型循环”。本节主要讲另一种循环——do_while循环,又称为“直到型”循环,这种循环会先执行一次循环体,再进行条件判断,当条件为假时结束循环。

do_while循环结构的一般形式为:

do S while(表达式);

S称为循环体,可以是空语句、简单语句或复合语句,最后一个分号“;”是语句的结束符号,不能省略。do_while是先执行一次循环体S,再进行表达式计算并判断,如果结果为真,继续重复执行循环体S。执行过程如流程图:

while循环结构(4.3dowhile循环结构)(1)

do_while循环流程图

以下形式是合法的do_while形式。

(1)

i=10; do ; while(--i);

(2)

i=10; do printf("*"); while(--i);

(3)

i=10; do{ printf("*"); --i; }while(i>=0);

(1)的循环体是一条空语句(;),且被执行了10次,但什么也没干,循环结束后i变成了0;(2)和(3)功能是一样的,都是在屏幕上显示10个*号,(3)用复合语句作循环体,(2)用单条语句作循环体,计算--i表达式后再判断结果是否为真,显得要紧凑一些。

与while循环不同,do_while是先执行一次循环体,再进行条件判断,因此这种循环至少会被执行一次。我们可以把前面一些用while实现的程序改写成用do_while实现,如求100的累加和,用while实现时是这样的:

sum=0;i=1; while(i<=100){ sum=sum i;i ; }

而改成用do_while实现变成:

sum=0;i=1; do{ sum=sum i;i ; }while(i<=100);

两段代码在求100的累加和时写法虽不同,但结果都是一样的,都是在i为101时退出循环。但是在求前n项的累加和时却未必等价,设n由键盘输入,前面两段程序可以写为:

(1)用while实现

sum=0;i=1; scanf("%d",&n); while(i<=n){ sum=sum i;i ; }

(2)用do_while实现

sum=0;i=1; scanf("%d",&n); do{ sum=sum i;i ; }while(i<=n);

两个程序分别执行后,当输入大于0的数时,两个程序的运算结果一样。但是当输入0时,结果还一样吗?代码(1)的sum为0,因为循环体一次也没执行;而代码(2)的结果为1,因为循环体执行了一次,1被加进了sum中。可见前n项累加和的程序,用while和do_while实现存在细微差别,用do_while并不完全正确。

例1:从键盘读入一个整数,统计该数的位数并输出。

如输入495,输出结果为3。如果输入0至9的一个数,则输出结果为1。

我们知道任何一个整数,其绝对值总是可以写为:

n=m*10 r;

其中,r称为n的个位,m是n整除以10后(丢掉个位)的结果。因此一个整数,可以可以拆分为m和r两个部分,m的位数刚好是n丢掉个位的数,r只有一位。如:

495 可拆分为m=49,r=5; 49又可拆分为m=4,r=9; 4又可拆分为 m=0,r=4;

当拆分到m为零时,拆分结束。从上述的分析可知一个具有k位的整数可以被拆分k次,每次从右到左依次把相应位丢掉,至到所有位全部拆分出为止(此时m==0)。由于我们不关心拆出来的位用来干什么,我们直接把整数的后一位丢掉就行,因此,丢掉n的个位的代码为:

m=n/10;

m就是n丢掉了个位后乘余的数,设一个计数变量cnt统计丢掉的位的数,因为每做一次m=n/10就丢掉一个位,因此接着要让cnt加1。循环体变为:

m=n/10; cnt=cnt 1;

因为还要继续对m进行拆分,所以下一次执行循环时变量n要变为m的值,也就是要把m赋给n,循环体变为:

m=n/10; cnt=cnt 1; n=m;

考虑循环体第1行和第3行之间,m没有发生变化,所以两句可以合并为一句,即n=n/10,循环体变为:

n=n/10; cnt=cnt 1;

由于循环执行的条件是n>0,因此可以用while语句构造循环如下:

while(n>0){ n=n/10; cnt=cnt 1; }

当n为大于0的整数时,while循环总能得到正确结果。但是当n=0时,循环体一次也不执行,cnt为0,而正确结果应为1。因此可以用do_while循环解决n为0的问题。用do_while写的代码如下:

do{ n=n/10; cnt=cnt 1; }while(n>0);

这样程序就更加完整了,输入任何合法的整数总能得到正确的结果。完整的程序如下:

#include <stdio.h> int main(void) { int cnt=0; int n; printf("Enter a integer:"); scanf("%d",&n); if(n<0) n=-n; do{ n=n/10; cnt=cnt 1; }while(n>0); printf("it contains %d digits!\n",cnt); return 0; }

程序中考虑了n为负整数的情况,当n为负整数时先要变成其相反数。思考一下,如果要用while循环,如何修正刚才的n为0时的错误!

例2:用do_while语句根据格雷戈里公式计算π值,要求最后一项精度小于10^-4。

由于结束循环使用item的绝对值小于10^-4,因此程序与while版本的功能一样,只是循环构造略有不同。

#include<stdio.h> #include<math.h> int main( ) { int flag,d; double item,sum,pi; item=1; d=1; flag=1; do{ sum=sum item; d=d 2; flag=-flag; item=flag*1.0/d; }while(fabs(item)>=1e-4); pi=4*sum; printf("pi=%f\n",pi); }

大部分情况下,用do_while可以完成的循环,稍作补充和修改也可以用while完成,针对do_while至少执行一次循环体的特例在while中要作特殊处理。如在例1中,如果要想用while代替do_while,要对n=0的情况进行特殊处理。

本节主要介绍了do_while循环的格式和执行过程,比较了while与do_while语句构造循环异同,介绍了两种循环结构的相互替代方法。本节就讲到这里,下节再见。

,