开始
上一篇写了点自己的事,这篇开始正经聊技术了。说实话我 C 语言学得也不算扎实,就是最近重新捡起来,所以这篇文章更像是我自己的听课笔记,与口语表达我认为的代码功能 *(我是这么理解的嘻嘻)*可能没法当成是什么教程,如果哪里写错了,麻烦各位大佬评论区骂我 (轻点喵) 。 如题这篇讲的是 C 语言里的分支和循环 。在学这些之前我一直以为代码就是从上往下一行行跑完就完事了,学了才发现,其实有很多类似循环与分支的工具,可以简化代码的书写量与实现一些妙妙小功能呢 。
为什么要有分支和循环
我之前认为,代码就是从上而下,从左到右依次执行,现在发现,这只是我的思考上的逻辑,c语言的逻辑更复杂一些 :要判断、要重复。这些事可以一个块运行。所以 C 里有了三种基本结构:顺序、分支、循环。结合起来,就能描述绝大多数逻辑了。
if 语句(分支的第一种)
其实if语句是我比较好理解的几个分支之一了,大部分直接翻译,if---如果 ,意味着如果条件,怎么怎么样了,成不成立 成立了就是真的为"1"那就运行,如果是假的那就为(0)那就不运行或者运行else-此外,要不然一般来说,if后直接会跟else,方便判断,输出为假的值。一般来说if语句块一般只管它下面的那一段话,比如:
c
#include<stdio.h>
int main(void)
{
int a = 0;
if(a==0)
printf("youxiao\n");
printf("wuxiao\n");
return 0;
}
那么确实会正常输出
youxiao wuxiao
以为if都管了是吗?那我们稍微改一下,我们现在把a的值改成1,让if不成立,不运行。
c
#include<stdio.h>
int main(void)
{
int a = 1;//a的值被改成了1
if(a==0)//此时if块不运行
printf("youxiao\n");
printf("wuxiao\n");
return 0;
}
会发现打印了
wuxiao
所以当if与else被使用时候多语句就必须加"{}" 改成这样:(此时if就会管{}里面的内容,外面的不管,正常正常被打印)
c
int main(void)
{
int a = 1;//a的值被改成了1
if (a == 0)//此时if块不运行
{
printf("youxiao\n");
printf("wuxiao\n");
}
printf("正常\n");
return 0;
}
所以if语句分为以下这些:
- 单分支 if
- 双分支 if...else
- 多分支 if...else if...else(最后也可以else if)
- 多分支麻烦版:if...if...if...(好像也可以这样写)
- 语法规则:条件为真(非 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 啊,每个后面还要加条件,很麻烦, 但是现在我们可以这样写:
c
//简化写了直接
scanf("%d",a);
switch(a)
{
case 0:...
break;
case 1:...
break;
case 2: ...
.....................
default
....
break;
}
意味着a是0时运行 case 0:冒号后面的代码注意是后面所有的,所以要在每个case后面末尾加break;防止穿透到下一个case 当然故意让其穿透的话就不用加了。 把switch看作if语句的思路,那么switch就像最开始的if,后面的case充当类似else if 的角色,最后的default充当最后的else。 下面我写个简易星期判断的代码根据思路大概就明白了:
- 这里正好演示了:穿透不一定是 bug,有时候还很好用(比如多个 case 共用一段代码)。
c
#include <stdio.h>
int main()
{
int day = 0;
printf("输入 1~7:");
scanf("%d", &day);
switch (day) {
case 1:
printf("周一,又是早起的一天喵\n");
break;
case 6:
case 7: // 利用穿透:6 和 7 走同一段逻辑
printf("周末!\n");
break;
default:
printf("不懂呢喵\n");
break;
}
return 0;
}
直译: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代码:
c
int a = 0;
while(a<5)
{
printf("买糖 ");
a++;
}
do while:
c
int a = 0;
do
{
printf("买糖 ");
a++;
}while(a<5);
这两个循环的输出结果都是:
买糖 买糖 买糖 买糖 买糖
那么区别在哪呢,其实不好看出来,但是我在这可以给你讲啊哈哈哈哈喵 咳咳区别就是while循环一开始就明白清楚,a<5,也就是一开始就知道只会输出5次买糖 ,反之dowhile是不管三七二十一,上来就先输出一个买糖,执行到下面的while后再看要求是几个,到了超了再停。 所以看下面这个代码:
c
int a = 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循环:
c
int i = 1;
while (i <= 100)
{
i++;
}
这是一个让i无限加到100后退出的while循环。那么他用了几行完成呢?他用了整整三行 ,如果不记住花括号的话。 首先定义i,对吧?然后while里面让i小于等于100,while循环里面让i一直加加 OK,同样逻辑,我们用for循环再写一遍:
c
for(int i = 1;i <= 100;i++)// C99 之后可以直接在 for 里定义变量
{
....
}
吓哭了喵 ,没错,While循环三行才能写出来的东西,for循环只用一行就能全部解决,也就是,for循环一行里面就有:for (初始化; 条件; 步进),把循环的三要素一行全部解决,这就是for循环。如此伟大,比while好多了。
其实再往下,我想展开说一下嵌套循环 。这里先用for循环写一个之前写过的作业:打印九九乘法表: 外层控制"行",内层控制"列"
c
#include <stdio.h>
int main()
{
for (int i = 1; i <= 9; i++)
{
for (int j = 1; j <= i; j++)
{
printf("%d*%d=%d", j, i, i * j);
}
printf("\n");
}
return 0;
}
嵌套循环我第一次看的时候觉得很绕,后来想明白:外层每转一次,内层都要从头到尾完整跑一遍。所以如果外层跑 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代码:
c
#include <stdio.h>
int main()
{
for (int i = 1; i <= 5; i++) {
for (int j = 1; j <= 5; j++) {
if (i * j == 12) {
printf("找到了:%d * %d = 12\n", i, j);
goto done; // 直接跳出两层循环
}
}
}
done: // 标签,后面跟冒号
printf("结束\n");
return 0;
}
是的,如果你还在用之前的break,你要连续break两次,如果循环套的比较多那么就要写好多好多break ,这时候用goto 简直爽的没边了喵 就可以一键跳出。 但是它会打乱代码的"从上往下"的阅读顺序,跳来跳去的很难维护后续的代码呢。 那我为什么要在这里写个goto语句呢,一是它的独特性,二是其实它也可以用来写循环,看好了:
c
int main(void)
{
char input[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
{
goto again;
}
return 0;
}
这是一段让朋友在60秒内输入"我是猪";如果不输入,他的电脑就会在60秒内自动关机的代码。这里代码只做演示,不推荐大家把这段代码发给朋友,恶搞朋友哦。 (搞坏了别说从我这里拿的) 那么again指向的是什么呢?重新用scanf让你的朋友输入,然后再重新判断,也就是给他机会。不对,就一直跳过去,一直循环。算是一种手动循环吧。
总结表格⭐
表一:控制语句速查
| 语句 | 作用 | 一句话记忆 |
|---|---|---|
if / else |
条件分支 | 满足就做,不满足就走else |
switch-case |
多值分支 | 等于哪个值就进哪个,记得 break |
while |
先判断的循环 | 可能一次都不跑 |
for |
三件套循环 | 次数明确首选 |
do-while |
后判断的循环 | 至少跑一次 |
break |
结束整层循环 | 不玩了,走人 |
continue |
跳过本次 | 这次不算,下一把 |
goto |
无条件跳转 | 能不用就别用喵 |
表二:我踩过的坑一些汇总
=写成==(或者反过来)。if/for/while后面手滑加分号。- 忘了
i++造成死循环。 switch里忘了break。- 循环边界差一位(
< n还是<= n)。 - 以为
break能跳出所有嵌套循环。 do-while结尾忘了分号。
结尾
以上就是我这一轮学习分支和循环的整理。写的过程中我也发现,这些东西看着简单,但真正写的时候还是会手滑(尤其是那个分号什么的烦死)。如果你也在学 C 语言,欢迎大佬们可以与我这个菜鸟一起交流,我们下一篇再见了喵!✅