学习编程语言,语法是次要的,思维是主要的。如何把头脑中的想法变成简洁的代码,至关重要。
产生死循环的程序在算法竞赛中是不能通过的,但是解决起来也很简单:检查条件变量是否正常变化,然后检查条件判断是否可以成立。
在不影响结果的情况下,我们应当尽可能减少循环的次数。在枚举时排除掉一定不可能的情况,这样就可以提升效率,加快程序的运行速度。
学习循环语句只需要抓住一点——代码执行顺序!
程序的三种结果:顺序结构、选择结构、循环结构
一、while循环 可以简单理解为循环版的if语句。
If语句是判断一次,如果条件成立,则执行后面的语句,然后停止;
while是每次判断,如果成立,则执行循环体中的语句,否则停止。练习:变量a从1增加到10,每次+1并输出结果,直到结束。
#include<iostream>
using namespace std;
int main(){
int a=0;
while(a<10){
a++;
cout<<a<<endl; //输出从1到10
}
return 0;
}
和分支结构程序设计一样,循环结构(尤其是结构复杂的程序)也应当按照层级加上合适的缩进。这样可以使程序的层次关系比较明显,可读性好。
练习:求1~100中所有数的立方和。
#include<iostream>
using namespace std;
int main(){
int a=1,sum=0; //sum表示和
while(a<=100){
sum+=a*a*a; //每一次循环将a*a*a加到sum
a++;
}
cout<<sum<<endl; //输出25502500
return 0;
}
练习:求斐波那契数列的第n项。f(1)=1, f(2)=1, f(3)=2, f(n)=f(n-1) + f(n-2)。
#include<iostream>
using namespace std;
int main(){
int n;
cin>>n;
int a=1,b=1,i=1;
while(i<n){ //循环条件
int c=a+b;
a=b; //第n项
b=c; //b是第n+1项目
i++;
}
cout<<a<<endl;
return 0;
}
死循环:循环永久执行,无法结束。我们要避免写出死循环。
#include<iostream>
using namespace std;
int main(){
int n=1; //下面是一个死循环
while(n==1) cout<<n<<endl;//只有1句代码,可省略大括号
return 0;
}
二、do while循环
do while循环不常用。 do while语句与while语句非常相似。唯一的区别是,do while语句限制性循环体后检查条件。不管条件的值如何,我们都要至少执行一次循环。
#include<iostream>
using namespace std;
int main(){
int n=1;
do{ //先执行,再检查条件
cout<<n<<endl;
}while(n>1);
return 0;
}
三、for 循环理解for循环的执行顺序:
for (语句1; 语句2; 语句3) { 语句4; }
先执行语句1,且执行1次;然后循环执行:语句2->语句4->语句3->语句2->语句4->语句3……,直到语句2的判断不成立!
注意理解for循环的执行顺序:
(1) 按照上述知识点中关于语句执行过程的讲解,可以看出首先执行i=1,为i赋初值;
(2) 接下来执行i<=10的判断条件;
(3) 如果条件成立,接下来执行cout<<i<<endl (注意:接下来不会继续执行i++);
(4) 执行i++,然后继续判断i<=10是否成立;
(5) 请特别注意,循环结束后 i 的值是多少?
int i;//循环变量
for (i = 1;i <= 10;i++){
cout<<i<<endl;
cout<<“z循环结束 i=”<<i<<endl ; //输出11
(6) 理论上for循环中分号隔开的3条语句都可以没有,但2个分号要保留,代码如下 ( 注意在实际编程中,虽然以下代码语法正确,但并不容易理解,因此尽量不要这样写 )。
int i =1;//循环变量
for( ;i <= 10; ) (
cout<<i<<endl;
i++;
}
练习:变量a从1增加到10,每次+1并输出结果,直到结束。
#include<iostream>
using namespace std;
int main(){
for(int i=1;i<=10;i++){
cout<<i<<endl; //输出从1到10
}
return 0;
}
练习:求 1 * 10 + 2 * 8 + 3 * 6 + 4 * 4:
#include<iostream>
using namespace std;
int main(){
int sum=0;
for(int i=1,j=10;i<=j;i++,j=j-2){//表达式1和3可以有多条
sum+=i*j;
}
cout<<sum<<endl; //输出60
return 0;
}
四、跳转语句
❶ break 可以提前从循环中退出,一般与if语句搭配。例题:判断一个大于1的数是否是质数:
#include<iostream>
using namespace std;
int main(){
int n;
cin>>n;
bool is_prime=true; //假设是质数
for(int i=2;i<n;i++){
if(n%i==0){ //判断是否被i整除
is_prime=false; //不是质数
break; //找到因子,就跳出循环
}
}
if(is_prime) cout<<"yes"<<endl;
else cout<<"no"<<endl;
return 0;
}
❷ continue 可以直接跳到当前循环体的结尾。在需要的地方临时结束循环的当前轮,然后直接进入下一轮的循环。例题:求1~100中所有偶数的和。
#include<iostream>
using namespace std;
int main(){
int sum=0;
for(int i=1;i<=100;i++){
if(i%2==1) continue; //奇数,则进入下一次循环
sum+=i; //偶数加到sum
}
cout<<sum<<endl;
return 0;
}
五、嵌套循环打印九九乘法口诀表:
#include<iostream>
using namespace std;
int main(){
int sum=0;
for(int i=1;i<=9;i++){
for(int j=1;j<=i;j++){
cout<<j<<'*'<<i<<'='<<i*j<<' ';
}
cout<<endl; //每一句之后换行
}
return 0;
}
内外层的循环计数变量不应当是一样的,否则就会发生混乱。
对于外层循环里定义的变量,内层循环也可以访问得到,但是反过来就不可以了。

练习:打印1~100中的所有质数
#include<iostream>
using namespace std;
int main(){
for(int n=2;n<=100;n++){
bool is_prime=true; //假设是质数
for(int i=2;i<n;i++){
if(n%i==0){ //判断是否被i整除
is_prime=false; //不是质数
break; //找到因子,就跳出循环
}
}
if(is_prime) cout<<n<<endl; //输出质数
}
return 0;
}
实际上,各种循环都可以进行嵌套,而且可以嵌套很多层。不过,如果循环嵌套层次过多,而且每层循环都需要较多循环次数时,就可能需要比较久的运行时间,甚至导致超时。
双层嵌套循环的几种形式:
◆ EOF的意义及用法
#include <iostream>
int main(){
int n;
while(scanf("%d",&n) != EOF){ //循环输入n,直到文件结束
}
return 0;
}
EOF,为End Of File的缩写,如上代码所示,当题目要不限次数循环输入数据时,可以参照上面的方法。当上面的程序运行时,如果不加” != EOF”,那么这个程序就是个死循环,会一直运行下去;加上” != EOF”后该程序就不是死循环了,如果在终端不进行输入该程序会自动结束(while的意思就是说当当前输入缓存还有东西时就一直读取,直到输入缓存中的内容为空时停止)。
在这”scanf(“%d”,&n) != EOF” 相当于 “scanf(“%d”,&n) != EOF”,或 “~scanf(“%d”,&n)”, 或”scanf(“%d”,&n) == 1 ” 。scanf的返回值由后面的参数决定。
要注意的是:在终端(黑框)中手动输入时,系统并不知道什么时候到达了“文件末尾”,因此需要用组合键(Ctrl+Z)然后按 Enter 键的方式来告诉系统已经到了EOF。
cin是C++的输入流对象,”>>”是重载的运算符,cin>>的返回值是cin对象。用这个当条件的话,通过检测其流的状态来判断结束;
(1)若流是有效的,即流未遇到错误,那么检测成功;
(2)若遇到文件结束符,或遇到一个无效的输入时,istream对象的状态会变为无效,条件就为假;读取失败的时候,就不能继续读取了,那么读取操作结束。
◆ 局部变量和全局变量的差异
(1)定义位置不同:全局变量定义在main函数的外面,局部变量定义在函数内部;
(2)生命周期不同:局部变量,仅在变量定义时对应的大括号的闭括号中有效;全局变量,在所有函数中都有效;
(3)是否有初值:局部变量定义不赋值,则初始值随机;全局变量定义不赋值,int初值为0,小数初值为0.0,字符类型初值’\0′ , bool初值 false, int a[100]初值都为 0。
#include <bits/stdc++.h>
using namespace std;
int n,a,b,c; //全局变量
int main(){
int x,y,z; //局部变量
for(int i=1;i<=n;i++){} //i 局部变量
}
◆ for循环和while循环的对比
◆ do while循环和while循环的对比
◆ 运算优先级
常见易错点:
1、++i和i++、–i和i–在有多步运算的情况下,i++会先做其他运算,再自增(后加先赋值);++i会先自增,再做其他运算(先加后赋值);
从运行的效率的角度来说,++i比i++的效率会更高一些。
2、scanf/printf 和 cin/cout
在大量的数据读入和输出的程序中 (比如:读入、输出105个整数),scanf、printf的读写效率高于cin、cout多倍。
3、auto关键字 在C++11标准的语法中,auto被定义为自动推断变量的类型。编程时常常需要把表达式的值赋给变量,这就要求声明变量时清楚的知道表达式的类型。然而有些情况是声明的变量的类型我们并不知道。auto可以在声明变量的时候根据变量初始值的类型自动为此变量选择匹配的类型。
在实际编程中我们在明确变量类型情况下,还是使用明确的类型。
4:for循环带冒号的用法1、需要编译器支持C++11及以上的标准
2、形如 for(auto c:s) 的格式,auto可以是别的数据类型比如char,int,const char*等等各类数据类型,可以是自定义的数据类型。c是一个变量名称,可以按变量名规则任意定义;s是一个容器名称,可以是一个数组,可以是string等等。
3、for(auto &c:s) 与 for(auto c:s)的区别1:for(auto c:s)中b为一个容器,效果是利用c遍历并获得s容器中的每一个值,但是c无法影响到s容器中的元素。for(auto &c:s)中加了引用符号,可以对容器中的内容进行赋值,即可通过对c赋值来做到容器s的内容填充。
4、for(auto &c:s)与for(auto c:s)的区别2:使用for(auto &c:s)时,直接引用原字符串进行遍历操作。使用for(auto c:s)时,逻辑上会复制一个s字符串再进行遍历操作。由于复制一个字符串花费了大量的时间,所以第一种用法的程序执行速度要快于第二种用法。
5、在for(auto &c:s)或for(auto c:s)中, auto用于for循环的作用:根据s的数据类型由编译器自动确定c的数据类型。