目录
1.引言
2.注释的使用
3.选择语句
3.1.if 语句
3.2.switch 语句
4.循环语句
4.1.while 语句
4.2.do – while 语句
4.3.for 语句
4.4.循环语句的使用情况及嵌套使用
5.break 语句与 continue 语句
6.goto 语句
7.综合应用(类猜数字游戏)
8.结语
1.引言
在上篇博客的结尾我们利用 while 语句加 scanf 特性实现了数据的批量输入与处理,那么实际上C语言是作为一门结构化的程序设计语言,包含了顺序结构,选择结构,循环结构三大结构,顺序结构由于过于简单就不展开细讲了,那么本篇博客就带领大家详细了解C语言选择结构的分支语句使用方法与循环结构的循环语句使用方法。
2.注释的使用
在正式讲解之前,先讲一下遗漏的注释。注释是什么?注释是程序员写给自己或其他人看的,对于自己所写代码的说明。编译器在编译运行时会把注释内容自动替换成空格,所以注释内容对程序运行没有任何影响。注释有什么用?好的注释有助于我们解读自己或别人所写的代码,让我们清楚地知道代码每一部分的功能。所以非常建议大家日常在自己代码的必要部分打上注释,这也是程序员的一个良好习惯。当然,注释通常只需要出现在必要部分,不需要写过多的不必要的注释。那么如何注释?C语言中注释方式主要有两种,一种是利用 /* */ 将注释内容包裹起来,这种方法支持多行注释且可以穿插在代码行内而不影响代码运行,但该方式无法嵌套使用,另一种是 // 后面加注释内容,该方式从 // 开始之后的整行内容都是注释,嵌套使用不影响注释效果,但一次只能注释一行,这是C99标准新加的。不过刚刚说过编译器在运行代码时会将注释内容替换成空格,所以不要在变量名等代码中间使用注释。那么在掌握了注释的用法之后,对于我们写过的代码我们可以直接将其注释掉而不是删掉,这样我们随时可以回来温故旧代码且不会影响新代码的书写。如果想要快速注释一大片代码,我们还可以使用快捷键的方式,在选中我们要注释的代码后按 Ctrl+K,Ctrl+C 就可以注释一整片代码,而再次选中后按 Ctrl+K,Ctrl+U 则可以取消注释,对应的小按钮也在上方的导航栏里,红色画线的左边是注释,右边是取消注释。


3.选择语句
首先要学习的是选择语句。
3.1.if 语句
在C语言里 if 语句的语法格式如下,其运行逻辑是,当表达式结果为真时就执行 if 控制体里的语句,否则就不执行,而在C语言中表达式结果为零就是假,非零就是真。由于 if 语句默认只控制一条执行语句,所以当 if 控制体里的执行语句只有一条时可以省去 { },但当 if 控制体里的执行语句不止一条时,必须用 { } 将所有执行语句包裹起来。通过下面两段代码的对比,小萌新们现在应该对 if 语句有了一个初步了解。表达式结果的真假只会影响 if 语句涵盖范围内的语句,对于此外的其他语句并无影响。





那么在掌握了简单的 if 语句之后,我们能否书写一个代码来输出一个数的奇偶性?显然仅靠一个 if 是不够的。那如果用两个 if ?看似可以解决这个问题,但在其他问题上可能会产生的毛病,我们后面会讲。这边讲解另一种方法,那就是和 if 一起的 else。if – else 语句的语法格式如下,其运行逻辑是,当表达式结果为真时就执行 if 控制体里的语句,否则就执行 else 控制体里的语句。同样的,表达式结果的真假只会影响 if else 语句涵盖范围内的语句,对于此外的其他语句并无影响。那么有了 else 之后我们就能写出能够正确输出结果的代码了,代码形式大概如下。这里用到了 % 操作符,这篇博客后续还会用到其他的操作符,而有关操作符的内容会在下篇博客中细讲,各位小萌新无需着急。



