第 12 节 · 第二部分 流程、方法与数据

循环

循环就是条件为真时一遍遍执行同一段代码;条件放前面(while/for)可能一次都不执行,放后面(do...while)至少一次;break 跳出当前这一层,continue 跳过这一圈。

时长 7:45授课计划第 4 周

学完这一节,你能

讲义

跟着视频的顺序写。每行代码都有注释,代码和运行结果都是实际运行得到的。

1为什么要循环

程序一般是一句接一句、从上往下执行的;想让同一段代码重复执行很多遍,就要用循环。每次重复执行的那一块代码叫循环体。

2while 循环

while 先看条件,条件成立才执行循环体;执行完再回来看条件,直到条件不成立。

C# · 第 7-13 行
7int i = 1;// i 从 1 开始
8while (i <= 3)// 每圈先看条件:i 小于等于 3 吗?
9{// while 循环体开始
10 Console.WriteLine("第 " + i + " 次");// i = 1、2、3 时各打印一行
11 i++;// i 加一(i++ 就是 i = i + 1);i 变成 4 时条件不成立
12}// while 循环体结束,回到条件
13Console.WriteLine("循环结束");// 退出循环后执行
查看完整代码(15 行)
C#
1using System;// 引入 System 命名空间,Console 在这里
2
3class Program// 定义 Program 类
4{// Program 类开始
5 static void Main()// 程序入口 Main 方法
6 {// Main 开始
7 int i = 1;// i 从 1 开始
8 while (i <= 3)// 条件:i 小于等于 3
9 {// while 循环体开始
10 Console.WriteLine("第 " + i + " 次");// 打印第几次
11 i++;// i 加一
12 }// while 循环体结束
13 Console.WriteLine("循环结束");// 循环后面的语句
14 }// Main 结束
15}// Program 类结束
运行结果
第 1 次
第 2 次
第 3 次
循环结束

很多人会忘了在循环体里改变 i。去掉 i++,i 永远是 1,条件永远成立,“第 1 次”会一直打印下去,这就是无限循环:

C# · 第 8-11 行
8while (i <= 3)// i 一直是 1,条件永远成立
9{// while 循环体开始
10 Console.WriteLine("第 " + i + " 次");// 一直打印“第 1 次”
11}// while 循环体结束:没有 i++,i 不会变

3do...while 循环

do...while 正好反过来:先执行循环体,最后才看条件,所以循环体至少执行一次。下面 n 是 5,两个循环的条件都是 n < 3。

C# · 第 8-17 行
8while (n < 3)// while 先看条件:5 < 3 不成立
9{// while 循环体开始
10 Console.WriteLine("while 执行了");// 一次也不执行
11 n++;// 一次也不执行
12}// while 循环体结束
13do// do:先执行,不看条件
14{// do 循环体开始
15 Console.WriteLine("do...while 执行了");// 先打印一次
16 n++;// n 变成 6
17} while (n < 3);// 最后看条件:6 < 3 不成立,退出(注意结尾有分号)
运行结果
do...while 执行了

4for 循环

for 把管理循环变量的三件事写在同一行,用分号隔开:初始化(开始时做一次)、条件(每圈开始前检查)、更新(每圈结束后执行)。三件事写在一起,就不容易忘了改变量。

C# · 第 7-11 行
7for (int i = 1; i <= 3; i++)// 初始化 i = 1;条件 i <= 3;每圈结束后 i++
8{// for 循环体开始
9 Console.WriteLine("第 " + i + " 次");// 打印第 1、2、3 次
10}// for 循环体结束
11Console.WriteLine("循环结束");// i 变成 4 后退出,执行这一行

输出和上面的 while 完全一样。

5foreach 循环

要把一组数据挨个过一遍,用 foreach 更省事:不用自己数次数,它把值依次取出来,取完自动结束。

C# · 第 7-11 行
7string[] fruits = { "苹果", "香蕉", "橙子" };// 字符串数组:三个水果名放在一起(数组后面专门讲)
8foreach (string f in fruits)// 每一圈,f 拿到下一个名字
9{// foreach 循环体开始
10 Console.WriteLine(f);// 打印这一圈拿到的名字
11}// foreach 循环体结束:三个都取完就结束

6嵌套循环

循环里面再放循环叫嵌套循环,while、for、do...while、foreach 都可以互相嵌套。下面的小九九,外层 i 管第几行,内层 j 管这一行写几个。

C# · 第 7-14 行
7for (int i = 1; i <= 3; i++)// 外层:i 从 1 到 3,一圈一行
8{// 外层循环体开始
9 for (int j = 1; j <= i; j++)// 内层:j 从 1 数到 i,i 是几就写几个
10 {// 内层循环体开始
11 Console.Write(j + "×" + i + "=" + (i * j) + " ");// 打印 j×i=积 和两个空格;Write 不换行
12 }// 内层循环体结束
13 Console.WriteLine();// 一行写完,换行
14}// 外层循环体结束
运行结果
1×1=1  
1×2=2  2×2=4  
1×3=3  2×3=6  3×3=9

外层跑了三圈,内层一共跑了 1 + 2 + 3 = 6 次。

7循环体里的变量

循环体是一对花括号围起来的一块代码,在里面声明的变量,出了循环就不能用了:

C# · 第 7-11 行
7for (int i = 1; i <= 3; i++)// 循环三圈
8{// for 循环体开始
9 int square = i * i;// square 在循环体里声明
10}// for 循环体结束,square 到这里为止
11Console.WriteLine(square);// 在循环外面用 square
编译报错
Program.cs(11,27): error CS0103: 当前上下文中不存在名称“square”

square 出了花括号就不能用,这在编译时就定了。至于用 new 创建的对象,C# 不会在离开花括号时马上销毁它,而是由垃圾回收器(.NET 自动清理没人用的内存的机制)以后回收;“离开范围就销毁对象”是 C++ 的规则。

8break:结束整个循环

接下来是两个循环控制语句:break 和 continue,它们让循环不按平常的顺序走。break 立刻结束整个循环,程序接着执行循环后面的语句;break 也能用在 switch 里。

C# · 第 7-15 行
7for (int i = 1; i <= 10; i++)// 本来要数到 10
8{// for 循环体开始
9 if (i == 4)// i 等于 4 时
10 {// if 块开始
11 break;// 立刻结束整个 for 循环
12 }// if 块结束
13 Console.WriteLine(i);// 只打印出 1、2、3
14}// for 循环体结束
15Console.WriteLine("循环结束");// break 后跳到这里
运行结果
1
2
3
循环结束

循环套着循环时,break 只跳出它所在的最内层循环,外层照样继续。下面这段内层循环外面还套着一层 for (int i = 1; i <= 3; i++):

C# · 第 9-15 行
9for (int j = 1; j <= 3; j++)// 内层:j 从 1 到 3
10{// 内层循环体开始
11 if (j == 2)// j 等于 2 时
12 {// if 块开始
13 break;// 只跳出内层 for,外层继续下一圈
14 }// if 块结束
15 Console.WriteLine("i=" + i + ", j=" + j);// 每圈只来得及打印 j = 1
运行结果
i=1, j=1
i=2, j=1
i=3, j=1

9continue:跳过这一圈

continue 不结束循环,只跳过这一圈剩下的语句。在 for 循环里,跳过以后还会先执行 i++,再检查条件。

C# · 第 7-14 行
7for (int i = 1; i <= 5; i++)// i 从 1 到 5
8{// for 循环体开始
9 if (i == 3)// i 等于 3 时
10 {// if 块开始
11 continue;// 跳过下面的打印,去做 i++,i 变成 4
12 }// if 块结束
13 Console.WriteLine(i);// 打印 1、2、4、5
14}// for 循环体结束

换成 while 就藏着一个坑:i++ 在循环体最后,continue 直接跳回条件,i++ 被跳过,i 永远停在 3,又成了无限循环。打印出 1 和 2 以后就再也没有动静,程序也不结束:

C# · 第 8-16 行
8while (i <= 5)// 条件:i 小于等于 5
9{// while 循环体开始
10 if (i == 3)// i 等于 3 时
11 {// if 块开始
12 continue;// 直接跳回条件,下面的 i++ 被跳过
13 }// if 块结束
14 Console.WriteLine(i);// 只打印了 1、2
15 i++;// i 是 3 时永远走不到这一行
16}// while 循环体结束
运行结果
1
2

改法是在 continue 前面先把 i 加一,输出就和 for 循环一样是 1、2、4、5:

C# · 第 10-14 行
10if (i == 3)// i 等于 3 时
11{// if 块开始
12 i++;// 先把 i 加一,变成 4
13 continue;// 再跳回条件
14}// if 块结束

10无限循环

条件永远成立,循环就停不下来。for 括号里的三个部分都可以省略,只剩两个分号;条件不写就当它永远为真:

C# · 第 10-13 行
10for (; ; )// 初始化、条件、更新全空着,条件当成永远为真
11{// for 循环体开始
12 Console.WriteLine("Hey! I am Trapped");// 不停地打印这句英文,停不下来
13}// for 循环体结束

写成 while (true) 效果完全一样。真正的程序里,无限循环通常配合 break,条件满足时跳出来。下面打印 1、2、3 后 break,接着执行循环后面的“跳出来了”:

C# · 第 7-16 行
7int n = 0;// n 从 0 开始
8while (true)// 条件永远为真
9{// while 循环体开始
10 n++;// 每圈给 n 加一
11 Console.WriteLine(n);// 打印 1、2、3
12 if (n == 3)// n 等于 3 时
13 {// if 块开始
14 break;// 跳出循环
15 }// if 块结束
16}// while 循环体结束

11小结

  • while 先看条件再执行;do...while 先执行一次再看条件。
  • for 把初始化、条件、更新写在一起;foreach 把值挨个取出来;循环里还能套循环。
  • break 结束它所在的那一层循环;continue 跳过这一圈剩下的部分,用 while 时别把 i++ 跳过了。
  • 条件永远成立,就成了无限循环。

下一节:类里的数据,谁能看、谁能改?

检查题

6 道,选完马上告诉你对不对。

  1. 1int i = 1; while (i <= 3) { Console.WriteLine(i); }(没写 i++)运行会怎样?

  2. 2n 是 5,do { 打印 } while (n < 3); 会打印几次?

  3. 3内层循环里 j 等于 2 时 break,外层 i 从 1 到 3,会打印几行?

  4. 4for (int i = 1; i <= 5; i++) { if (i == 3) continue; Console.WriteLine(i); } 输出?

  5. 5下面哪个是无限循环?

  6. 6int i = 1; while (i <= 5) { if (i == 3) continue; Console.WriteLine(i); i++; } 运行会怎样?