首页 服务器 编程 必备知识 搜索引擎 圩日手册
站内搜索
最近浏览
推荐文章
热文排行

第十章 循环语句


10.1 while 循环

10.2 do ... while 循环

10.3 for 循环

   10.3.1 循环条件三要素

   10.3.2 三要素在for循环结构上体现

10.4 多层循环

10.5 小结及一点问题

 

 

循环就是反复。

生活中,需要反复的事情很多。譬如你我的整个人生,就是一个反复,反复每一天的生活,直到死,幸好,我们每天的生活并不完全一个样。

 

10.1 while 循环

 

语法形式:

 

while(条件)

{

  需要循环执行的语句; 

}

while 是“当”的意思。

 

请首先和if语句作一个比较:

 

if(条件)

{

  条件成立时执行的语句;

}

 

二者除了关键字不一样以外,结构完全一样。但一定要注意,在条件成立时,if语句仅仅执行一遍,而while语句则将反复执行,直到条件不再成立。

请看while循环的流程图:

 

程序从“前面的语句”开始执行,然后进行条件判断,如果条件成立,则执行一次“每次循环执行的语句”,再后请特别注意红色部分,这是我们碰上的,第一次会往后走流程:红线就像汽车拐弯,掉头到条件处(并不包括前面的语句),然后再进行下一次的条件判断……直到某一次判断时条件不成立了,程序“继续后面的语句”。

 

 

我们用while的语法套用生活中的实际例子,可以直观地看出while的用法。

假设有一个爱哭的小娃娃,有一天她要求父母给买一条小红裙,可惜父母不同意,于是她就开始一个循环:
  

while ( 父母不给买小红裙)

{
      我哭;
   }

 

这段“代码”的意思是:当“父母不给买小红裙”,那么,小女孩就一遍一遍地哭。

这就是我们和循环流程的第一个遭遇战。所举的例子看似直观:“小孩一遍遍地哭,直到父母给买裙”,但真正要用程序的语言来正确地表达出来,需要很多方面要考虑到,必竟,程序是严谨的。

首先,一个合适的判断是否继续的条件相当重要。小女孩要继续哭,仅仅“父母不给买小红裙”,这显示不符合事实,想想我们小时候,再会哭,最终也有累的时候,所以,要想继续哭,我们的条件有两个:“父母不给买小红裙”并且“我还没有哭累”。

while ( 父母不给买小红裙 && 我还没有哭累)

{
      我哭;
   }

 

其次,大多数情况下,条件需要被恰当地改变。小女孩在不停地哭,那么她如何知道父母是否买了红裙呢?所以,她不能只顾哭,还得在哭的间隙观察大人是否同意买裙。至于是否哭累,我们假设小女孩有一个疲劳度,每哭一次疲劳度加1,当疲劳度到达200时,可怜的小女孩累了……

 

while(父母不给买小红裙 && 疲劳度 < 200)

{

  我哭;

  我偷看爸妈是否同意买裙;

  疲劳度++;

}

 

例一: 用 while 语句实现求从1到100的累加和。

 

求1+2的和,我们可以写 a = 1 + 2;求1加到100,我们当然可以这样写 a = 1 + 2 + 3 + ... 100.不过这样写显然太累人了,要从1写到100啊!所以聪明如高斯的你,当然也知道这样写:a = (1+100) * 50;这确实是个在任何时候都值得称赞的,又快又简的方法,只是今天我们想让计算机累一点,老老实实地从1加到100。首先用我们先学的while式的循环。

 

请同学们打开CB,然后新建一空白的控制台程序,在main()函数体加入下面黑体部分代码。然后按F9运行。查看运行结果以加深印象。

//---------------------------------------------------------------------------

#include <iostream.h>

#pragma hdrstop

//---------------------------------------------------------------------------

#pragma argsused

int main(int argc, char* argv[])

{

int sum = 0; //变量sum将用于存储累加和,将它初始化为0,这很重要。

int i = 1; //i是每次要加的数,它从1开始。

 

while ( i<= 100)

{

   sum += i;

   i++;

}

 

//输出累加结果:

cout << "1到100的累加和为:" << sum << endl;

getchar();

} 