当我们写出如下代码并尝试去测试时会发现结果与我们设想的并不一样,这里就涉及 else 的匹配问题了,else 总是与他最接近的 if 语句进行匹配,除非人为加上 { } 改变他的匹配规则。那么在这里其实也说明了代码格式的重要性,我们平时写代码时在该缩进的地方一定要缩进,养成良好的写代码习惯是一个程序员必备的。




那么在上述代码基础上如果还要输出一个数的正负性,且只对正数做奇偶性判断输出,那该如何修改?聪明的小萌新肯定会在外面再嵌套一层 if – else 语句,那么代码就变成了下面这样。

此时我们再对代码做一下修改,将 else 与 if 连用,就可以得到下面这个代码。我们测试一下就会发现上下两段代码实现的功能是一样的,那么下面这个代码有什么优势?根据前面所学,我们已经知道单个 if 只能做一个判断,而多个 if 的使用可能会导致问题,else 则直接包含其余全部情况,可能把我们不想要的结果也包含进去,如果使用 if else 嵌套则可能在极端情况下导致代码冗长,此时就可以使用我们的 if – else if – else 语句。

我们对比下面三个例子就可以直观感受到差距,在同样的条件限制同样的输入情况下,多个 if 语句的使用并没有跑出正确结果,这是因为受 if 语句的特性影响,只要表达式结果为真,就会执行 if 控制体里的语句,如果想要改正也容易,只要对 x 做更严格的范围限制即可,但往往在复杂的问题下我们并不能一下子穷举出所有的可能情况,此时只用 if 就可能发生问题,而 if – else 语句嵌套与 if – else if – else语句虽然都运行出了正确结果,但多层的 if – else 语句嵌套使用使代码冗长不利于解读与检查错误,所以在结果有多种情况时,我们尽量使用 if – else if – else 语句。






在完整掌握了 if 语句之后,小萌新们肯定能利用他书写一个代码来判断输出一年中某个月的天数(2月认为是28天),那么具体代码如下。

3.2.switch 语句
但我们明显也能看出,if 语句在约束条件很多时的表达式往往很长,那么对于表达式的结果是与若干个常量做等值判断的长约束条件表达式,我们就可以使用另一种选择语句,也就是 switch 语句。若将上述代码改用 switch 语句表示,那么具体代码如下。

所以 switch 语句可以认为是特殊的 if 语句,switch 语句的语法格式如下,case 与后面的值之间必须有空格,不可忘记。其运行逻辑是,根据表达式结果的值,执行对应值的 case 分支语句,如果没有任何值可以匹配上,就执行 default 分支语句。其中 default 分支语句并非是必须要有的,但建议加上,且 default 分支语句的位置是任意的,无论放哪里都不会影响 switch 语句的执行,不过通常会放在末尾。值得注意的是,switch语句的表达式必须是整型表达式,case 后面所跟的值也必须是整型常量表达式。

那么在了解了 switch 语句是什么了之后,我们尝试测试先前改写的代码会发现结果并不是我们想要的,这是因为 switch 语句也有一个特性,当表达式的结果与某个 case 后的值匹配上时,会从这一条 case 分支语句开始执行,直至遇到 break 语句或者 switch 语句结束,这个现象也叫 case 穿透,如果想要避免这个现象,我们就要在 case 分支语句和 default 分治语句后面加上 break;。那么正确的代码就应该如下图。


但这样一看,switch 语句在把单个判断条件变简单的同时,也让代码无形中变长了不少。实际上我们利用 switch 语句的 case 穿透和遇到 break 语句终止执行的特性,就可以简化代码,那么最终的代码如下。

4.循环语句
到这里我们就差不多掌握了C语言的选择语句,接下来就是C语言的循环语句。
4.1.while 语句
while 语句的语法与用法都与 if 语句类似。while 语句语法格式如下,其运行逻辑是,当表达式结果为真时就循环执行 while 循环体里的语句,当表达式结果为假时跳出循环执行后续语句。由于 while 语句和 if 语句一样默认只控制一条执行语句,所以当 while 循环体里的执行语句只有一条时可以省去 { },但当 while 循环体里的执行语句不止一条时,必须用 { } 将所有执行语句包裹起来。

