3.循环结构
学习本章之前:循环结构是结构化程序设计的三种基本结构之一,在程序设计中对于那些需要重复执行的操作应该采用循环结构来完成,利用循环结构处理各类重复操作既简单又方便。所以相较于前面两种结构的难度会有所提升,所以在此章节的代码和语法知识更需要花时间消化并且上机操作❤️
- 使用循环可以多次重复地执行多条语句,这里的“多条语句”称为循环体。在C语言中,可以使用三种循环,分别是:while、do…while、for
- 在这些语句中,循环体被重复执行的次数由循环条件控制,称为控制表达式(controlling expression)。
- 这是一个标量类型的表达式,也就是说,它属于一个算术表达式或指针表达式。如果控制表达式的值不等于 0,循环条件为 true,反之,循环条件为 false。
- 语句 break 和 continue 用于在一次循环还未执行完时,跳转出循环或返回到循环头部。
📍 无论是 while,do…while 还是 for,他们都具有四要素:
循环变量初始化
:循环的起始位置循环变量迭代
:所执行的步长,统计变化情况,识别是否继续循环条件判断
:标记循环继续的条件循环操作(循环体)
:循环所执行的内容
3.1 for 循环
3.1.1 基本语法
for(循环变量初始化;循环条件判断;循环变量迭代) { 语句1; 语句2; …………; }
🚩在一个典型的 for 循环中,在循环体顶部,下述三个动作需要执行:
- 表达式 1:
循环变量初始化
只计算一次。在计算控制表达式之前,先计算一次表达式 1,以进行必要的初始化,后面不再计算它。 - 表达式 2:
循环条件判断
每轮循环前 都要进行循环条件判断,以判断是否需要继续本轮循环。当控制表达式的结果为false
,结束循环。 - 表达式 3:
循环变量迭代
,也叫调节器
调节器(例如计数器自增)在每轮循环结束后 且表达式 2 计算前 执行。即,在运行了调节器后,再执行表达式 2进行判断。
📍 执行过程如图:
📝 我们来举个例子
#include<stdio.h> int main() { int i; /*在这里面: 1. 循环变量初始化:i = 0 2. 循环条件判断:i < 3 3. 循环变量迭代:i++ 4. 循环体:printf("print the value of i =%d\n", i); */ for(i = 0; i < 3; i++) { printf("print the value of i =%d\n", i); } return 0; }
运行结果:
📍 一次循环的执行过程:
- 循环变量赋初值: 将 i 的初始值变成 0
- 循环条件判断: 判断 i 是否小于3,若小于3则为true,其它为false
- 循环变量值变化: i 的值自动加1
3.1.2 中途终止循环 - return&break
在
第 3.5 节
会再次介绍 break,这里预热一波
1️⃣ 方式一:return
#include<stdio.h> int main() { int i; for(i = 0; i < 3; i++) { if(i == 1) { return 0;//直接退出程序,这也是中途终止循环的方式 }else { printf("%d", i); } } printf("My love end"); return 0; }
💬 当 i==1 时直接退出程序,因此这道题的输出结果就是 0 。因为 i为1的时候就直接退出程序了,并未printf打印结果,也并未打印My love end
。注意与第二种方式 break
进行比较哦。
2️⃣ 方式二:break
break语句用于终止某条语句块的执行,一般使用在 switch或者 循环(for,while,do…while)中,表示退出 switch 或
退出
循环。
#inlcude<stdio.h> int main() { int i; for(i = 0; i < 3; i++) { if(i == 1) { break;//退出for循环,但并未退出程序 }else { printf("%d", i); } } printf("My love end"); return 0; }
💬 当 i==1 时直接退出for循环,但并未退出程序,因此控制台的打印结果为0My love end
。
3.1.3 跳过本次循环,进入下次循环 - continue
在第
3.5
节会再次介绍continue,这里预热一波
除了break 语句可以结束循环体外,这里再介绍一个continue语句,这个语句跟break语句一样,也可以结束循环体,但不同的是,它只是结束本次循环,循环体会跳过continue后面的语句,直接去再次判断循环条件,进行下一次的循环操作。
📝 举个例子
#include<stdio.h> int main() { int i; for(i = 0; i < 3; i++) { //即当i等于1的时候,执行 continue语句,结束本次循环 //即当i等于1的时候不会打印信息,直接执行下一次循环 if(i == 1) { continue; } printf(" print the value of i = %d\n", i); } return 0; }
运行结果如下:
通过以上例子,我们可以看到,运用 break
和 continue
语句,我们可以更加灵活的使用循环语句来控制程序的流程。
3.1.4 🚩 一个思考
for(表达式1;表达式2;表达式3) { 循环操作; }
我们已经知道了for循环的基本结构,但我们一定要遵循那个位置标准吗?这么说吧,我们一定要把循环变量初始化
放在表达式1
吗,一定要把循环条件判断
放在表达式2
的位置吗,一定要把循环变量迭代
放在表达式3
的位置吗?
✏️ 不是的,这些只是一些规范,你可以遵循,也可以不遵循。我们来举个例子,把位置改一改。
#include<stdio.h> int main() { int i = 0; //循环变量初始化 for(;i < 3;)//表达式1和表达式2的位置空缺,甚至我们把 i < 3 的位置改到循环体中也是没问题的 { printf("%d\n",i); i++; //循环变量迭代 } }
于是我们发现了,其实表达式1,2,3都可以不放任何东西,可以放到其它位置的。再来看一个更特殊的:
#include<stdio.h> int main() { for(;;)//三个位置什么都不放,但两个分号无论如何是一定都要写的 { printf("I love you ,软件协会"); } }
你可以发现,循环变量初始化
、循环条件判断
、循环变量迭代
都没有,而且你应该意识到这个for循环居然无法退出循环(可以自己运行一下看看),这叫做**死循环**。这是我们必须避免的,在程序中绝对不能够出现死循环,带给程序的伤害比拒绝你表白的女孩给你的伤害更大!
3.2 while 循环
3.2.1 基本语法
循环变量初始化; while(循环条件判断) { 循环体; 循环变量迭代; }
- 在while循环前,先进行循环变量初始化。
- 再判断while后边括号内的表达式是否为真,若为真即执行大括号内的语句,若为假,则跳过while循环结构执行大括号下方的第一条语句。
- 若为真,当执行完大括号内语句后,再次回到
2
去判断,执行。 - 直到while后小括号内表达式的表达式为假,结束循环。
📍 注意:若在while的大括号内执行了 break
语句,则立刻结束循环结构,开始执行大括号外下方的第一条语句。
3.2.2 实例演示
📝 例子1:
#include <stdio.h> int main() { int a = 5, b = 10; while(b > a) //即若b > a 为真就执行大括号内的语句, { //若为假则执行大括号下方语句 printf("while looping a = %d, b = %d\n", a, b); a++; } printf("while loop over\n"); return 0; }
运行结果:
即当,a的值等于10时,b>a 不成立,循环结束。
📝 例子2:
#include <stdio.h> int main() { int a = 5, b = 10; while(b > a) //即若b > a 为真就执行大括号内的语句, { //若为假则执行大括号下方语句 printf("while looping a = %d, b = %d\n", a, b); if(a == 8) { break; //如果a等于8跳出while循环,注意哦,如果是return则就是结束整个程序 } a++; } printf("while loop over\n"); return 0; }
运行结果如下:
将例子1和例子2分别执行一下,查看打印输出信息的不同,体会一下while循环的使用,以及 break 的用法。
3.2.3 while死循环
不多说明,上代码演示最简单的while死循环,细品。
#include<stdio.h> int main() { while(true) { } }
3.2.4 注意事项
- 循环条件判断必须返回一个
布尔值
的表达式 - while循环是先循环条件判断再执行大括号中循环操作
3.3 do…while 循环
3.3.1 基本语法
不像 for
和 while
循环,它们是在循环头部 检查循环条件。在 C 语言中,do…while
循环是在循环的尾部 检查它的条件。
do…while 循环与 while 循环类似,但是 do…while 循环会确保至少执行一次循环。
循环变量初始化; do { 循环操作; 循环变量迭代; }while(循环条件判断);
- 首先执行大括号内语句
- 判断while后边括号内的表达式是否为真,若为真回到第一步,若为假,则退出while循环结构,执行大括号下方的第一条语句。
3.3.2 实例演示
#include<stdio.h> //输出结果:012【3】 int main() { int i = 0;//循环变量初始化 do { printf("%d", i);//循环操作 i++;//循环变量迭代 } while (i < 3);//循环条件判断 printf("【%d】", i); }
3.3.3 注意事项
- 循环条件判断必须返回一个
布尔值
的表达式 - do…while循环是先执行大括号中的循环操作再进行循环条件判断,因此循环操作会至少执行一次。
- 注意
while(循环条件判断)
的后面有一个;
,千万不要忘记写哦。
3.4 嵌套循环
3.4.1 基本介绍
- 将一个循环放在另一个循环体内,就形成了嵌套循环,其中
for
,while
,do...while
均可以作为外层循环和内层循环,建议一般使用两层即可,最多不要超过三层,否则代码的可读性很差。 - 实际上嵌套循环就是把内层循环当成外层循环的循环体,当只有内层循环的循环条件为false时,才会完全跳出内层循环,才可以结束外层的当次循环,开始下一次循环。
3.4.2 实例演示
📝 示例1
#include<stdio.h> int main() { for (int i = 1; i <= 3; i++)//外循环 { for (int j = 1; j <= 4; j++)//内循环 { printf("i = %d ; j = %d\n", i, j); } } }
📝 示例2:输出三三乘法表
#include<stdio.h> //三三乘法表 int main() { for (int i = 1; i <= 3; i++)//外循环 { for (int j = 1; j <= i; j++)//内循环 { printf("%d * %d = %d\t", i, j, i * j);// \t是水平制表符,即向右移动8个单位 } printf("\n"); } }
运行结果:
3.5 跳转控制语句
循环控制语句改变你代码的执行顺序。通过它你可以实现代码的跳转。
📍 C 提供了下列的循环控制语句。
控制语句 | 描述 |
break 语句 | 终止循环或 switch 语句,程序流将继续执行紧接着循环或 switch 的下一条语句。 |
continue 语句 | 告诉一个循环体立刻停止本次循环迭代,重新开始下次循环迭代。 |
goto 语句 | 将控制转移到被标记的语句。但是不建议在程序中使用 goto 语句。 |
3.5.1 break
C 语言中 break 语句有以下两种用法:
- 当 break 语句出现在一个循环内时,循环会立即终止,且程序流将继续执行紧接着循环的下一条语句。
- 它可用于终止 switch 语句中的一个 case。
📍如果小伙伴使用的是嵌套循环(即一个循环内嵌套另一个循环),break 语句会退出离自己最近的那层循环,然后开始执行该块之后的下一行代码。
3.5.2 continue
- C 语言中的 continue 语句有点像 break 语句。但它不是强制终止,continue 会跳过当前循环中的代码,强迫开始下一次循环。
- 对于 for 循环,continue 语句执行后自增语句仍然会执行。对于 while 和 do…while 循环,continue 语句重新执行条件判断语句。
3.5.3 goto
💬goto语句在此不要求小伙伴们掌握,只需要了解,知道有这么个东西,并且要求大家非必要不使用goto语句。
📍在任何编程语言中,都不建议使用 goto 语句。因为它使得程序的控制流难以跟踪,使程序难以理解和难以修改。任何使用 goto 语句的程序可以改写成不需要使用 goto 语句的写法。原因如下:
- goto语句是低级语言的表征。它很灵活,灵活到没有任何拘束,在函数体内直来直往。函数体内可能含有一些嵌套的循环,这就意味着goto可以跳进跳出循环而无所顾忌。当程序比较复杂时很容易造成程序流程的混乱。
- 滥用goto语句,程序无规律,可读性差。在团队开发中影响效率,以后调试和维护程序的过程会令同事和自己都头秃。
任何事物都有两面性,goto语句灵活性如果在适当的地方发挥出来确实非常有用的,毕竟现在有些地方需要无条件的跳转语句。尤其在汇编语言中,如果不使用类似于goto语句的jmp指令,那么其就无法实现循环和条件分支。所以在汇编语言中,goto语句用处还是很大的。使用goto可以使程序变得更加可扩展。当程序需要在错误处理时释放资源时,统一到goto处理最方便。这也是为什么很多大型项目,开源项目,包括Linux,都会大量的出现goto来处理错误!
但现在的编程趋势是要模块化、结构化、所以大多书上已经不建议使用无条件分支的goto语句了,尽管现在大多数语言还在支持它,但还是少用为妙,尤其是像C语言小白玩家,还是瑟瑟发抖的乖乖用break慢慢跳吧。
3.5.4 return
return 使用在方法中,表示跳出/退出所在的方法。如果 return 写在 main 方法中,则会退出程序。