sum 初始为0,然后在每一遍的循环里,它都加上i,而,i则每次都在被加后,增加1。最终,i递增到101,超过100了,这个循环也就完成了任务。

 

运行上面程序,输出结果为:

 

1到100累加和为为:5050

 

例二:用while循环实现简单的统计功能

 

统计功能在各行业里都经常用到,比如学校学生成绩总分的统计,商店中每日销售额的统计等。下面我们实现一个学生成绩的统计。

由于成绩中包含有80.5这样的需要小数的部分,所以我们使用实数类型。

 

保存,然后关闭上面的工程,然后再新建一个控制台工程。在主函数main内加入以下黑体部分的代码:

 

//---------------------------------------------------------------------------

#include <iostream.h>

#pragma hdrstop

//---------------------------------------------------------------------------

#pragma argsused

int main(int argc, char* argv[])

{

   float sum,score;

   int num; //num 用于存储有几个成绩需要统计。

   int i;   //i 用于计数

 

   //初始化:

   sum = 0; 

   i = 1;

 

   cout << "====成绩统计程序====" << endl;

   //用户需事先输入成绩总数:

   cout << "请输入待统计的成绩个数:";

   cin >> num;

   cout << "总共需要输入"<< num << "个成绩(每个成绩后请加回车键):" << endl;

 

   while ( i <= num)

   {

      cout << "请输入第" << i << "个成绩:";

      cin >> score;
         sum += score;
         i++;
      }

      //输出统计结果:
      cout << "参加统计的成绩数目:" << num << endl;
      cout << "总分为:" << sum << endl;

      getchar();

}

//---------------------------------------------------------------------------
 

以下是运行结果,我输入4个成绩参加统计:

回车结束上面的程序。稍作休息。

 

为了更直观地了解循环流程,现在我们来跟踪这段程序中的while循环。

1、首先在循环开始处设置断点(F5 功能):

 

2、按F9运行程序,在DOS窗口提示“请输入待统计的成绩个数:”时,输入4,并回车。

 

3、程序将在一瞬间运行到第一步设置的断点所在行。即 while(...)这一行。

   此时请鼠标挪到 i 上,稍等片刻,出现提示 “i=1",同样的方法可以观察num的值。

 

可见第一遍循环时,i = 1,num = 4,条件:i <= num 显然成立,循环得以继续。

 

4、按F8,程序往下运行一行,接着再按F8,程序要求输入一个成绩,请切换到DOS窗口,随便输入一个数,并回车。

回车后,程序运行到下图中蓝底的一行:

5、之后,连续按F8,你将发现程序“回头”运行到 while(...)这一行。此时,i=2, i <= num 条件仍然成立,如果您想再跟踪一遍循环,请继续按F8,如果想结束跟踪,在断点行上再按一次F5以取消断点,然后按F9,程序恢复全速运行。

(程序往回走,回到while行)

 

10.2 do ... while 循环

 

语法形式:

 

do

{

    需要循环执行的语句; 

}

while(条件);

 

和 while循环最明显的区别,就是do...while循环中,判断是否继续循环的条件,放在后面。也就是说,就算是条件一开始就不成立,循环也要被执行一次。请比较以下两段代码,前者使用while循环,后者使用do...while循环。

 

代码段一:

int a = 0;

while( a > 0 )

{

  a--;

}

 

变量a初始值为 0,条件 a > 0 显然不成立。所以循环体内的 a--;语句未被执行。

本段代码执行后,变量a值仍为0;

 

代码段二:

int a = 0;

do 

{

  a--;

}

while( a > 0 );

 

尽管循环执行前,条件 a > 0 一样不成立,但由于程序在运行到 do...时,并不先判断条件,而是直接先运行一遍循环体内的语句:a--。于是a的值成为 -1,然后,程序才判断 a > 0 ,发现条件不成立,循环结束。

 

do..while中的条件和while循环中的条件一样是:“允许继续循环的条件”,而不是“结束循环的条件”,这和Pascal语言中的do...until正好相反,学习过Pascal(Delphi)的学员可得注意。

 

