使用循环结构编程解决问题时,while循环和算法的流程图是一一对应的,最容易理解。除了while循环,C++还有高度结构化的for循环和与while相似的do...while循环。
一、for循环
首先来看两段功能相同的while循环和for循环程序:
#include<iostream> using namespace std; int main() { int i; i = 1; while(i<=5){ cout<<"Hello"<<endl; i++; } return 0; }
#include<iostream> using namespace std; int main() { int i; //for比while更精简,高度结构化 for(i=1;i<=5;i++){ cout<<"Hello"<<endl; } return 0; }
for循环的使用格式与while循环的对应关系如下(注意for循环()中是两个分号隔开了三条语句):
for(①;②;③){ ④; }
①; while(②){ ④; ③; }
可见for循环和while循环是相通的,不过for循环整合得更精简,其执行流程如右图所示,对①②③④语句具体功能描述后,for循环的使用格式如下:
for(控制变量初始化;循环条件;控制变量改变语句){ 循环体; }
可见for循环是一种“高度结构化”的循环语句,就像一个功能模块一样,for循环不同位置的语句在其自动执行的流程图中发挥不同的作用。而且for循环中涉及到循环控制变量的语句集中在for后面的()中,所以读了for循环的头部就能够明确循环执行的具体流程,而while往往要读到循环体中修改控制变量值的语句才行,这也是for循环比较while循环的优势。
for循环和while循环是相通的,可以将for循环改写成while循环,也可以将while循环改写成for循环。一般地,要解决的问题循环次数明确的时候,习惯使用for循环;循环条件明确的时候,习惯使用while循环。
来看一个例子,计算\(1+2+3+...+100\)(也就是\(\sum\limits_{i=1}^{100}i\))的结果。如果不使用高中数学的“等差数列求和公式”,大家应该能联想到前面介绍的累加器:
#include<iostream> using namespace std; int main() { int s = 0; s += 1; s += 2; s += 3; //... s += 100; cout<<s; return 0; }
这里的100条累加语句很显然应该借助循环结构实现,累加语句的形式都是 s += ?;
,那么这样的语句应该作为重复执行100次的for循环的循环体(可以很容易总结出重复执行n次的for循环头部可以写出for(i=1;i<=n;i++)
):
int i,s = 0; for(i=1;i<=100;i++){ s += ?; } cout<<s;
那么循环体中的s += ?;
中?处应该填写什么内容呢?再来分析100次循环执行语句:第1次循环是 s += 1;
第2次循环是 s += 2;
第3次循环是 s += 3;
……第100次循环是 s += 100;
,那么第i次循环应该是 s += i;
。大家要注意这一个找规律并抽象归纳的过程,以后我们再探讨循环执行流程就应该说第i次循环执行什么操作,而不是停留在分析具体的第1次、第2次……循环执行什么操作。这样完整的程序代码如下:
#include<iostream> using namespace std; int main() { int i,s = 0; for(i=1;i<=100;i++){ s += i; //第i次循环:s累加上i } cout<<s; return 0; }
分析变量i的作用,可知其首先作为循环的控制变量,控制循环的执行流程;此外在循环体中变量i还参加了计算。
再来看一个例子:指定正整数\(n\),计算\(n\)的阶乘: \(n! = 1 \times 2 \times 3 \times ... \times n\)(也就是 \(n! = \prod\limits_{i=1}^{n}i\))
分析:这里应该使用累乘器来计算\(n!\)。首先输入正整数\(n\),累乘器变量\(t\)初值赋值为1,使用for实现n次循环,循环体中实现累乘:
#include<iostream> using namespace std; int main() { int n; //计算n!,n值即使不大,但n!可能很大,最好使用long long long long t = 1; cin>>n; for(int i=1;i<=n;i++){ t *= i; //第i次循环:t累乘上i } cout<<t; return 0; }
参照上面的程序,尝试编程完成下面的计算:
- 计算\(1^2\)+\(2^2\)+\(3^2\)+...+\(100^2\)(也就是\(\sum\limits_{i=1}^{100}i^2\))的结果
- 计算\(1\)+\(\frac{1}{2}\)+\(\frac{1}{3}\)+...+\(\frac{1}{100}\)(也就是\(\sum\limits_{i=1}^{100}\frac{1}{i}\))的结果(注意累加器变量的数据类型,注意
整数/整数
结果是整数!)
二、do...while循环
首先来对比while循环和do...while循环的流程图:
从流程图可以看出来,while循环是先判断条件是否成立,条件成立才执行循环体;do...while循环是先执行循环体,然后判断条件是否成立,如果成立继续执行循环体然后再判断。
#include<iostream> using namespace std; int main() { int i; i = 1; while(i<=5){ cout<<"Hello"<<endl; i++; } return 0; }
#include<iostream> using namespace std; int main() { int i; i = 1; do{ cout<<"Hello"<<endl; i++; }while(i<=5); //;不能少 return 0; }
while循环是当条件成立时一直执行循环体,do...while循环是执行循环体后判断是否再次重复执行循环体。一般情况下,当循环控制变量初始值相同、循环条件相同、循环体相同时,while循环和do...while循环的效果几乎是相同的。while循环有可能不会执行循环体(循环的条件上来就不成立),而do...while循环会至少执行一次循环体。
三、goto语句实现循环
首先说明,这里只是兴趣扩展,简单介绍一下goto语句以及使用goto语句实现循环。在实际编程中,不要随意使用goto语句,并且应该避免使用goto语句。具体原因可以点击 这里 阅读一篇博文。
#include<iostream> using namespace std; int main() { int i = 1; label: //在这一行作了一个标记,标记名称为label cout<<"Hello World"<<endl; i++; if(i<=5){ goto label; //goto意思是前往,语句的作用是跳转到label标记处 } return 0; }
四、循环控制变量的命名
仔细分析前面例题参考代码,循环控制变量习惯使用 \(i,j,k\) 这些变量。这只是惯例,就像符号常量一般全大写一样,遵循这样的惯例可以一定程度增强程序的可读性。