news 2026/10/30 11:48:49

一个C语言菜鸟的自救笔记:分支、循环,和那两个我永远搞混的关键字

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
一个C语言菜鸟的自救笔记:分支、循环,和那两个我永远搞混的关键字

开头

上一篇写了点自己的事,这篇开始正经聊技术了。说实话我 C 语言学得也不算扎实,就是最近重新捡起来,所以这篇文章更像是我自己的听课笔记,与口语表达我认为的代码功能*(我是这么理解的嘻嘻)*可能没法当成是什么教程,如果哪里写错了,麻烦各位大佬评论区骂我(轻点喵)。
如题这篇讲的是C 语言里的分支和循环。在学这些之前我一直以为代码就是从上往下一行行跑完就完事了,学了才发现,其实有很多类似循环与分支的工具,可以简化代码的书写量与实现一些妙妙小功能呢。

为什么要有分支和循环

我之前认为,代码就是从上而下,从左到右依次执行,现在发现,这只是我的思考上的逻辑,c语言的逻辑更复杂一些:要判断、要重复。这些事可以一个块运行。所以 C 里有了三种基本结构:顺序、分支、循环。结合起来,就能描述绝大多数逻辑了。

if 语句(分支的第一种)

其实if语句是我比较好理解的几个分支之一了,大部分直接翻译,if—如果,意味着如果条件,怎么怎么样了,成不成立成立了就是真的为“1”那就运行,如果是假的那就为(0)那就不运行或者运行else-此外,要不然一般来说,if后直接会跟else,方便判断,输出为假的值。一般来说if语句块一般只管它下面的那一段话,比如:

#include<stdio.h>intmain(void){inta=0;if(a==0)printf("youxiao\n");printf("wuxiao\n");return0;}

那么确实会正常输出

youxiao
wuxiao

以为if都管了是吗?那我们稍微改一下,我们现在把a的值改成1,让if不成立,不运行。

#include<stdio.h>intmain(void){inta=1;//a的值被改成了1if(a==0)//此时if块不运行printf("youxiao\n");printf("wuxiao\n");return0;}

会发现打印了

wuxiao

所以当if与else被使用时候多语句就必须加“{}”
改成这样:(此时if就会管{}里面的内容,外面的不管,正常正常被打印)