以笔者的经验,do..while循环用得并不多,大多数的循环用while...来实现会更直观。下面我们仅简单地将1到100的连加程序转换为用do...while实现:

 

int sum =0;

int i=1;

 

do

{

   sum += i;

   i++;

}

while(i<=100);

 

例三:用 do...while实现可以多次统计的程序。

 

在例二中,我们做了一个统计程序。假如一个学生有三门成绩,如语文,数学,英语要统计总分,例二的程序可以方便地使用,但如果要连续统计一个班级每个学生的这三门成绩,我们就得不断地运行例二的成绩,这显然不方便。

一个同学的三门成绩需要一层循环,要不断统计多个同学各自的成绩,就需要再套上一层循环。请看下面例子中,如何在原来的 while...循环上再加一层do...while循环。

程序的思路是:统计完一遍后,就问一句是否要继续统计新同学的成绩,如果用户输入字母Y或y,表示需要统计一下位,否则,程序结束循环。

这个程序是在例二的基础上进行功能改进,以下粗体部分为新加的代码。

 

//---------------------------------------------------------------------------

#include <iostream.h>

#pragma hdrstop

//---------------------------------------------------------------------------

#pragma argsused

int main(int argc, char* argv[])

{

   float sum,score;

   int num; //num 用于存储有几个成绩需要统计。

   int i;   //i 用于计数

 

   char c; //用来接收用户输入的字母

 

  do

   {

     //初始化:

      sum = 0; 

      i = 1;

 

      cout << "====成绩统计程序====" << endl;

      //用户需事先输入成绩总数:

      cout << "请输入待统计的成绩个数:";

      cin >> num;

      cout << "总共需要输入"<< num << "个成绩(每个成绩后请加回车键):" << endl;

 

      while ( i <= num)

      {

         cout << "请输入第" << i << "个成绩:";

         cin >> score;
            sum += score;
            i++;
         }

         //输出统计结果:
         cout << "参加统计的成绩数目:" << num << endl;
         cout << "总分为:" << sum << endl;

       

      //提问是否继续统计:  

      cout <<"是否开始新的统计?(Y/N)?";

      cin  >> c;

     }

     while( c == 'y' || c == 'Y');

}

//---------------------------------------------------------------------------

程序完成一次统计以后,会提问“是否开始新的统计”,用户输入一个字母,存到变量 c,然后程序在do...while的条件里检查c是否等于‘Y’或‘y’。如果不等于,就结束循环。

由于程序在统计之后有一个提问的时间,所以,原来的getchar()就不再需要了。

在这个例子,外层循环使用do...while是最好的选择,因为,用户运行本程序,多数情况下,他至少想统计一次。

 

最后我们来看do...while循环的流程图,请和while的流程图对比。

 

 

10.3 for 循环

for 循环里在C,C++里用得最多,也是最灵活的循环语句。要学好它,需要从已经学过的while循环的身上,“挖掘”出有关循环流程的要素,这些要素隐藏在while,或do...while的背后,但它将直接体现在for循环的结构上。

10.3.1 循环条件三要素

 

学习了两种循环,我们来挖掘一下循环流程中的“条件三要素”。

 

第一、条件一般需要进行一定的初始化操作。

 

请看我们用while循环实现1到100累加的代码:

 

int sum = 0; //变量sum将用于存储累加和,将它初始化为0,这很重要。

int i = 1;   //i是每次要加的数,它从1开始。

 

while ( i<= 100)

{

   sum += i;

   i++;

}

 

这段代码中,循环的条件是 i <= 100;因此,一开始,i肯定需要一个确定的值。前面的:

int i = 0;这一行代码,在声明变量i的同时,也为i赋了初始值:1。这样,条件 i <= 100 得以成立(因为i为1,所以 i <= 100 当然成立)。

 

第二、循环需要有结束的机会。

 

程序中最忌“死循环”。所谓的“死循环”就是指该循环条件永远为真,并且,没有另外的跳出循环的机会(后面将学到)。比如:

 

//一段死循环的例子:

while ( 2 > 1 )

{

  cout << "死循环" <<endl; 

}

 

执行这段代码,你会发现程序停不下来了。原因就是它的循环条件 2 > 1 永远为true。所以,一个最后可以变成不成立条件在大多数情况下是必需的。比如在while的那个例子:

while ( i<= 100)

条件 i <= 100 ,由于 i 在循环中被改变,所以它至少在理论上有可能造成 i <= 100 不成立。

 

第三、在循环中改变循环条件的成立因素

 

这一条和第二条互相配套。

比如这段代码:

int i=1;

while ( i<= 100)

{

   sum += i;

}

同样是一段可怕的“死循环”。因为i没有被改变的机会,其值永远为1,从而循环条件 i<=100也就永远为真。所以在循环中最后一句(下面加粗部分),不可遗忘。

while ( i<= 100)

{

   sum += i;

   i++;

}

当然,在这段程序里,i++除了起改变条件成立因素以外,同时也起上sum不断加递增的数,从而实现得到累加和。

 

说完这一些,我们来看C,C++中最灵活循环结构:for循环。

 

10.3.2 三要素在for循环结构上体现

 

for 循环的语法:

 

for(条件初始化;条件;条件改变)

{

  需要循环执行的语句; 

}

 

可见,for的结构中,不仅提供了的“条件”的位置,同时也提供了条件初始化,和条件改变的位置。这三者虽然在同一行上,但并不是依次连接地执行。

 

条件初始化的表达式首先被执行(并且只被执行一次);

然后程序检查条件是否成立,如果成立就执行循环体中的语句,否则直接结束循环。

执行完一遍循环以后,程序执行“条件改变”语句。

 

1到100整数累加的程序,改为for循环写,是最合适的了:

 

int sum = 0;

int i;

 

for( i=1; i <= 100;i++)

{

  sum += i;

}

 

程序先执行条件初始化语句:i=1;

然后立即判断条件 i <= 100 吗?显示,此时该条件成立;

于是程序执行循环体内的语句,此时只有一句: sum += i;

然后,执行改变条件因子的语句: i++; 此时,i值变为 2;

程序再次判断条件 i <= 100 ?,依然成立,于是开始第二遍循环……

 

变量 i 可以初始化条件时才临时声明:

for(int i = 1;i <= 100;i++) ……

 

for 语句的复合结构,使得程序变得简捷。比如上面的例子中,原来 while或者do...while结构中,循环体内必须两句语句,现在只需一句(即:i++这一句被移到for的特定位置上),这样,我们可以去除花括号:

for(int i=0;i <= 100;i++)

   sum += 100;

当然,如果在其它情况下,for的循环体内仍需有多行语句时,{}仍是不可避免的。事实上,就算现在这种情况,我也建议大家使用花括号。这样可以让程序的结构看上去更清晰。

 

在本例中,如果非要讲究简捷,我们还可以将循环体内的那惟一的一行移到“条件改变”的位置:

for(int i=1; i<=100;sum += i,i++);

sum += i和i++之间用逗号分开。而在for后面的()行末,则直接跟上分号,表示for不必再执行其它的语句。

考虑到后置++的特性(在完成表达式的求值后,才进行加1操作),也可以将sum += i和i++合为一句:

for(int i=1;i<=100;sum += i++);

 

以上讲了for语句极尽合并之技巧,以求一个简捷。反过来,for语句也可以向 while或do...while语句一样拆开写:

 

int i = 1;

for(; i <= 100;)

{

  sum += i;

  i++;

}

 

看,条件初始化语句被移出for的结构,而条件改变语句则被当成一行普通语句,直接加入到循环体内。而在相应的位置上,只留下分号,用于表示空语句(请注意这一行中有2个分号,分别在 i<=100前后):

for (; i <= 100;)

如上行所示,for循环结构中的“条件初始”和“条件的改变”表达式都被省略,在这种情况下for和while或do...while循环完全一样。比如求1~100累加和:

int i=1,sum=0;

for(;i<=100;)

{

  sum += i;

  i++;

}

int i=1,sum=0;