我们在最开始接触C语言时尝试过书写代码让程序在屏幕上打印 Hello World ! ,如果没有学习循环语句,我们想要打印 n 遍 Hello World ! 可能会傻傻的复制粘贴 n 行代码,但学习了循环结构之后,我们就可以利用循环语句来完成这件事。在最开始的 printf 语句外嵌套 while 语句,就可以得到如下代码。


我们可以看到,展示的代码除了上述所说的内容还多 i++; 这一条语句,那这一条语句的作用是什么?其实是配合 i<n 这个判断条件用来最终结束循环的。如果我们把这行语句注释掉,那么无论输入的 n 是多少,只要是一个正数,屏幕上就会源源不断的打印,直至你手动关闭程序。因为 while 语句的运行逻辑与 if 语句相同,只要表达式为真就能运行,但又区别于 if 语句只会执行一次,我们最开始设定 i=0,那么 i<n 这个表达式的结果永远为真,程序就会永远运行,我们把这样的表达式叫永真式。我们知道写代码的目的是为了让程序实现某种功能而不是一直无意义的运行下去,所以我们通常会设置一个边界值用以控制程序的循环次数,循环的每一次执行都是在向边界值靠近,直至结束循环。而循环除了按照设定好的边界值正常结束外,我们还能利用 break 语句强制结束循环,当执行语句碰到 break 语句后就会终止循环,跳出循环并执行后续语句。


4.2.do – while 语句
那么会了 while 语句之后,就顺带会了 do – while 语句。do – while 语句语法格式如下,在 do – while 语句里 while 后面结束时一定要带 ; ,不可忘记。其运行逻辑是颠倒了 while 语句原先表达式判断与循环体内执行语句的运行顺序,即先执行循环体内的语句,然后再判断表达式结果是否为真,为真就继续执行,为假则结束循环执行后续语句,所以在 do – while 语句里无论最终表达式的结果是否为真,都会至少运行一次循环体。通过两段代码的对比,我们可以明显看出区别。





4.3.for 语句
我们已知想要结束 while 或者 do – while 语句,如果不使用 break 语句强制结束,就需要有一个变量来控制循环次数,如果我们将变量的初始化,循环的判断条件,变量的更新放到一起,那我们就能得到 for 循环语句。for 语句语法格式如下,其运行逻辑是,当表达式2结果为真时就循环执行 for 循环体里的语句,当表达式2结果为假时跳出循环执行后续语句。其中表达式1仅在第一次循环开始时执行一次,完成循环变量的初始化,而每完成一次循环,循环变量都会依据表达式3进行更新,用以控制循环次数,表达式2既是循环能否继续进行的判断条件,也是循环最终结束的终止条件。不过这三个表达式也不是必须的,可以将表达式1放置到循环体外面,将表达式2与表达式3放置到循环体里面,不过不推荐。





4.4.循环语句的使用情况及嵌套使用
关于C语言的循环结构到这里也就学完了,虽然三者看上去差不多,但实际应用中 do – while 语句是用的最少的,而 for 语句是用的最多的,因为 for 语句条件控制集中易于代码维护,同时 while 语句常用于不确定循环的具体情况,只能用判断条件去做循环限制,而 for 语句常用于知道循环具体需要执行多少次,可以利用变量的更新情况来减少不必要的循环。所以在处理实际问题时需要选择合适的循环语句,有时甚至需要我们嵌套使用循环语句,具体可以参考下面这段代码。


5.break 语句与 continue 语句
前面在讲解循环时提到了 break 语句,这边深入讲解一下 break 语句的作用,以及与他类似的 continue 语句的作用。break 的作用是跳出整个循环,直接终止本次循环,在有多层循环嵌套时一个 break 只能跳出自己所在的这一层循环,就如上面展示的代码一样,for 语句里的 break 只是在找到非素数时提前结束 for 循环,出来后仍然会执行 while 循环里的语句,而借助 while 循环里的break 才能在找到素数后真正跳出 while 循环。而相比于 break,continue 的作用仅仅是跳过本次循环,如果条件满足,下一个循环仍会继续,直到结束,同时 continue 无法用于 switch 语句。通过下面两段代码的对比,各位小萌新应该会对这两个语句有一个直观理解。