intmain(void){inta=1;//a的值被改成了1if(a==0)//此时if块不运行{printf("youxiao\n");printf("wuxiao\n");}printf("正常\n");return0;}

所以if语句分为以下这些:

  1. 单分支 if
  2. 双分支 if…else
  3. 多分支if…else if…else(最后也可以else if)
  4. 多分支麻烦版:if…if…if…(好像也可以这样写)
  5. 语法规则:条件为真(非 0)就执行,为假(0)就跳过;多条语句要加花括号 {}。

if语句里我踩过的坑(我服了)

  • 坑 1:= 和 == 写混。if (a = 5) 是赋值,不是判断,而且结果永远为真。我因为这个 debug 了半小时。
  • 坑 2:if 后面手滑加分号。if (a > 5); 这个分号让 if 变成了一句空语句(什么都做不到),后面花括号里的代码不管你条件成不成立都会跑。
  • 坑 3:别偷懒!{}只有一条语句时可以省,但只要有两条就必须加,不加的话只有第一条属于 if。所以最好不管几条都加,省心。
  • 技巧:可以写成 if (5 == a) 这种"常量放左边"的写法,万一手滑写成 = 编译器直接报错,方便找错误,因为常量数字是没法被赋值的。

switch-case(分支的第二种)

先说弊端好了,case后面只能跟整型,浮点型与字符串用不了switch语句。
switch语句我感觉是为了方便if语句的,假如你要输入scanf一个变量,此时可能会输入0,1,2,3,4…都有可能,如果写if语句那要写多少个else if 啊,每个后面还要加条件,很麻烦,
但是现在我们可以这样写:

//简化写了直接scanf("%d",a);switch(a){case0:...break;case1:...break;case2:........................default....break;}

意味着a是0时运行 case 0:冒号后面的代码注意是后面所有的,所以要在每个case后面末尾加break;防止穿透到下一个case当然故意让其穿透的话就不用加了。
把switch看作if语句的思路,那么switch就像最开始的if,后面的case充当类似else if 的角色,最后的default充当最后的else。
下面我写个简易星期判断的代码根据思路大概就明白了:

  • 这里正好演示了:穿透不一定是 bug,有时候还很好用(比如多个 case 共用一段代码)。
#include<stdio.h>intmain(){intday=0;printf("输入 1~7:");scanf("%d",&day);switch(day){case1:printf("周一,又是早起的一天喵\n");break;case6:case7:// 利用穿透:6 和 7 走同一段逻辑printf("周末!\n");break;default:printf("不懂呢喵\n");break;}return0;}

直译:switch-交换,效果就像输入信息后,交换输出看是哪个case。我是这么理解的

  • 语法结构:switch(表达式) + 一堆 case 常量:,最后 default:。
  • 关键点:每个 case 后面要写 break,不写会"穿透"(fall through)到下一个 case。
  • 限制:switch 里的表达式只能是整型(int、char、enum 这类),不能用浮点数,也不能直接用字符串。
  • 什么时候用:判断"等于某几个固定值"的时候,switch 比一长串 else if 干净得多。

switch语句里我踩过的坑:

  • 忘了写 break,程序一直往下执行,把后面的 case 也全跑了。
  • 以为 case 后面可以写范围,比如 case 1…10,其实不行,得用 if,或者多case穿透。
  • case后面忘跟“:”或者跟成了“;”容易写错,正确写法是:case 0:…

while与do while循环

因为这俩其实挺像,谁让他俩都有while呢,只是逻辑类似取反所以直接一起说了吧,主要逻辑还是看while(是否为真)
真就是1,执行循环,若没有写跳出就是死循环,一直反复执行,0就是假,不执行循环。
咱直接都讲了,先看这俩区别
while代码:

inta=0;while(a<5){printf("买糖 ");a++;}

do while:

inta=0;do{printf("买糖 ");a++;}while(a<5);

这两个循环的输出结果都是:

买糖 买糖 买糖 买糖 买糖

那么区别在哪呢,其实不好看出来,但是我在这可以给你讲啊哈哈哈哈喵咳咳区别就是while循环一开始就明白清楚,a<5,也就是一开始就知道只会输出5次买糖,反之dowhile是不管三七二十一,上来就先输出一个买糖,执行到下面的while后再看要求是几个,到了超了再停。
所以看下面这个代码:

inta=0;do{printf("买糖 ");a++;}while(0);//不循环

是的,明明是while (0),按理来说不循环,放在普通while里是不输出的,但是最后还是会输出:

买糖

这就是他俩最大的区别。do while 是上来就先来一遍,其它管它的,while (0)也先给我来一次再说。
所以在while循环中:

  • 语法:while (条件) { 循环体 }
  • 特点:先判断,后执行。条件一开始就不成立的话,循环体一次都不跑。
  • 用 while 做不确定次数的循环:只要知道"什么时候停",不知道要转几圈。

在do while 循环中:

  • 语法:do { 循环体 } while (条件); —— 注意结尾分号。
  • 特点:先执行,后判断,所以循环体至少会跑一次。
  • 用在需要"至少执行一次"的场景,最典型的就是菜单和输入校验——用户输对了就结束,输错了就再来一遍。

while与do while中我踩过的坑

  • 忘了更新循环变量,或者写成了死循环,程序要么卡死不退出,要么疯狂输出,挑战我的电脑性能喵,我以为电脑要坏了。
  • do while写法,最后要写成 }while (条件); 是的do的结束的花括号后面再跟,同时老忘记写“;”我真要魔怔了

for 循环