while(i<=100)

{

  sum += i;

  i++;

}

下面分析几个实例:(用于分析的实例不提供上机的完整代码,请同学们自行创建空白工程,然后加入需要代码,确保每个实例都可运行,这是初学者逐步熟练的必经之路……信不信由你。打开CB吧)。

 

题一:用for循环在屏幕上逐行输出数字:1~200。

分析:这需要一个变量,其值从1变到200,并且每变一次新值,就用 cout 语句在屏幕上输出其值。

答案:

for(int i=1;i<=200;i++)

   cout << i << endl;

 

由于循环中执行的动作只有一句,所以我们省略了{}。

 

题二:6能被1、2、3、6整除,这些数称为6的因子,请循环列出36的所有因子。

分析:因子?忘了吗?求36的因子,就是求1~36中哪些整数可以整除36。我们学过 % 操作符,它用于求两数相除的余数。所以整除不整除,只要看余数是否为0即可。

答案:

 

for(int i=1;i<=36;i++)

{

   if(36 % i == 0)   //余数为0,说明整除

      cout << i << " "; //多输出一个空格,用于做两数之间的间隔

}

 

如果运行程序,得到结果应是:

1 2 3 4 6 9 12 18 36 

 

在这道题中,我们也看到了两种流程的结合:for循环流程和if条件分支流程。复杂问题的解决,往往就是条件流程和循环流程的种种组合,下面要讲的多层循环也是这些组合中一种。

 

10.4 多层循环

 

有些问题需要多层循环嵌套才能解决。前面可以多次统计的程序,就使用了两层循环。外层的do...while实现重复统计,内层的while循环实现一次统计。

 

继续分析一些题目:

题三:输出以下内容,要求使用两种方法,第一种方法采用单层循环,第二种方法采用双层循环。

 

123

456

789

 

方法一:

分析:单层循环的思路是:从1输出到9,并且,每当输出三个数字时,多输出一个换行符。

答案:

for(int i=1;i<=9;i++)

{

  cout << i;

  if( i % 3 == 0) //又一次用到“求余”操作。

     cout << endl;

}

 

方法二:

分析:双层循环的思路是:输出三行,每行输出三个数字。

答案:

for(int i=1;i<=3;i++)

{

    for(int j=i;j<=i+3;j++)

    {

        cout << j;

    }

   

    cout << endl;

}

代码中,内层的for用于输出每一行的数字,而外层的for则在每一行输出完成后,输出一个换行符,用于换行.需要另加注意的是,内层循环的条件初始化,和外层循环有关。即这一句:int j=i; 正是。每次开始内层循环时,j的值都将从当前i的值开始。

这道题似乎让人留恋于用单层循环解决一切,因为看上去用双层循环并不是很直观?

 

题四:请用输出以下内容:

 

1

12

123

1234

12345

123456

1234567

12345678

123456789

 

题目刚出,只见一同学噼噼啪啪开始输入代码,并且很快在屏幕上输出正确的内容,他的答案是:

 

cout << "1" << endl;

cout << "12" << endl;

cout << "123" << endl;

cout << "1234" << endl;

cout << "12345" << endl;

cout << "123456" << endl;

cout << "1234567" << endl;

cout << "12345678" << endl;

cout << "123456789" << endl;

 

如果谁在有关循环的作业中交上类似这样的答案,我准备给他一个“鸭蛋”呵。

这道题目,除非跟自已过不去,否则没有人会非要硬去用一层循环来实现(用一层循环不如用上面的“答案”,笨是笨点,却最为直观)。本题使用双层循环来实现实为最佳方法。

 

分析:外层循环用于控制输出9行;内层循环用于输出每行的数字。每一行都是从1开始,但第一行输出1个数字,第二行输出2个,第三行输出3个……

 

答案:

for(int i=1; i<=9; i++)

{

    for(int j=1; j<=i; j++)

    {

       cout << j;

    }

 

   cout << endl;

}

 