![]()

![]()
6.goto 语句
我们前面说了,一个 break 只能跳出一层循环,如果我们嵌套使用了很多层循环,那么使用 break 来提前结束循环就会显得很麻烦。为此,我们需要学习一下C语言里的另一个语句——goto 语句。goto 语句作为一种比较特别的语句,首先语法格式如下,其次他需要依赖跳转标号才能在同一个函数里实现从当下位置快速跳转到标号位置。但是我们也明显可以看到,由于 goto 语句的特殊性,我们只要定义了标号并引用了标号就可以实现跳转,因此 goto 语句极其容易破坏代码原有的运行结构,如果不是为了快速从深层次的循环里跳转出来,在平时写代码时尽量不要乱用 goto 语句。



7.综合应用(类猜数字游戏)
关于选择结构与循环结构的具体应用,本篇博客就不过多的展开了,这里附上一份类猜数字游戏的源码,各位感兴趣的小萌新可以研究一下。
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #include<time.h> #include<math.h> int sum = 0; void game() { int bomb = rand() % 100 + 1; //通用形式:结果=a+rand()%(b-a+1); 可用于表示取值范围在[a,b]之间的一个随机数 printf("炸弹已埋好了(1-100层里的某一层),快去拆炸弹吧!\\n"); int guess = 0; int num = 0; int score = 0; int flag = 1; for (int i = 10; i > 0;i–) { printf("请输入你要去往的层数(仅数字),还剩余%d次:\\n",i); scanf("%d", &guess); num = guess; if (guess == bomb) { flag = 0; score += 20; printf("成功找到并拆除了炸弹,得分+20!\\n"); break; } if (abs(guess – bomb) <= 5) { score += 3; printf("近了近了,炸弹就在附近,得分+3!\\n"); } else if (abs(guess – bomb) <= 15) { score += 2; printf("已经慢慢靠近炸弹了,得分+2!\\n"); } else if (abs(guess – bomb) <= 30) { score += 1; printf("炸弹离得还是有点远,得分+1!\\n"); } else { printf("炸弹离得还挺远的,得分+0!\\n"); } } if (flag) { if (abs(num – bomb) <= 5) { score = 0; printf("BOM!真男人就要直面爆炸,得分清零!\\n"); } else if (abs(num – bomb) <= 10) { score = 0; printf("BOM!炸弹的余波直接将你哄睡着了,得分清零!\\n"); } else if (abs(num – bomb) <= 12) { score += 5; printf("精准控制!炸弹的余波在你身后停止,得分+5!\\n"); } else if (abs(num – bomb) <= 15) { score += 3; printf("准度欠佳,炸弹的余波在你身后停止,得分+3!\\n"); } else if (abs(num – bomb) <= 20) { score += 2; printf("马马虎虎,但好歹没被炸弹的余波波及,得分+2!\\n"); } else { printf("胆小如鼠,但好歹没被炸弹的余波波及,得分+0!\\n"); } } printf("本轮游戏结束,最终得分为%d!\\n", score); sum += score; } int main(){ sum = 0; int input = 0; srand((unsigned int)time(NULL)); //srand为随机种子,参数的不同使得每一次所获取的随机数不同 //time为时间戳,以当下时间与1970年1月1日0时0分的时间差为结果传值 //利用时间戳不断改变参数,使得srand随机种子的参数不再是默认的1,从而实现实时的伪随机 do { printf("——————–\\n"); printf("— 1.start game —\\n"); printf("—- 0.end game —-\\n"); printf("——————–\\n"); scanf("%d", &input); switch (input) { case 1: game(); break; case 0: printf("欢迎下次来玩,本次游戏总得分为%d!\\n", sum); break; default: printf("请输入正确的游戏选项!\\n"); break; } } while (input); return 0; }
8.结语
本篇博客到这里就结束了,希望能够帮到各位刚接触C语言的小萌新们,下篇博客将继续讲解C语言的相关知识。



