很多学C语言的朋友都有过这样的经历:单独看if和for的语法都懂,一到自己写判断和循环就乱套,要么多分支逻辑调度不清晰,要么循环条件里埋了死循环和越界的雷。说穿了,分支和循环语句就是C语言的骨架,程序里几乎九成的逻辑都落在"怎么判断"和"怎么反复执行"这两件事上。这篇东西就把我在一线写C、带新人过程中积累的经验摊开来聊,先讲清楚每种语句背后的设计逻辑和适用场景,再给出一套可以直接照着写的实操套路,最后整理一份踩坑速查表,希望帮你把这部分基本功彻底焊死。
既然上手写代码,绕不开的就是代码风格和工具链。结合这两年大家问得比较多的问题,我把 vscode 配置 C语言环境、C-Free 这类开发工具的取舍,以及分支循环代码里常见的坑一起讲透。适合正在学C语言的初学者,也适合教书带团队的朋友当教学素材参考。
1. 先把分支和循环这盘棋想清楚
1.1 判断与重复是程序的两条腿
任何程序跑起来,本质上都在做三件事:输入数据、处理数据、输出结果。而"处理"这一步,翻来覆去就是两个动作——根据条件走不同的路,以及把同样的操作重复多遍。前者叫分支,后者叫循环。
你去看任何一段实际项目代码,不管它多复杂,底层逻辑最终都会被拆成这两种结构的组合。哪怕是用深度循环模型做训练,落到代码层面,backbone 里的数据处理、梯度累积、epoch 遍历,统统是for、while在干活。再比如 Redis 的循环队列、SQL 语句的批量查询、C# 后台开线程做数据采集,底层也离不开这套基本功。
所以,不是"我要学分支循环所以看这篇",而是"我写的任何程序都要靠它撑起来"。把这两样东西练成肌肉记忆,后面学数组、指针、结构体、文件读写,才能把精力放在新概念上,而不是每次都被老问题绊倒。
1.2 学语句别只看语法,要看它解决了什么烦恼
很多教材讲if就只丢给你一份语法格式,然后让读者自己背。这其实是本末倒置。你在这个阶段真正该建立的意识是:C语言为什么给了你这么多种分支工具,又给了你这么多种循环工具?
分支工具给了if、else if、switch,因为在不同场景下,代码的"可读性"和"执行效率"诉求不一样。比如单条件判断用if就够了,多条件逐级判断时else if比嵌套if清爽,而判断一个整数取值落在哪个区间时,switch的匹配逻辑天生更清晰。循环工具给了while、do-while、for,同样是为了适配"先判断再执行"和"至少执行一次"这两种截然不同的需求,以及让循环变量的初始化、条件判断、步进更新能在一行里被看见。
带着"它解决了什么问题"的心态去学,你会发现这些东西根本不用硬背,用到的时候自然就会选。
2. 分支语句全景拆解:if 就是程序的"红绿灯"
2.1 if 与 if-else 的基本姿势
代码里的分支,本质上就是给程序装红绿灯。绿灯放行、红灯停下、黄灯犹豫一下走另一条道,每一条分支都必须有一个条件表达式,条件成立执行一段,不成立就绕过去或执行另一段。
实际写的时候,我强烈建议哪怕是只有一条执行语句,也把大括号写全。你可能会觉得if (a > 0) printf("yes");这样更简洁,但等你自己回头改代码,或者别人帮你 review 的时候,没大括号的if就是一颗定时炸弹——后面加一行你想当然认为属于if的代码,结果它根本不在分支里面,运行结果驴唇不对马嘴。
#include <stdio.h> int main(void) { int score; scanf("%d", &score); if (score >= 90) { printf("优秀\n"); } else if (score >= 75) { printf("良好\n"); } else { printf("需要再加油\n"); } return 0; }这段代码的逻辑很直白:90 分以上是一档,75 到 89 是一档,剩下的人手动善意安慰一下。因为用了else if,条件之间天然互斥,程序会从上往下找到第一个满足的条件执行,执行完整个分支结构就结束,不会出现"同时满足两个条件然后执行两遍"的尴尬。
这里有个很重要的细节:判断区间时,两个相邻区间的边界值是重叠还是不重叠,直接决定代码正确性。上面例子我先判断>= 90,再判断>= 75,那么 90 分本身只会进第一档;如果你顺序反过来,先>= 75再>= 90,那 90 分就会先被拦截在"良好"里,这就是典型的边界判断次序错误。写边界条件时,最好拿典型值、边界值、异常值三种数据各测一遍。
2.2 悬空 else 是怎么发生的
悬空 else 属于C语言里出了名的坑,而且新手几乎百分百会踩一次。规则只有一句话:else总是与离它最近的、尚未匹配的if配对。但这句话的真实后果,很多人要踩过才知道。
看下面这段代码:
int a = 1, b = -1; if (a > 0) if (b > 0) printf("positive\n"); else printf("negative\n");光看缩进,你肯定以为else配的是外层的if (a > 0),觉得逻辑是"a 大于 0 且 b 不大于 0 时打印 negative"。但实际编译器会把它配对成"a 大于 0 时,进入内层判断,如果 b不大于 0 则打印 negative"。换句话说,else陪的是内层那个if (b > 0),跟缩进完全没有关系。
这段程序跑起来,因为 a > 0 成立,进入内层,b 不大于 0,于是输出 negative。看起来好像歪打正着,可一旦 a 改成负数,输出就变成什么都不打印,彻底暴露配对错误。
解决办法就是前面说的大括号:每层if都显式加括号。别跟编译器玩猜谜游戏,写清楚最省心。
2.3 switch-case 是整型分支的利器
当分支的判断条件是一个变量和多个离散常量比较时,switch往往比一连串else if更合适。它天生就是把一个整数拿到多个 case 里去撞,撞上谁执行谁,一个都撞不上就执行default。这个语义非常适合做菜单选择、命令解析、状态机这类场景。
#include <stdio.h> int main(void) { int cmd; printf("请选择操作:1-查询 2-新增 3-删除 0-退出\n"); scanf("%d", &cmd); switch (cmd) { case 0: printf("退出系统\n"); break; case 1: printf("执行查询\n"); break; case 2: printf("执行新增\n"); break; case 3: printf("执行删除\n"); break; default: printf("无效指令,请重新输入\n"); break; } return 0; }这种写法比起写三个else if,结构的意图一目了然:cmd 这个变量,每一种取值对应一条路。而且switch在编译器层面通常会被优化成跳转表,多个分支时性能也比逐个比较的else if更好,有兴趣的话可以了解一下 FPGA 综合工具对多分支 case 语句的处理,道理有相通之处。
switch有几个强制规矩,记不住就会出事:
- case 后面必须是整型常量表达式,不能用变量,也不能用浮点数。
- 每一个非空 case 块最后不要忘了
break,否则会执行"穿透",也就是 fall-through,把下面所有 case 的代码顺序执行一遍,直到遇到 break 或 switch 结束。 - 同一个 switch 里,case 值不能重复。
有时候"穿透"也被当作技巧故意使用,比如多个 case 共享同一段处理逻辑:
switch (grade) { case 'A': case 'B': printf("通过\n"); break; case 'C': printf("刚好及格\n"); break; default: printf("未通过\n"); break; }这种写法没问题,但故意穿透时必须写清楚注释,否则很容易吓到后来维护代码的人。我见过不止一次,代码里忘写break导致连续执行了好几个功能,查了半天才发现是穿透问题,教训非常深刻。
2.4 if-else 链和 switch 怎么挑
简单粗暴的规则是:条件在比较"区间、大小、范围",或者需要做复杂逻辑运算时,用if-else;条件在拿一个整型变量和几个固定离散值撞时,用switch。比如判断成绩及格不及格,用if;解析用户输入的数字菜单,用switch。
还有一种情况,当你同时需要判断多个彼此独立的条件,而不是互斥条件时,就不要把它们写成层层嵌套的else if,那样会把你自己的逻辑都绕晕。把条件拆成独立的if或者用逻辑运算符组合,更清爽,也更容易测试。
3. 循环语句逐一说透:for、while、do-while
3.1 为什么需要三种循环
循环的本质是重复执行一段代码,但"重复"这件事也有不同姿势:有的要先判断再执行,有的要先做一次再说,有的需要清晰地管理计数器。C语言干脆给你三样工具,各管一摊。
学习的时候,我最反感的一种教法是让新手把三种循环都背一遍,然后考试时搞语法默写。有用吗?暂时有,转头就忘。真正管用的办法是:理解每种循环解决的真实场景,再去写代码验证。
3.2 while:先看门再进门
while (条件) { 循环体 }的执行顺序是:先判断条件成立不成立,成立才执行一遍循环体,然后回来再判断。如果条件一开始就不成立,循环体一次都不执行。
典型的应用场景是:你不知道到底要循环多少次,只知道在什么条件下继续、在什么条件下停。比如从标准输入不断读取数据,遇到 0 就结束;或者做数值迭代,直到误差小于某个阈值才停止。
#include <stdio.h> int main(void) { int sum = 0; int n; printf("请输入多个正整数,以0结束:\n"); scanf("%d", &n); while (n != 0) { sum += n; scanf("%d", &n); } printf("总和是 %d\n", sum); return 0; }这段代码每读一个数、加一次,再读下一个数,读到 0 就说明输完收工。条件n != 0就是"继续循环的门票"。这个模式在真实项目里非常常见,C语言文件读写、C# 循环数据采集、SQL 结果集遍历,思路全是一模一样。
写while最尴尬的事情是忘了更新循环变量。比如上面如果漏了scanf("%d", &n);,n 永远不等于 0,循环就成永动机了。所以写完循环体,先检查一遍:条件里用到的变量,在循环体里有没有一条路能让它朝"退出"的方向变化。
3.3 do-while:先进门再查票
do { 循环体 } while (条件);的独特之处在于:它先执行一次循环体,再判断条件。这保证了循环体至少运行一次。这在某些场景下是刚需。
最典型的例子就是菜单程序。你希望用户至少看一眼菜单、至少能操作一次,然后循环询问他是否要继续;还有一种输入校验场景,先让用户输入一次,如果输入不合法就让他重新输,这也天然适合 do-while,因为总得先输入才能判断合不合法。
#include <stdio.h> int main(void) { int choice; do { printf("菜单:1-开始 2-设置 0-退出\n"); printf("请输入:"); scanf("%d", &choice); switch (choice) { case 1: printf("开始运行\n"); break; case 2: printf("进入设置\n"); break; case 0: printf("程序退出\n"); break; default: printf("输入无效\n"); break; } } while (choice != 0); return 0; }注意 do-while 的结尾分号千万别丢。这是语法里唯一一个循环/分支语句后面还要加分号的地方。很多人第一次写都是死在这。
3.4 for:把计数器管得明明白白
for循环把三件事压缩到一行:初始化循环变量、判断循环条件、更新循环变量。它的最大优势是循环的"三要素"集中在一起,别人读代码的时候一眼就能看到循环怎么开始、怎么结束、每次怎么步进,不容易出现 while 里常见的"忘更新变量"问题。
最常见的是固定次数的遍历,比如数组、字符串、打印九九乘法表、做累加:
#include <stdio.h> int main(void) { int sum = 0; for (int i = 1; i <= 100; i++) { sum += i; } printf("1 到 100 的总和是 %d\n", sum); for (int i = 0; i < 5; i++) { for (int j = 0; j <= i; j++) { printf("*"); } printf("\n"); } return 0; }这里有两个细节很容易被忽略:
第一个,for (int i = 1; i <= 100; i++)用的是<=,循环体执行 100 次。如果你写成i < 100,那就变成 99 次。很多字符串处理的循环,正确边界是< strlen(s),多一个等号就可能把结尾的\0也遍历进去,甚至越界访问。所以 for 循环的边界条件务必拿实际例子心算一遍。
第二个,for 的三个表达式理论上都可以省略,但省略时必须保证循环逻辑能正确结束。比如:
for (;;) { // 相当于 while(1),死循环,通常配合 break 使用 }死循环本身不是罪过,很多服务器主循环、驱动事件循环就是永不停歇的。但死循环里头必须要有break或者可以退出程序的条件,否则你的程序就跑成"赖着不走"了。
3.5 三种循环怎么选:一张对照表
| 循环类型 | 执行顺序 | 最少执行次数 | 典型场景 |
|---|---|---|---|
| while | 先判断条件,再执行循环体 | 0 次 | 不知道循环次数,只知道继续/停止条件 |
| do-while | 先执行循环体,再判断条件 | 1 次 | 至少执行一次,例如菜单、输入校验 |
| for | 初始化、判断、步进集中在头部 | 0 次 | 已知循环次数,遍历数组/字符串/计数器 |
没有绝对的好坏,按场景选。你如果觉得"我要写一个循环 N 次",优先 for;如果是"持续读数据直到某个条件",优先 while;如果是"先给用户看一次菜单再决定是否继续",优先 do-while。
4. break 和 continue:循环的刹车与免跑单
4.1 break 跳出整个循环
break用在循环里,作用是立刻跳出当前这一层循环,后面所有未执行的迭代都取消。它和switch里的break都是"退出当前结构",但要注意作用范围:它只退出"最近的那一层",不能跨层。
经典场景是在循环里找到了目标,就不需要再傻乎乎找下去了:
#include <stdio.h> int main(void) { int numbers[] = {3, 7, 12, 5, 8}; int target = 12; int found = 0; for (int i = 0; i < 5; i++) { if (numbers[i] == target) { found = 1; break; } } if (found) { printf("找到了目标值,下标是 %d\n", find_index); } else { printf("没有找到\n"); } return 0; }这段代码里,break一旦命中就立刻跳出 for,后面数组元素不再比对。这就是"提前结束循环"的典型用法,比遍历完整个数组再判断节省时间,逻辑也更清晰。
但注意:break只跳一层。双层循环里,内层 break 后外层还在继续跑。如果你是想同时退出两层,通常不能依靠 break 的"默认行为去赌",而是设一个标志变量,外层每轮先看标志再决定是否继续。
4.2 continue 跳过本次迭代
continue的作用是结束当前这一次迭代,直接跳到下一次循环判断。它不退出循环,只是"这一轮先不干了"。
在循环体里,continue 之后的所有代码都被跳过,直接回到循环头部。对于 for 循环,会先执行步进表达式再判断条件;对于 while,会直接进入下一次条件判断。这个差异很重要,因为 continue 配合 while 容易顺手把循环变量更新写漏了。
int n = 0; while (n < 10) { n++; // 确保更新在 continue 之前 if (n % 2 == 0) { continue; // 跳过偶数打印 } printf("%d ", n); }输出结果是 1 3 5 7 9。如果你把n++放在continue之后,一遇到偶数就 continue,循环变量永远不增加,直接死循环。这不是 continue 的错,是循环更新位置选错了。
4.3 break 和 continue 别乱嵌套
很多新手写多重循环时脑子一发热,在内层循环里写了一堆 break 和 continue,最后自己都说不清程序会走到哪。这里我建议一条纪律:如果循环超过两层,优先考虑把内层逻辑抽成函数,或者用标志变量控制退出,而不是无限堆 break。
举个例子,要在一个二维数组里找到第一个值为 -1 的位置,双层循环需要两层退出逻辑:
int matrix[3][3] = { {1, 2, 3}, {4, -1, 6}, {7, 8, 9} }; int target_row = -1, target_col = -1; int found = 0; for (int i = 0; i < 3 && !found; i++) { for (int j = 0; j < 3; j++) { if (matrix[i][j] == -1) { target_row = i; target_col = j; found = 1; break; } } }这里外层循环条件里加了!found,内层 break 之后,外层判断 found 为真,也会结束。这种写法比单独靠 break 更容易读,也更好排查问题。
5. 实操:把分支循环组合成能跑的程序
5.1 综合案例:写一个数字猜谜小游戏
把分支和循环放在一起练手,最合适的入门项目就是猜数字。程序随机生成一个 1 到 100 的整数,然后循环提示用户输入,判断输入值和目标值的大小关系,直到猜对或者次数用尽。这个程序用到了 for/while 循环、if 判断、break 跳转,一石三鸟。
#include <stdio.h> #include <stdlib.h> #include <time.h> int main(void) { int secret, guess; int max_attempts = 7; srand((unsigned)time(NULL)); secret = rand() % 100 + 1; printf("我已经想好了一个 1 到 100 之间的整数,你有 %d 次机会。\n", max_attempts); for (int i = 1; i <= max_attempts; i++) { printf("第 %d 次猜测:", i); scanf("%d", &guess); if (guess == secret) { printf("恭喜你,猜对了!\n"); return 0; } else if (guess > secret) { printf("太大了\n"); } else { printf("太小了\n"); } } printf("机会用完了,正确答案是 %d。欢迎再玩一次!\n", secret); return 0; }这个程序把for控制次数、if-else判断大小、return 0提前结束、边界值rand() % 100 + 1全部串在了一起。写完跑一遍,你会发现代码的每一处基本都离不开分支和循环的语言要素。
5.2 开发工具与配置:VSCode 和 C-Free 的取舍
写 C 代码之前,顺手把环境搞定。我见过太多人把时间浪费在配置工具链上,绕了一圈又想放弃。如果你用的 Windows 系统,最省事的方案是安装 C-Free 5.0,它自带编译器(C-Free 5 内置了 MinGW 的一个版本),新建文件就能写、能编译、能运行,面向刚学 C 的同学非常友好。缺点是它已经年代久远,界面老旧,但用来跑通语法和简单项目完全够用。
如果你想用 VSCode 写 C,那么配置 C 语言环境的核心步骤是:先安装编译器(MinGW-w64 或者 MSYS2),再把编译器的 bin 目录加到系统 PATH 环境变量,最后在 VSCode 里安装 C/C++ 扩展,用 tasks.json 配置编译命令。网上有不少图文教程,照着做就能跑通。配置完记得在终端执行gcc --version验证一下,看到版本号输出就说明编译器装好了。这一步如果卡住,先检查 PATH 里有没有刚才加的路径,几乎九成的报错都是环境变量没生效。
C-Free 和 VSCode 怎么选?我的建议是:纯新手阶段,用 C-Free 把精力集中在语言本身;等你开始写那种几十个文件的项目、需要依赖分析和 Git 版本管理时,再切换到 VSCode 加插件的工作流。现在网上也常有人问"VSCode 配置 C语言环境"遇到各种报错,我建议你先用 C-Free 跑通第一个程序,对 C 的编译过程有感觉后,再折腾 VSCode 也不迟。工具是拿来用的,不是拿来磨的。
5.3 分支循环场景的通用代码模板
很多时候你需要的不是一整个项目,而是一个能直接套用的片段。我把日常开发中最常用的模板整理一下:
- 输入校验循环:读入一个值,不合法就重新读,用 do-while 最自然。
- 菜单循环:do-while 包住 switch,用 while 条件判断是否退出。
- 固定次数累加:for 循环加累加器。
- 找目标值提前退出:for 循环加 break 加标志变量。
- 嵌套打印图形/表格:外层控制行,内层控制列,例如九九乘法表、直角三角形、菱形。
这些模板背下来不值得,动手各写一遍,肌肉记忆自然就有了。写的时候给每个循环起一个有意义的名字,比如for (int col = 0; col < cols; col++),而不是for (int i=0; i<5; i++)。这个习惯越早建立越好,等代码一行变十行、十行变百行,你就知道变量名和意图清晰有多救命。
5.4 编程风格:大括号、缩进和注释
最后再讲一个容易被忽略但很重要的点:分支循环代码的可读性。同样一段逻辑,有人写得一目了然,有人写得像天书。核心区别在于:
- 大括号统一:要么 K&R 风格,大括号跟在语句尾部;要么 Allman 风格,大括号独占一行。别混着用。我推荐统一 K&R,占的行数少,看代码更紧凑。
- 缩进统一:用 4 个空格或一个 Tab,别一会儿空格一会儿 Tab。很多编辑器交换过 Tab 和空格后代码乱掉,就是混用造成的。
- 注释说意图,不说废话:
// 如果总分大于90就打印优秀这种注释没有价值,应该写的是// 成绩等级按总分划分,边界条件:90分属于优秀。
搞项目不是写给自己一个人看的。C语言遍布底层芯片、操作系统、嵌入式、数据库内核,团队协作是常态,代码风格差异如果太大,合并分支时 Git 冲突能把你烦死。这也是为什么很多团队从一开始就对代码格式有严格规范。我的经验是:新手阶段就养成一致的格式化动作,任何环境里写完代码随手格式化,这个好习惯能省掉后续无数 review 争吵。
6. 常见问题与排查技巧实录
6.1 快捷键映射、条件编译等周边概念
有位读者之前问过我,说自己在 VSCode 里写完代码,编译报错一堆,问是不是编译器坏了。我让他把报错贴出来,发现全是"未定义符号 main",他其实编译的是一个只有函数没有 main 的源文件。这里顺带说三点:
- C 程序的入口必须是
main。编译可以生成.o目标文件,但可执行程序的链接阶段必须找到main,否则链接失败。 - 想在多个平台写不同分支逻辑,可以用
#ifdef条件编译。这不是运行时分支,是预处理阶段的分支,用来处理不同操作系统的差异代码。比如 Windows 和 Linux 下某些系统 API 不一样,就可以用#ifdef _WIN32包两套实现。 - C 语言来源年份虽然久远,但至今仍是嵌入式、操作系统、数据库实现的主流语言。学分支循环时,顺便了解一点编译原理(预编译、编译、汇编、链接)会对理解"条件编译为什么在编译期就决定了"很有帮助。
6.2 死循环怎么快速定位
死循环是分支循环阶段最让人头疼的问题。程序跑起来不结束,按 Ctrl+C 也未必能停,只能崩溃掉。我的排查顺序是:
先看循环条件里涉及的变量有没有被正确更新。最典型的错误是 while 写成了while (i < 10),循环体里却忘了i++,或者i++被 continue 跳过了。再看循环边界有没有可能永远不满足。比如for (i = 0; i < n; i--),方向写反了,i 永远小于 n,直接就死循环。最后看是不是循环体里逻辑上有多个条件互相制约,导致某条路径下条件永远不改变。
如果实在一眼看不出来,可以临时在循环体里加一个打印语句,输出当前变量值。比如:
while (n > 0) { printf("n = %d\n", n); // 其他逻辑 }看到输出卡在哪个值附近,基本就定位了。这类问题十有八九是边界和更新的问题,跟语言本身没关系,排查时必须冷静。
6.3 悬空 else、运算优先级与常见编译报错
悬空 else 我们已经提过。除了它,另外一个常搞混的是运算优先级。if (a & 1 == 0)这种写法里,==优先级比&高,所以实际是a & (1 == 0),跟你想的完全不一样。遇到复合表达式时,不要装酷,直接用括号把意图写清楚。编译器不会嫌括号多,但会默默按错误的优先级执行你写错的代码。
常见编译报错基本就那几类:括号不匹配、分号漏在奇怪的地方、case 标签后面跟了变量、字符常量用了双引号、比较浮点数时用了精确等于。这些报错信息你在 C-Free 或 VSCode 里看多了,基本一眼就能识别。我的建议是把编译器报错当成学习资料,先读第一行,找到文件和行号,再回头核对代码,不要看到一片红就先慌了。
6.4 常见问题速查表
| 问题 | 可能原因 | 解决方法 |
|---|---|---|
| 程序不进入分支直接跳过 | 条件表达式写反,比如if (a = 0)用了赋值而不是等于 | 检查是否写成==,避免在条件里做赋值 |
| 满足了条件却不走分支 | 变量类型不匹配,浮点与整数比较有精度问题 | 转成同一类型再比较,区间判断用范围比较 |
| switch 执行了多个 case | 忘写 break,发生穿透 | 每个非空 case 检查是否有 break |
| 循环次数多了 1 次或少了 1 次 | 边界写错,比如i <= n与i < n弄混 | 用具体数值代入推算执行次数 |
| 死循环 | 循环变量未更新,或 continue 跳过更新语句 | 检查循环变量是否在每次迭代都朝退出方向变化 |
编译报错expected ';' | 分号漏写,尤其 do-while 结尾 | 检查 do-while 尾部是否有分号 |
| VSCode 编译报"gcc 不是内部或外部命令" | 编译器未安装或 PATH 未配置 | 安装 MinGW-w64,并把 bin 目录加到 PATH |
| 浮点比较总是出问题 | 浮点数在二进制里不能精确表示 | 用差值绝对值小于阈值的方式比较 |
这张表你可以留在手边,后面自己调试程序时对着排查,比到处翻资料高效得多。
我个人带新人这两年最大的体会是:分支和循环能不能写好,不取决于背了多少语法,而是取决于有没有在真实 Debug 里摔过跤。悬空 else、死循环、break 穿透、变量更新位置弄错,这些坑踩一次比看十遍教材都管用。建议你把这篇文章看完后,把文中的代码手敲一遍,再自己改几个版本,比如把猜数字游戏的次数改成无限次、把打印三角改成打印菱形、把成绩分级改成 switch 版本。改着改着,你会发现分支循环真正长在你脑子里了。祝写码顺利。