看,在这道中,内层循环的条件初始化和外层循环无关,但循环条件判断却和外层的i有关了(j<=i)。当然,这并不是必要条件,但内层循环的条件初始化或条件判断,和外层循环的某些因素有关,这是很多多层循环的解决问题的关键!继续一个经典的题目。

 

题五:请输出以下九九口诀表:

 

1*1=1

1*2=2 2*2=4

1*3=3 2*3=6 3*3=9

1*4=4 2*4=8 3*4=12 4*4=16

1*5=5 2*5=10 3*5=15 4*5=20 5*5=25

1*6=6 2*6=12 3*6=18 4*6=24 5*6=30 6*6=36

1*7=7 2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=49

1*8=8 2*8=16 3*8=24 4*8=32 5*8=40 6*8=24 7*8=56 8*8=64

1*9=9 2*9=18 3*9=27 4*9=36 5*9=45 6*9=36 7*9=63 8*9=72 9*9=81

 

分析:你可以看出,本题和题四有很大的类似,都是要输出一个“三角形”(严格说是梯形?),所以解题思路也大致一样:输出九行。你可能会说,输出九列也可以吧?的确可以,不过由于我们现在使用控制台(DOS)窗口来输出,所以被限定只能由上到下一行一行输出,而不能由左到右一列列输出。

既然是按行输出,我们来看每一行的内容有什么特点:

每一行输出的内容都是: i*j=k,其中k是积,由i和j决定,所以我们可以不必看:

 

第1行:1*1,只有一个,看不出有什么特点。

第2行:1*2 2*2  ……1,2 分别乘以2

第3行: 1*3 2*3 3*3  ……1,2,3分别乘以3

所以,各行的内容的规律是:设当前为第line行,则输出 n*line ,n为1到line.

 

for(int line=1; line <= 9;line++)

{

   for(int n=1; n<=line;line++)

   {

      cout << n << '*' << line << '=' << n * line <<' ';

   }

  cout << endl;

}

 

把line换成i,n换成j,本题的循环控制部分的代码和题四完全一样。

 

理解以上各分析题,最好的方法是实际上机,然后运行,并且最好自已尝试按F8来一步步运行。所以再说以遍,本章内容可以宣告结束,但如果你没有上机操作这些循环题,就不能说你学好本章。

 

10.5 小结及一点问题

 

学习了三种循环流程:while,do...while,for。

 

while在每一遍循环开始时检查条件是否成立,如果一开始条件就不成立,则循环中的语句将一次也没有执行。

 

do...while的特殊之处在于,第一遍循环前,并不检查条件,所以,就算条件根本就不成立,循环也将并执行一次,如:

do

{

  ...

}

while(false);

条件是“false”?这也是条件吗?是的,这也是条件,一个摆明了就是不成立的条件,常见的还有:while(0)。0可以看false。相反的,摆明是真的条件是:while(true)或while(1)等。

 

for 的特殊之处在于,它除了条件判断以外,还明确地留出了条件初始化,条件变化的位置。所以,有关计数的循环最适于用for来实现,请参看课程中用for实现1到100累加的实例。

至于for的各种“变体”,只须了解,以后用得熟了,再去卖弄不迟 :) 。

 

循环就象绕圈子。比如,体育课,跑1200米,跑道一圈400米,所以我们要做的事就是一边跑一边在心里计数(当然要已数,否则老师万一少计一圈,我们可就玩完了),当计数到3圈时,“循环”结束。

在这个例子,条件初始化就将计数设为0;循环的条件则是计数小于3;条件变化则是指在每跑完一圈时,心里将计数加1;至于循环的动作,自然就是跑步了……

用while实现:

 

int js = 0; //js 取意“计数”,而不是“奸商”,也不是“句神”

 

while( js < 3)

{

  跑一圈……;

  js++;

}

 

用do...while实现:

 

int js = 0;

 

do

{

  跑一圈……

  js++;

}

while( js <3);

 

用 for 实现(最适合了)

 

for(int i=0;i<3;i++)

{

   跑一圈……;

}

 

如果,我在跑步时不幸由于体力不支而晕倒……怎么办?下一章见!

[wangjy17908]
添加时间:2008-04-12
版权所有(C)2005-2015