1.什么是语句?
C语言的语句可以分为以下五类:
①表达式语句;
②函数调用语句;
③复合语句;
④空语句;
⑤控制语句;
而本次我们要介绍的分支和循环语句就属于控制语句的范畴。
简单来说,控制语句用于控制程序的执行流程,以实现程序的各种结构方式(C语言支持的三种结构:顺序结构、选择结构、循环结构),它们由特定的语句定义符组成,C语言有九种控制语句。这九种控制语句又可以分为以下三类:
1.分支语句(条件判断语句):if语句、switch语句;
2.循环语句:do while语句、while语句、for语句;
3.转向语句:break语句;goto语句;continue语句;return语句。
2.分支语句(选择结构)
一生当中,我们面临着许多选择,比如高考后选择哪所大学又选择哪个专业,又比如大学毕业后是选择接着读研还是直接就业亦或是选择创业……这些都是选择!而C语言正是从实际生活出发为我们提供了选择结构,它包括if语句和switch语句。
2.1 if语句
语法结构(初识C语言1中提到过)
单分支:
①if(表达式)
语句;
意思是:若表达式的值为真(非0),则往下执行语句。
②if(表达式)
语句1;
else
语句2;
意思是:若表达式的值为真(非0),则执行语句1;若为假(0),则执行语句2。
多分支:
③if(表达式1)
语句1;
else if(表达式2)
语句2;
else
语句3;
意思是:若表达式1的值为真(非0),则执行语句1;为假(0),则判断表达式2的值,若为真则执行语句2,若为假则执行语句3。
④更多的分支以此类推。
利用选择语句我们想实现这样一个多分支程序:
如果年龄在12岁以下我们输出‘少年’;13~18岁输出‘青少年’;19~35岁输出‘青年’;36~70岁输出‘老青年’;71~100岁输出‘老年’;101岁以上输出‘老寿星’;有代码:
#include <stdio.h> int main() { int age = 12; printf("请输入年龄:\n"); scanf("%d", &age); if (age <= 12) { printf("少年\n"); } else if (age >= 13 && age <= 18) { printf("青少年\n"); } else if (age >= 19 && age <= 35) { printf("青年\n"); } else if (age >= 36 && age <= 70) { printf("老青年\n"); } else if (age >= 71 && age <= 100) { printf("老年\n"); } else { printf("老寿星\n"); } return 0; }
运行结果:
2.2 switch语句
2.2.1switch语句基本形式
switch语句也是一种分支语句,常常用于多分支语句。
比如:我们想
输入1,输出一月;输入2,输出二月;输入3,输出三月;输入4,输出四月;输入5,输出五月;输入6,输出六月;输入7,输出七月;输入8,输出八月;输入9,输出九月;输入10,输出十月;输入11,输出十一月;输入12,输出十二月。
如果用if...else当然也能够实现,可是那样写未免太繁琐了,这时候我们就可以用到switch语句了。
switch语句基本形式:
switch(整型表达式)
{
case 整型常量表达式1:
语句1;
case 整型常量表达式2:
语句2;
......
}
依此,上述问题的代码就可以这样写:
#include <stdio.h> int main() { int mon = 0; scanf("%d", &mon); switch (mon) { case 1: printf("一月\n"); case 2: printf("二月\n"); case 3: printf("三月\n"); case 4: printf("四月\n"); case 5: printf("五月\n"); case 6: printf("六月\n"); case 7: printf("七月\n"); case 8: printf("八月\n"); case 9: printf("九月\n"); case 10: printf("十月\n"); case 11: printf("十一月\n"); case 12: printf("十二月\n"); } return 0; }
输出结果:
这时候问题就发生了:我们输入1想得到的只有一月,可是你把一到十二个月都给我输出了,这是怎么回事呢?!
这是因为,case后面的常量表达式实际上只起语句标号作用,而不起条件判断作用,即:这个常量表达式只是开始执行处的入口符号。
因此,case后面的表达式一旦与switch后面圆括号里的表达式的值相匹配,程序进入到switch语句后就从此标号处开始执行,并且执行完一个case语句后就自动进入到下一个case语句继续执行,直到退出switch语句。
那么,怎么才能得到我们想要的结果呢?这时就不得不用到我们的转向语句break了。
2.2.2在switch语句中的break
因此在switch语句中,我们没法直接实现分支,搭配break使用才能实现真正的分支。(break翻译成中文就有打破、中止的意思。)
所以上述问题的代码可以这样来写:
#include <stdio.h> int main() { int mon = 0; scanf("%d", &mon); switch (mon) { case 1: printf("一月\n"); break; case 2: printf("二月\n"); break; case 3: printf("三月\n"); break; case 4: printf("四月\n"); break; case 5: printf("五月\n"); break; case 6: printf("六月\n"); break; case 7: printf("七月\n"); break; case 8: printf("八月\n"); break; case 9: printf("九月\n"); break; case 10: printf("十月\n"); break; case 11: printf("十一月\n"); break; case 12: printf("十二月\n"); break; } return 0; }
运行结果:
有时候我们的需求变了:
我们想输入1~3,输出的是属于第一季度;输入4~6,输出属于第二季度;输入7~9,输出属于第三季度;输入10~12,输出属于第四季度。
我们便可以这样实现:
#include <stdio.h> int main() { int mon = 0; scanf("%d", &mon); switch (mon) { case 1: case 2: case 3: printf("属于第一季度\n"); break; case 4: case 5: case 6: printf("属于第二季度\n"); break; case 7: case 8: case 9: printf("属于第三季度\n"); break; case 10: case 11: case 12: printf("属于第四季度\n"); break; } return 0; }
运行结果:
2.2.3default子句
思考这样的一个问题:如果表达式的值与所有的case标签的值都不匹配怎么办?就像上面的问题,如果我们输入的数字不是1~12,我偏偏要输入13,这时候会出现什么结果呢?
其实也不会有什么大问题,如果那样做了,程序会正常运行,也不会报错,但是你会发现程序没有输出值就直接结束了。
可是,我不想要程序这样,我想让程序反馈给我一个信息,我想让它告诉我:你输错值了,重新输入吧!
这时候就轮到default上场了:
(default翻译成中文就有违约、默认的意思)当我们想达到如上所说的目的时,就可以在任何一个case标签后加上default。如图:
注意:每个switch语句中只能出现一条default子句,但是它可以放在任何一个case语句的后面,而且语句流会像执行一个case标签一样执行default子句。因此大多数情况下我们都将其放在switch语句的最后面,即最后一个case语句的后面,一方面是让代码看起来更有层次感,另一方面因为大多数情况下我们输入的值可能并轮不到default发挥作用,放在最后可以尽量减少default的执行,提高程序运行效率。
3.循环语句
说选择语句的时候,假如我们在面临大学毕业的选择时选择了考研,并且明确了目标一定一定要考上清华的研究生,一年考不上我就二战,二战考不上我就三战,三战考不上我就……直到考上为止。这就是一个循环的过程,联系实际生活,C语言也为我们提供了循环语句,分别为while语句,do...while语句,for语句。
3.1while语句
3.1.1while语句基本形式
while语句在初识C语言1中提到过,见初识C语言1(4.2).
3.1.2while语句中的break与continue
break介绍
break在前面的switch中提到过,其在程序中的作用如出一辙,看代码:
#include <stdio.h> int main() { int i = 1; while (i <= 9) { printf("%d ", i); i = i + 1; } return 0; }
我们已经知道这样一串代码打印的是数字1~9,可是我又把代码这样写会出现什么结果呢?
可见,当i=5时,循环直接结束了。
总结:break在while循环中的作用:
其实在循环中只要遇到break,就停止后期的所有的循环,直接终止循环。
所以:while中的break是用于永久终止循环的。
continue介绍
我们把上面代码中的break换成continue会发生什么情况呢?看图:
可见程序输出也是只输出了1 2 3 4,与break似乎一样,可是仔细观察,此时的光标一直在闪烁,程序并没有运行结束呀!这是为什么呢?
先不解释,我们把i=i+1;放到if的上面再观察一下运行结果:
可见这次5没有输出,这又是为什么呢?
这就涉及到continue的用法了:
continue是用于终止本次循环的,也就是continue后面的代码不会再执行,而是直接跳转到while语句的判断部分,进行下一次循环的入口判断。
即:在第一个程序中,当i=5时,遇到continue,程序跳转回到while的判断部分,发现i=5小于9,于是继续进入循环,每次遇到continue又回来,发现i一直都是等于5的,所以程序一直在此之间循环往复,continue后面的程序到死都不会执行,程序也就永远不会结束,也就是说死循环了!
可是在第二个程序中,当i=5时,遇到continue,程序跳转回到while的判断部分,发现i=5小于9,于是继续进入循环,可是接着我们就遇到i=i+1了呀,此时的i就等于6,也就是说,整个程序跳过了i=5,程序正常结束。
3.2for语句
我们已经知道了while循环,但是为什么还要一个for循环呢?首先来看一下for循环的语法:
3.2.1for循环语法
for(表达式1;表达式2;表达式3)
{
循环语句;
}
解释:
表达式1:为初始化部分,用于初始化循环变量;
表达式2:为条件判断部分,用于判断循环什么时候终止;
表达式3:为调整部分,用于循环条件的调整。
3.2.2for循环实例
与while一样,我们先打印数字1~9:
#include <stdio.h> int main() { int i = 0; for (i = 1; i <= 9; i = i + 1) printf("%d ", i); return 0; }
再打印九九乘法表:
#include <stdio.h> int main() { int i = 0; int j = 0; for (i = 1; i <= 9; i = i + 1) { for (j = 1; j <= i; j = j + 1) { printf("%d*%d=%d ", j, i, i * j); } printf("\n"); } return 0; }
3.2.3for循环与while循环比较
打印数字1~9:
我们可以发现在while循环中依然存在循环的三个必须条件,可是如果循环体很长的话,while循环中的三个部分很可能偏离较远,查找修改起来就不够集中方便。
因此,for循环使用的频率会更高。
3.3do...while循环
3.3.1do语句的语法
do
{
循环体;
}
while(表达式);
3.3.2do语句的特点
do与while和for语句不同的是,后者是先判断条件再进入循环,而前者是先进入循环执行一次循环体再判断条件,也就是说,在do...while语句中,循环至少要进行一次,因其使用场景有限,所以do...while循环使用的频率是最低的。
3.3.3do...while循环实例
打印数字1~9:
最后:
(break与continue也可以用在for循环和do...while循环中,它们的意义与在while中的意义是一样的,但也并不是完全相同,大体思路与while相似,所以在for与do...while中也就没有提到break与continue的内容)