5.3 循环结构
微视频
在实际应用中,往往会遇到一行或几行代码需要执行多次的情况,这就是代码的循环。几乎所有的程序都包含循环,循环是重复执行的指令,重复次数由条件决定,这个条件称为循环条件,反复执行的程序段称为循环体。一个正常的循环程序具有4个基本要素,分别是循环变量初始化、循环条件、循环体和改变循环变量的值。典型的循环结构流程图如图5-16所示。
图5-16 循环结构流程图
5.3.1 循环结构类型
在C++语言中,为用户提供了4种循环结构类型,分别为while循环、do…while循环、for循环、嵌套循环,具体介绍如表5-2所示。
表5-2 循环结构类型
1.while循环
while循环根据循环条件的返回值来判断执行零次或多次循环体。当逻辑条件成立时,重复执行循环体,直到条件不成立时终止。while循环的语法格式如下:
while(表达式) { 语句块; }
在这里,语句块可以是一个单独的语句,也可以是几个语句组成的代码块。表达式可以是任意的表达式,表达式的值非零时条件取值为true,执行循环;否则,退出循环,程序流将继续执行紧接着循环的下一条语句。
while循环语句的执行流程图如图5-17所示。当遇到while循环时,首先计算表达式的返回值,当表达式的返回值为true时,执行一次循环体中的语句块;循环体中的语句块执行完后,将重新查看是否符合条件,若表达式的值还返回true将再次执行相同的代码,否则跳出循环。while循环的特点:先判断条件,后执行语句。
图5-17 while循环语句的执行流程图
【实例5.8】编写程序,实现100以内自然数的求和,即1+2+3+…+100,最后输出计算结果(源代码\ch05\5.8.txt)。
#include <iostream> using namespace std; int main() { /* 定义变量并初始化 */ int i=1,sum=0; cout <<"100以内自然数求和:"<<endl; /* while 循环语句 */ while(i<=100) { sum+=i; i /* 自增运算 */ } cout <<"1+2+3+…+100="<<sum<<endl; }
程序运行结果如图5-18所示。
图5-18 例5.8的程序运行结果
使用while循环语句时要注意以下几点。
(1)while语句中的表达式一般是关系表达式或逻辑表达式,只要表达式的值为真(非0)即可继续循环。
(2)循环体包含一条以上语句时,应用“{}”括起来,以复合语句的形式出现;否则,它只认为while后面的第1条语句是循环体。
(3)循环前,必须给循环控制变量赋初值,如上例中的“i=1;”。
(4)循环体中,必须有改变循环控制变量值的语句(使循环趋向结束的语句),如上例中的“i++;”,否则循环永远不结束,形成所谓的“死循环”。例如以下代码:
int i=1; while(i<10) printf("while语句注意事项");
因为i的值始终是1,也就是说,永远满足循环条件i<10,所以,程序将不断地输出“while语句注意事项”。要使循环不陷入死循环,必须要给出循环终止条件。
while循环之所以被称为有条件循环,是因为语句部分的执行要依赖于判断表达式中的条件。之所以说其是入口条件,是因为在进入循环体前必须满足这个条件。如果在第一次进入循环体时条件就没有被满足,程序将永远不会进入循环体。例如以下代码:
int i=11; while(i<10) printf("while语句注意事项");
因为i一开始就被赋值为11,不符合循环条件i<10,所以不会执行后面的输出语句。要使程序能够进入循环,必须给i赋比10小的初值。
【实例5.9】编写程序,求数列1/2、2/3、3/4……前20项的和,最后输出计算结果(源代码\ ch05\5.9.txt)。
#include <iostream> using namespace std; int main() { int i; /*定义整型变量i用于存放整型数据*/ double sum=0; /*定义浮点型变量sum用于存放累加和*/ i=1; /*循环变量赋初值*/ while(i<=20) /*循环的终止条件是i<=20*/ { sum=sum+i/(i+1.0); /*每次把新值加到sum中*/ i++; /*循环变量增值,此语句一定要有*/ } cout <<"该数列前20项的和为:"<<sum<<endl; }
程序运行结果如图5-19所示。本实例的数列可以写成通项式:n/(n+1),n=1,2,…,20,n从1循环到20,计算每次得到当前项的值,然后加到sum中即可求出结果。
图5-19 例5.9的程序运行结果
☆大牛提醒☆
while后面不能直接加“;”。如果直接在while语句后面加了分号“;”,系统会认为循环体是空体,什么也不做。后面用“{}”括起来的部分将认为是while语句后面的下一条语句。
2.do…while循环
在C++语言中,do…while循环是在循环的尾部检查它的条件。do…while循环与while循环类似,但是也有区别。do…while循环和while循环的最主要区别如下。
(1)do…while循环是先执行循环体后判断循环条件,while循环是先判断循环条件后执行循环体。
(2)do…while循环的最小执行次数为1次,while循环的最小执行次数为0次。
do…while循环的语法格式如下:
do { 语句块; } while(表达式);
这里的条件表达式出现在循环的尾部,所以循环中的语句块会在条件被测试前至少执行一次。如果条件为真,控制流会跳转回上面的do,然后重新执行循环中的语句块,直到给定条件变为假为止。do…while循环语句的执行流程图如图5-20所示。
图5-20 do…while循环语句的执行流程图
程序遇到关键字do会执行大括号内的语句块,语句块执行完毕,执行while关键字后的布尔表达式,如果表达式的返回值为true,则向上执行语句块,否则结束循环,开始执行while关键字后的程序代码。
使用do…while循环语句应注意以下几点。
do…while循环语句是先执行循环体语句,后判断循环终止条件,与while循环语句不同。两者的区别在于:当while后面表达式开始的值为0(假)时,while语句的循环体一次也不执行,而do…while语句的循环体至少要执行一次。
(1)在书写格式上,循环体部分要用“{}”括起来,即使只有一条语句也如此;do…while循环语句最后以分号结束。
(2)通常情况下,do…while循环语句是从后面控制表达式退出循环。但它也可以构成无限循环,此时要利用break语句或return语句直接从循环体内跳出循环。
【实例5.10】编写程序,实现100以内自然数的求和,即1+2+3+…+100,最后输出计算结果(源代码\ch05\5.10.txt)。
#include <iostream> using namespace std; int main() { /* 定义变量 */ int i=1,sum=0; cout<<"100以内自然数求和:"<<endl; /* do…while循环语句 */ do { sum+=i; i++; } while(i<=100); cout<<"1+2+3+…+100="<<sum<<endl; }
程序运行结果如图5-21所示。
图5-21 例5.10的程序运行结果
【实例5.11】编写程序,根据输入的两个数,计算两个数的最大公约数(源代码\ch05\5.11.txt)。
#include <iostream> using namespace std; int main() { int m,n,r,t; int m1,n1; cout<<"请输入第1个数:"<<endl; cin>>m; /*由用户输入第1个数*/ cout<<"请输入第2个数:" <<endl; cin>>n; /*由用户输入第2个数*/ m1=m;n1=n; /*保存原始数据供输出使用*/ if(m<n) {t=m;m=n;n=t;} /*m和n交换值,m存放大值,n存放小值*/ do /*使用辗转相除法求得最大公约数*/ { r=m%n; m=n; n=r; }while(r!=0); cout<<m1<<"和"<<n1<<"的最大公约数是"<<m<<endl; }
保存并运行程序,从键盘上输入任意两个数,按Enter键,即可计算它们的最大公约数。程序运行结果如图5-22所示。
图5-22 例5.11的程序运行结果
在本实例中,求两个数最大公约数的具体方法如下。
(1)比较两数,并使m大于n。
(2)将m作为被除数,n作为除数,两数相除后,余数为r。
(3)将m←n,n←r。
(4)若r=0,则m为最大公约数,结束循环。若r≠0,执行步骤(2)和步骤(3)。
由于在求解过程中m和n已经发生了变化,因此要将它们保存在另外两个变量m1和n1中,以便输出时可以显示这两个原始数据。
如果要求两个数的最小公倍数,只需要将两个数相乘再除以最大公约数,即m1×n1/m即可。
3.for循环
for循环和while循环、do…while循环一样,可以循环重复执行一个语句块,直到指定的循环条件返回值为假。for循环的语法格式如下:
for(表达式1;表达式2;表达式3) { 语句块; }
其主要参数说明如下。
(1)表达式1为赋值语句,如果有多个赋值语句可以用逗号隔开,形成逗号表达式。此为循环四要素中的循环变量初始化。
(2)表达式2返回一个布尔值,用于检测循环条件是否成立。此为循环四要素中的循环条件。
(3)表达式3为赋值表达式,用来更新循环控制变量,以保证循环能正常终止,循环四要素中的改变循环变量的值。
for循环的执行过程如下。
(1)计算表达式1,为循环变量赋初值。
(2)计算表达式2,检查循环控制条件,若表达式2的值为true,则执行一次循环体语句;若为false,终止循环。
(3)执行完一次循环体语句后,计算表达式3,对循环变量进行增量或减量操作,再重复第2步操作,进行判断是否要继续循环。
使用for循环语句应注意以下几点。
(1)表达式1先被执行,且只会执行一次。这一步允许用户声明并初始化任何循环控制变量。用户也可以不在这里写任何语句,只要有一个分号出现即可。
(2)判断表达式2。如果为真,则执行循环主体。如果为假,则不执行循环主体,且控制流会跳转到紧接着for循环的下一条语句。
(3)在执行完for循环主体后,控制流会跳回表达式3语句。该语句允许用户更新循环控制变量,可以留空,只要在条件后有一个分号出现即可。
(4)最后条件再次被判断。如果为真,则执行循环,这个过程(循环主体,然后增加步值,再重新判断条件)会不断重复。在条件变为假时,for循环终止。
for循环语句的执行流程图如图5-23所示。
图5-23 for循环的语句的执行流程图
☆大牛提醒☆
C++语言不允许省略for语句中的3个表达式,否则会出现死循环现象。
【实例5.12】编写程序,实现100以内自然数的求和,并输出结果(源代码\ch05\5.12.txt)。
#include <iostream> using namespace std; int main() { /* 定义变量 */ int i,sum=0; cout<<"100以内自然数求和:"<<endl; /* for循环语句 */ for(i=1;i<=100;i++) { sum+=i; } cout<<"1+2+3+…+100="<<sum<<endl; }
程序运行结果如图5-24所示。
图5-24 例5.12的程序运行结果
☆大牛提醒☆
通过上述实例可以发现,while循环、do…while循环和for循环有很多相似之处,这三种循环都可以互换。
如果条件永远不为假,则循环将变成无限循环。for循环在传统意义上可用于实现无限循环。若构成for循环的三个表达式中任何一个都不是必需的,用户可以将某些条件表达式留空来构成一个无限循环。例如,下面一段代码。
#include <iostream> using namespace std; int main() { for( ; ; ) { cout<<"该循环会永远执行下去!"; } }
当条件表达式不存在时,它被假设为真。用户也可以设置一个初始值和增量表达式,但是一般情况下,C++程序员偏向于使用for( ; ; )结构来表示一个无限循环。
☆大牛提醒☆
按Ctrl+C键可以终止一个无限循环。
4.嵌套循环
在一个循环体内又包含另一个循环结构,称为嵌套循环。如果内嵌的循环中还包含循环语句,这种称为多层循环。while循环、do…while循环和for循环语句之间可以相互嵌套。
1)嵌套for循环
在C++语言中,嵌套for循环的语法格式如下:
for (表达式1;表达式2;表达式3) { 语句块; for (表达式1;表达式2;表达式3) { 语句块; … } … }
嵌套for循环语句的执行流程图如图5-25所示。
图5-25 嵌套for循环语句的执行流程图
【实例5.13】编写程序,在屏幕上输出九九乘法表(源代码\ch05\5.13.txt)。
#include <iostream> #include <iomanip> using namespace std; int main() { int i, j; /* 外层循环,每循环1次,输出一行 */ for(i = 1; i <= 9; i++) { /* 内层循环,循环次数取决于i*/ for(j = 1; j <= i;j++) { cout << setw(2) << j << "*" << i << "=" <<setw(2) << i * j ; } cout << endl; } }
程序运行结果如图5-26所示。
图5-26 例5.13的程序运行结果
2)嵌套while循环
在C++语言中,嵌套while循环的语法格式如下:
while(条件1) { 语句块; while;(条件2) { 语句块; … } … }
嵌套while循环语句的执行流程图如图5-27所示。
图5-27 嵌套while循环语句的执行流程图
【实例5.14】编写程序,在屏幕上输出由*组成的形状(源代码\ch05\5.14.txt)。
#include <iostream> using namespace std; int main() { int i = 1, j; while (i <= 5) { j = 1; while (j <= i) { cout <<"*" ; j++; } cout << endl; i++; } }
程序运行结果如图5-28所示。
图5-28 例5.14的程序运行结果
3)嵌套do…while循环
在C++语言中,嵌套do…while循环的语法格式如下:
do { 语句块; do { 语句块; … }while (条件2); … }while (条件1);
嵌套do…while循环语句的执行流程图如图5-29所示。
图5-29 嵌套do…while循环语句的执行流程图
【实例5.15】编写程序,在屏幕上输出由*组成的形状(源代码\ch05\5.15.txt)。
#include <iostream> using namespace std; int main() { int i=1,j; do { j=1; do { cout<<"*"; j++; }while(j <= i); i++; cout <<endl; }while(i <= 5); }
程序运行结果如图5-30所示。
图5-30 例5.15的程序运行结果
5.3.2 循环控制语句
循环控制语句可以改变代码的执行顺序,编程时利用这些语句可以实现代码的跳转。C++语言提供的循环控制语句有break语句、continue语句和goto语句等,如表5-3所示。
表5-3 C++语言中的循环控制语句
1.break语句
break语句只能应用在switch语句和循环语句中,如果出现在其他位置会引起编译错误。C++语言中break语句有以下两种用法。
(1)当break语句出现在一个循环内时,循环会立即终止,且程序流将继续执行紧接着循环的下一条语句。
(2)break语句可用于终止switch语句中的一个case。
☆大牛提醒☆
如果用户使用的是嵌套循环(即一个循环内嵌套另一个循环),break语句会停止执行最内层的循环,然后开始执行该语句块后的下一行代码。
C++语言中break语句的语法结构如下:
break;
break语句在程序中的应用流程图如图5-31所示。
图5-31 break语句应用流程图
break语句用在循环语句循环体内的作用是终止当前的循环语句。例如:
(1)无break语句
int sum=0, number; cin>>number; while (number !=0){ sum+=number; cin>>number; }
(2)有break语句
int sum=0, number; while (1) { cin>>number; if(number==0) break; sum+=number; }
以上这两段程序产生的效果是一样的。需要注意的是,break语句只是跳出当前的循环语句。对于嵌套的循环语句,break语句的功能是从内层循环跳到外层循环。例如:
int i=0, j, sum=0; while(i<10) { for( j=0; j<10; j++) { sum+=i+j; if(j==i) break; } i++; }
本例中的break语句执行后,程序立即终止for循环语句,并转向for循环语句的下一个语句(即while循环体中的i++语句),继续执行while循环语句。
【实例5.16】编写程序,使用while循环输出10~20的整数变量a。注意在内循环中,当输出到15时,使用break语句跳出循环(源代码\ch05\5.16.txt)。
#include <iostream> using namespace std; int main() { /*局部变量定义*/ int a =10; /*while循环执行*/ while(a<20) { cout<<"a的值:"<<a<<endl; a++; if(a>15) { /*使用break语句终止循环*/ break; } } }
程序运行结果如图5-32所示。
图5-32 例5.16的程序运行结果
☆大牛提醒☆
在嵌套循环中,break语句只能跳出离自己最近的那一层循环。
2.continue语句
C++语言中的continue语句有点像break语句。但它不是强制终止,continue会跳过当前循环中的代码,强迫开始下一次循环。对于for循环,continue语句执行后自增语句仍然会执行。对于while循环和do…while循环,continue语句重新执行条件判断语句。
C++语言中continue语句的语法结构如下:
continue;
continue语句在程序中的应用流程图如图5-33所示。
图5-33 continue语句应用流程图
通常情况下,continue语句总是与if语句联系在一起,用来加速循环。假设continue语句用于while循环语句,要求在某个条件下跳出本次循环,一般形式如下:
while(表达式1) { … if(表达式2) { continue; } … }
这种形式和前面介绍的break语句用于循环的形式十分相似,两者的区别是:continue只终止本次循环,继续执行下一次循环,而不是终止整个循环;break语句则是终止整个循环过程,不会再去判断循环条件是否还满足。在循环体中,continue语句被执行后,其后面的语句均不再执行。
【实例5.17】编写程序,输出100~120所有不能被3和7同时整除的整数(源代码\ch05\ 5.17.txt)。
#include <iostream> using namespace std; int main() { int i,n=0; /*n计数*/ for(i=100;i<=120;i++) { if(i%3==0&&i%7==0) /*如果能同时整除3和7,不打印*/ { continue; /*结束本次循环未执行的语句,继续下次判断*/ } cout <<"\t" << i; n++; if(n%5==0) /*5个数输出一行*/ cout <<endl; } }
程序运行结果如图5-34所示。可以看出,输出的这些数值不能同时被3和7整除,并且每5个数输出一行。
图5-34 例5.17的程序运行结果
在本实例中,只有当i的值能同时被3和7整除时,才执行continue语句,跳过后面的语句,直接判断循环条件i<=120,再进行下一次循环;只有当i的值不能同时被3和7整除时,才执行后面的语句。
一般来说,它的功能可以用单个的if语句代替。如本例可改为:
if(i%3==0&&i%7==0) /*如果能同时整除3和7,不打印*/ { printf("%d\t",i); }
这样编写比用continue语句更清晰,又不用增加嵌套深度。因此,如果能用if语句,就尽量不要用continue语句。
3.goto语句
C++语言中的goto语句允许程序无条件地转移到同一函数体内被标记的语句。goto是“跳转到”的意思,也就是说,使用它可以跳转到另一个加上指定标签的语句。goto语句的语法结构如下:
goto [标签]; … [标签]:语句块;
在这里,标签可以是任何除C++关键字以外的纯文本,可以设置在程序中goto语句的前面或者后面。例如,使用goto语句实现跳转到指定语句的代码如下。
int i = 0; goto a; i = 1; a : printf("%d",i);
以上代码的含义是,第一行定义变量i,第二行跳转到标签为a的语句,接下来就输出i的结果。可以看出,第三行是无意义的,因为没有被执行,跳过去了,所以输出的值是0,而不是1。
goto语句在程序中的应用流程图如图5-35所示。
图5-35 goto语句应用流程图
☆大牛提醒☆
goto语句并不是一定要跳转到后面的语句,也就是说,goto语句还可以跳到前面去执行。
【实例5.18】编写程序,实现100以内自然数的求和,即1+2+3+…+100,最后输出计算结果(源代码\ch05\5.18.txt)。
#include <iostream> using namespace std; int main() { int i,sum=0; i=1; loop: if(i<=100) /*标记loop标签*/ { sum=sum+i; i++; goto loop; /*如果i的值不大于100,则转到loop标签处开始执行程序*/ } cout<<"1+2+3+…+100="<<sum<<endl; }
程序运行结果如图5-36所示,即可显示1~100整数之和。
图5-36 例5.18的程序运行结果
☆大牛提醒☆
在任何编程语言中,都不建议使用goto语句。因为它会使程序的控制流难以跟踪,使程序难以理解和难以修改,所以原使用goto语句的程序尽量改写成不需要使用goto语句的方式。