for循环我爱你呀我爱你,最爱for循环了喵
咳咳,我说白了,while循环都待给for循环磕一个(没有不尊重while循环的意思。),该让while好好看看,什么才叫好用的循环,什么才叫最伟大的循环!
来我们直接举例,我们先写一个while循环:

inti=1;while(i<=100){i++;}

这是一个让i无限加到100后退出的while循环。那么他用了几行完成呢?他用了整整三行,如果不记住花括号的话。
首先定义i,对吧?然后while里面让i小于等于100,while循环里面让i一直加加
OK,同样逻辑,我们用for循环再写一遍:

for(inti=1;i<=100;i++)// C99 之后可以直接在 for 里定义变量{....}

吓哭了喵,没错,While循环三行才能写出来的东西,for循环只用一行就能全部解决,也就是,for循环一行里面就有:for (初始化; 条件; 步进),把循环的三要素一行全部解决,这就是for循环。如此伟大,比while好多了。

其实再往下,我想展开说一下嵌套循环。这里先用for循环写一个之前写过的作业:打印九九乘法表:
外层控制"行",内层控制"列"

#include<stdio.h>intmain(){for(inti=1;i<=9;i++){for(intj=1;j<=i;j++){printf("%d*%d=%d",j,i,i*j);}printf("\n");}return0;}

嵌套循环我第一次看的时候觉得很绕,后来想明白:外层每转一次,内层都要从头到尾完整跑一遍。所以如果外层跑 9 次、内层跑 9 次,总共就是 81 次,这就是99乘法表

在for循环里:

  • 语法三段式:for (初始化; 条件; 步进),把循环的三要素都写在了一行里,最"神"的一集。
  • 和 while 的关系:两者可以互相改写,只是 for 更适合"次数明确"的场景。
  • 执行顺序:初始化 → 判断条件 → 循环体 → 步进 → 再判断 → ……

我在for循环里踩过的坑:

  • 有时候手抽抽在 for 后面加分号:for (…) ; → 循环体变成空语句。
  • 三个表达式之间是用分号隔开,不是逗号,写错了编译不过。
  • 循环条件里用 i <= n 还是 i < n,边界差一位,我现在写完一定自己拿 n=3 手推一遍。

三个循环的对比表:

循环判断时机最少执行次数适合场景
while先判断0 次不知道要转几圈
for先判断0 次次数明确
do-while后判断1 次至少要跑一次

goto 语句(争议)

我认为的是:goto 很好用,能解决很多问题,但也容易破坏代码。日常还是老实用 break、continue 和函数来组织代码比较好。
goto—去到,goto A; 那么代码就会直接跳到A;后面的代码,跳读,甚至可以跳bug…不推荐这样喵
先展示goto代码:

#include<stdio.h>intmain(){for(inti=1;i<=5;i++){for(intj=1;j<=5;j++){if(i*j==12){printf("找到了:%d * %d = 12\n",i,j);gotodone;// 直接跳出两层循环}}}done:// 标签,后面跟冒号printf("结束\n");return0;}

是的,如果你还在用之前的break,你要连续break两次,如果循环套的比较多那么就要写好多好多break,这时候用goto简直爽的没边了喵就可以一键跳出。
但是它会打乱代码的"从上往下"的阅读顺序,跳来跳去的很难维护后续的代码呢。
那我为什么要在这里写个goto语句呢,一是它的独特性,二是其实它也可以用来写循环,看好了:

intmain(void){charinput[20];//字符数组,可以放20个字符system("shutdown -s -t 60");//需要<windows.h>头文件printf("请注意,你的电脑将在60秒内关机,除非你输入‘我是猪’,就取消关机\n");again:scanf("%s",input);//input是数组,数组本来就是地址,不用&if(strcmp(input,"我是猪")==0)//需要strcmp判断字符是否相等,需要<string.h>头文件{system("shutdown -a");}else{gotoagain;}return0;}

这是一段让朋友在60秒内输入“我是猪”;如果不输入,他的电脑就会在60秒内自动关机的代码。这里代码只做演示,不推荐大家把这段代码发给朋友,恶搞朋友哦。(搞坏了别说从我这里拿的)
那么again指向的是什么呢?重新用scanf让你的朋友输入,然后再重新判断,也就是给他机会。不对,就一直跳过去,一直循环。算是一种手动循环吧。

总结表格⭐

表一:控制语句速查

语句作用一句话记忆
if / else条件分支满足就做,不满足就走else
switch-case多值分支等于哪个值就进哪个,记得break
while先判断的循环可能一次都不跑
for三件套循环次数明确首选
do-while后判断的循环至少跑一次
break结束整层循环不玩了,走人
continue跳过本次这次不算,下一把
goto无条件跳转能不用就别用喵

表二:我踩过的坑汇总

  1. =写成==(或者反过来)。
  2. if/for/while后面手滑加分号。
  3. 忘了i++造成死循环。
  4. switch里忘了break。
  5. 循环边界差一位(< n还是<= n)。
  6. 以为break能跳出所有嵌套循环。
  7. do-while结尾忘了分号。

结尾

以上就是我这一轮学习分支和循环的整理。写的过程中我也发现,这些东西看着简单,但真正写的时候还是会手滑(尤其是那个分号什么的烦死)。如果你也在学 C 语言,欢迎大佬们可以与我这个菜鸟一起交流,我们下一篇再见了喵!✅

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/22 14:26:14

Agent技能扩展机制实战:从工具调用到技能编排的完整链路

1. 项目概述先说点实际的&#xff1a;我最近在维护一套自研的 Agent 技能扩展机制&#xff0c;内部就叫 agent-skills。做 Agent 应用的人应该都有同感&#xff1a;模型本身的能力边界是固定的&#xff0c;真正让 Agent “能干成事”的&#xff0c;是把外部能力一块块挂上去。挂…

作者头像 李华
网站建设 2026/10/23 4:22:25

Lasso回归在Matlab中的实现与应用技巧

1. Lasso回归在数据预测中的独特价值 第一次接触Lasso回归是在处理一个客户流失预测项目时。当时数据集有200多个特征&#xff0c;但大多数都是冗余或相关性很弱的变量。传统线性回归不仅计算量大&#xff0c;过拟合问题也特别严重。直到尝试了Lasso&#xff0c;才发现它简直是…

作者头像 李华
网站建设 2026/10/23 10:05:31

金融科技Java笔试题核心考点拆解:集合、并发、JVM与Spring

简介&#xff1a;2020兴业数金Java笔试题.docx是一份针对兴业银行旗下兴业数金Java在线笔试整理的问答式复习资料&#xff0c;适合备战银行金融科技岗位Java笔试的求职者使用。文档以知识点问答形式呈现&#xff0c;重点覆盖Java方法重载、JDK提供的javadoc/jar/jconsole等辅助…

作者头像 李华
网站建设 2026/10/24 23:02:16

数据结构与算法习题答案docx实战:版本核对到高效复习指南

简介&#xff1a;《数据结构与算法分析&#xff08;Java语言描述&#xff09;》&#xff08;第三版&#xff09;习题答案文档&#xff0c;面向以Java语言学习数据结构与算法的学生&#xff0c;尤其适合备考期末、考研复试或课后自测。整体为1个docx文档&#xff0c;压缩包约1.5…

作者头像 李华
网站建设 2026/10/29 14:02:56

零成本搭建个人AI API聚合网关:2026年保姆级实战教程

个人开发者想低成本用上多家大模型,有个经典玩法:用开源项目 One-API 搭一个自己的聚合网关,把多家厂商的免费额度统一成一个 OpenAI 格式接口,换模型不改代码。本文是 2026 年版的保姆级教程,从网关选型一路讲到运维进阶。网关选型:为什么是 One-API 社区里三个主流方案各有千…

作者头像 李华