✨个人主页: Anmia.
🎉所属专栏: C Language🎃操作环境: Visual Studio 2019 版本
目录
什么是分支语句?
if语句
if
if - else单分支
if - else if - else ...多分支
if - if嵌套
switch语句
基本语法
break
default
练习
练习1
练习2
练习3
练习4
练习5
练习6
练习7
练习8
练习9
练习10
练习11
练习12
练习13
练习14
后言
什么是分支语句?
在生活中需要进行判断和选择的事情很多。
如:
- 如果你在家,我去拜访你;(需要判断你是否在家)
- 如果考试成绩是班级前三名,就可以得到奖励;(需要判断是否为班级前三名)
- 如果遇到绿灯,可以通行;(需要判断是否为绿灯)
- 70岁以上的老人,乘坐公交车免费;(需要判断是否满70岁)
从以上的例子可以看出,条件判断是一个逻辑值:“是”或“否”,例如,在判断是否为班级前3名时,答案只有两种可能:“是前三名”和“不是前三名”,不会是“第5名”或者“第10名”等。
在计算机语言中,用“真”和“假”(1/0)来表示“是”或者“否”。
在程序中,用选择结构来检查所指定的条件的是否满足,并判断结果执行哪种操作。
在C语言的两种分支结构
- if
- switch
if语句
if
if(表达式)
{
语句....
}
- 流程图
代码逻辑:如果 if 表达式条件成立,则执行语句。如果条件不成立,则不执行 if 中的语句。
if - else单分支
if(表达式)
{
语句1...
}
else
{
语句2...
}
- 流程图
代码逻辑:如果 if 表达式成立,则执行语句1,否则执行语句2。
if - else if - else ...多分支
if(表达式1)
{
语句1...
}
else if(表达式2)
{
语句2...}
else
{
语句3...}
- 流程图
- 代码逻辑:如果if 表达式1条件成立,则执行语句1,否则走else,再判断表达式2的条件。如果表达式2条件成立,执行语句2,否则执行语句3。
- 例子:多分支一般用于分段,如判断一个人的分数。
如果小于70分,则输出general,否则判断是否在70-80之间(注意:如果前面的if条件不成立,本次if会自动把前面的条件加入本次判断范围,前面小于70不成立说明分数不在70以下,在判断是否小与80时会自动加入先前的判断结果,则呈现本次只判断70-80之间)。如果70-80之间也不成立,则走了else,本次else后面没有if,说明本次范围时除了前面的全部范围,所以80以上的数字都会输出excellent。#include <stdio.h> int main() { int score = 0; scanf("%d", &score); if (score < 70) { printf("general"); } else if (score < 80) { printf("good"); } else { printf("excellent"); } return 0; }
if - if嵌套
if(表达式1)
{
if(表达式2){
语句1...
}
}
- 流程图
代码逻辑:如果表达式1成立,执行外层 if 中的语句,又碰到 if 再判断表达式2,如果成立则执行语句1,否则不执行。
例子:if嵌套,无非就是多层条件判断。如要购买一双鞋,购买条件是必须是会员,商品价格是100元。在这个例子中,不难看出,如果不是会员有钱也买不了,所以外层 if 可以设计成判断是否是会员。如果是(内层if)再判断是否够钱买,如果不是,想都美咯。
#include <stdio.h> int main() { int vip = 0;// 0 表示无会员,1表示有会员。 int cash = 0; scanf("%d %d", &vip, &cash); if (vip == 1) { if (cash >= 100) { printf("鞋子"); } } return 0; }
结合上面的例子,相信大家应该对if常见形式有一定的认识吧!接下来看看switch吧。
switch语句
if是分支语句,为什么要会有switch呢?既然存在,必有它的意义。我们来看个例子。
我们需要从从键盘输入1-7任意一个数字,让编译器输出对应的星期数。如输入1,输出“Monday”。用 if 语句先试试吧
#include <stdio.h>
int main()
{
int day = 0;
scanf("%d", &day);
if (day == 1)
{
printf("Monday\n");
}
else if (day == 2)
{
printf("Tuesday\n");
}
else if (day == 3)
{
printf("Wednesday\n");
}
else if (day == 4)
{
printf("Thursday\n");
}
else if (day == 5)
{
printf("Friday\n");
}
else if (day == 6)
{
printf("Saturday\n");
}
else if (day == 7)
{
printf("Sunday\n");
}
return 0;
}
经过多次调试,发现 if 语句也是可以完成的。但不会感觉很麻烦吗?代码量大,结构不是很清晰。那用switch试试?
#include <stdio.h>
int main()
{
int day = 0;
scanf("%d", &day);
switch (day)
{
case 1:printf("Monday\n"); break;
case 2:printf("Tuesday\n"); break;
case 3:printf("Wednesday\n"); break;
case 4:printf("Thursday\n"); break;
case 5:printf("Friday\n"); break;
case 6:printf("Saturday\n"); break;
case 7:printf("Sunday\n"); break;
}
return 0;
}
对于这些“点”的范围控制。switch多分支似乎对比 if 多分支更加简洁和明了。数字1 2 3...这些是一个常量字符表达式,字面值等。用 if 写起来比较麻烦,switch正是它的强项,但对范围区间的操作,还得是 if 。所以还是具体问题具体分析,根据需求选择合适的分支语句。
基本语法
switch(整型表达式)
{
case 整形常量表达式:
语句;......
}
这个是switch的基本语法形式,整型表达式是条件,整型常量表达式是整型表达式的其中一种可能性,如果相等则执行后面的语句,直到遇到break,或者到switch语句结束自动结束。
那break又是什么呢?
break
在switch语句中,我们没办法直接实现分支,搭配break使用才能实现真正的分支。
以上面星期的例子为例,如果不加break会怎么样?
#include <stdio.h> int main() { int day = 0; scanf("%d", &day); switch (day) { case 1:printf("Monday\n"); case 2:printf("Tuesday\n"); case 3:printf("Wednesday\n"); case 4:printf("Thursday\n"); case 5:printf("Friday\n"); case 6:printf("Saturday\n"); case 7:printf("Sunday\n"); } return 0; }
多次调试后不难看出,没有break语句会从当前case后的语句执行到switch语句完全结束。这似乎没有实现多分支的效果。
switch搭配break循环可以起到跳出当前switch的效果。如上面的成功案例,假如case 1:成立,输出Monday后遇到break就会跳出当前switch,如果没有break会继续向下执行,直到遇到break结束,如果没有break会执行完整个switch中的语句。因此要合理的应用好break。
default
如果表达的值与所有的case标签的值都不匹配怎么办?
其实也没什么,结构就是所有的语句都被跳过而已。
程序并不会终止,也不会报错,因为这种情况在C中并不认为是个错误。
但是,如果你并不想忽略不匹配所有标签的表达式的值时该怎么办呢?
你可以在语句列表中增加一条default子句,把下面的标签
default:
写在任何一个 case 标签可以出现的位置。
当 switch 表达式的值并不匹配所有 case 标签的值时,这个 default 子句后面的语句就会执行。
所以,每个switch语句中只能出现一条default子句。
但是它可以出现在语句列表的任何位置,而且语句流会像执行一个case标签一样执行default子句。
编程好习惯:
在每个 switch 语句中都放一条default子句是个好习惯,甚至可以在后边再加一个 break 。
#include <stdio.h>
int main()
{
printf("您是否是本店会员?(1:是 / 0:否)\n:>");
int input = 0;
scanf("%d", &input);
switch (input)
{
case 1:printf("会员请进"); break;
case 0:printf("你不是会员"); break;
default:printf("输入错误,请重新输入!"); break;
}
return 0;
}
上面有一个判断是否为会员的代码,是则输入1,不是则输入0,如果输入其他则提示输入错误,这里就可以用default语句了。
练习
练习是对知识点掌握程度的检测,接下来有一些关于分支语句的题目,认真看看一定有所收获!
练习1
下面代码执行的结果是
#include <stdio.h>
int main()
{
int i = 0;
for (i = 0; i<10; i++)
{
if (i = 5)
printf("%d ", i);
}
return 0;
}
解析:
上述代码本来的想法应该是:循环10次,每次循环时如果i==5则打印i的结果。
但if语句中表达式的==写成了赋值符号=,相当于每次循环尽量都是将i的值设置成了5,5为真,因此每次都会打印5
i每次修改成5打印后,i的值永远不会等于10,因此造成死循环
故:死循环的打印5
练习2
关于if语句说法正确是:( )
A.if语句后面只能跟一条语句
B.if语句中0表示假,1表示真
C.if语句是一种分支语句,可以实现单分支,也可以实现多分支
D.else语句总是和它的对齐的if语句匹配
解析:
答案解析:
A:错误,if之后可以跟多条语句,跟多条语句时需要使用{}括起来
B:错误,0表示假,非零表示真
C:正确
D:不一定,要看具体的代码,如果代码不规范,可能没有对齐,比如:
if() if() else ;
上述else虽然是和外层if对齐,但是会和内部if进行匹配。(else 会和自己最近的未匹配的if匹配)
练习3
int func(int a)
{
int b;
switch (a)
{
case 1: b = 30;
case 2: b = 20;
case 3: b = 16;
default: b = 0;
}
return b;
}
则func(1) = ( ).
解析:
switch的每个case之后如果没有加break语句,当前case执行结束后,会继续执行紧跟case中的语句。
func(1)可知,在调用func时形参a的值为1,switch(a)<==>switch(1),case 1被执行,因为该switch语句中所有分支下都没有增加break语句,因此会从上往下顺序执行,最后执行default中语句返回。
因此:选择D
练习4
switch(c)语句中,c不可以是什么类型( )
A.int
B.long
C.char
D.float
解析:
switch语句中表达式的类型只能是:整形和枚举类型
D选项为浮点类型,不是整形和枚举类型
因此:选择D
练习5
下面代码的执行结果是什么( )
#include <stdio.h>
int main() {
int x = 3;
int y = 3;
switch (x % 2) {
case 1:
switch (y)
{
case 0:
printf("first");
case 1:
printf("second");
break;
default: printf("hello");
}
case 2:
printf("third");
}
return 0;
}
解析:
switch语句时多分支的选择语句,switch中表达式结果命中那个case,就执行该case子项,如果case子项后没有跟break语句,则继续往下执行。
关于该题解析,请看以下注解:
#include <stdio.h> int main() { int x = 3; int y = 3; switch (x % 2) { // x%2的结果为1,因此执行case1 case 1: switch (y) // y是3,因此会执行case3,而case3不存在,那只能执行default { case 0: printf("first"); case 1: printf("second"); break; default: printf("hello"); // 打印hello,打印完之后,内部switch结束,此时外部case1结束 } // 因为外部case1之后没有添加break语句,所以继续执行case2 case 2: // 打印third printf("third"); // 外部switch结束 } return 0; }
即:先在内部switch的default位置打印hello,紧接着在外部case2中打印third
因此:选择D
练习6
关于switch说法不正确的是:( )
A.switch语句中的default子句可以放在任意位置
B.switch语句中case后的表达式只能是整形常量表达式
C.switch语句中case子句必须在default子句之前
D.switch语句中case表达式不要求顺序
解析:
A:正确,可以放在任意位置,但是一般建议最好还是放在最后
B:正确,case语句后一般放整形结果的常量表达式或者枚举类型,枚举类型也可以看成是 一个特殊的常量
C:错误,没有规定case必须在default之前,一般case最好放在default之前
D:正确,但一般还是按照次序来
因此:选择C
练习7
写一个代码打印1-100之间所有3的倍数的数字
解析:
#include <stdio.h> int main() { int i = 0; for(i=1; i<=100; i++) { if(i%3==0) { printf("%d ", i); } } return 0; }
for循环遍历数组,if 判断如果 1-100之间的数取模后结果为0的,则输出这个数。
练习8
写代码将三个整数数按从大到小输出。
例如:
输入:2 3 1
输出:3 2 1
解析:
#include <stdio.h> int main() { int a, b, c; scanf("%d%d%d", &a, &b, &c); if (a < b) { int tmp = a; a = b; b = tmp; } if (a < c) { int tmp = a; a = c; c = tmp; } if (b < c) { int tmp = b; b = c; c = tmp; } printf("%d %d %d\n", a, b, c); return 0; }
思路:
- 首先,我们可以使用第一个 if 语句来比较
a
和b
的大小。如果a
小于b
,那么我们可以交换它们的值,确保a
是其中较大的数。这样,我们就能确保a
是三个数中最大的数。- 接下来,我们使用第二个 if 语句来比较
a
和c
的大小。如果a
小于c
,我们再次进行交换,确保a
是三个数中最大的数。- 最后,我们使用第三个 if 语句来比较
b
和c
的大小。如果b
小于c
,我们进行最后一次交换,确保b
是三个数中的第二大数。这样,通过三个 if 语句的比较和交换,我们可以将三个数按照从大到小的顺序排列。最后,我们使用 printf函数将排序后的结果输出。
这种思路可以确保每一次比较和交换都能将当前最大的数放在正确的位置上,从而实现整个排序过程。
练习9
写一个代码:打印100~200之间的素数
解析:
素数:即质数,除了1和自己之外,再没有其他的约数,则该数据为素数,具体方式如下//方法一:试除法
int main() { int i = 0; int count = 0; // 外层循环用来获取100~200之间的所有数据,100肯定不是素数,因此i从101开始 for(i=101; i<=200; i++) { //判断i是否为素数:用[2, i)之间的每个数据去被i除,只要有一个可以被整除,则不是素数 int j = 0; for(j=2; j<i; j++) { if(i%j == 0) { break; } } // 上述循环结束之后,如果j和i相等,说明[2, i)之间的所有数据都不能被i整除,则i为素数 if(j==i) { count++; printf("%d ", i); } } printf("\ncount = %d\n", count); return 0; } //上述方法的缺陷:超过i一半的数据,肯定不是i的倍数,上述进行了许多没有意义的运算,因此可以采用如下
// 方法二:每拿到一个数据,只需要检测其:[2, i/2]区间内是否有元素可以被2i整除即可,可以说明i不是素数
int main() { int i = 0; int count = 0; for(i=101; i<=200; i++) { //判断i是否为素数 //2->i-1 int j = 0; for(j=2; j<=i/2; j++) { if(i%j == 0) { break; } } if(j>i/2) { count++; printf("%d ", i); } } printf("\ncount = %d\n", count); return 0; }
- 为什么是逐个检查该数字是否可以被2到i/2之间的任何数字整除?
因为在判断一个数字是否为素数时,只需要检查它是否能被小于等于它一半的数字整除即可。
假设一个数字n不是素数,即存在一个大于1且小于等于n的数字m能够整除n,那么必定存在一个因子p,使得pm=n。如果p和m都大于n的一半,那么pm也会大于n,与n相等矛盾。因此,我们只需要检查小于等于n一半的数字是否能整除n,即可确定n是否为素数。
所以,内部循环的范围是从2到i/2,用来逐个检查是否存在能整除当前数字i的数。如果存在能整除i的数,那么i就不是素数;如果内部循环完全执行完毕,即没有找到能整除i的数,那么i就是素数。
方法二还是包含了一些重复的数据,再优化:
方法三:
如果i能够被[2, sqrt(i)]之间的任意数据整除,则i不是素数
原因:如果 m 能被 2 ~ m-1 之间任一整数整除,其二个因子必定有一个小于或等于sqrt(m),另一个大于或等于 sqrt(m)。int main() { int i = 0; int count = 0; for(i=101; i<=200; i++) { //判断i是否为素数 //2->i-1 int j = 0; for(j=2; j<=sqrt(i); j++) { if(i%j == 0) { break; } } //... if(j>sqrt(i)) { count++; printf("%d ", i); } } printf("\ncount = %d\n", count); return 0; }
方法4
继续对方法三优化,只要i不被[2, sqrt(i)]之间的任何数据整除,则i是素数,但是实际在操作时i不用从101逐渐递增到200,因为出了2和3之外,不会有两个连续相邻的数据同时为素数int main() { int i = 0; int count = 0; for(i=101; i<=200; i+=2) { //判断i是否为素数 //2->i-1 int j = 0; for(j=2; j<=sqrt(i); j++) { if(i%j == 0) { break; } } //... if(j>sqrt(i)) { count++; printf("%d ", i); } } printf("\ncount = %d\n", count); return 0; }
练习10
打印1000年到2000年之间的闰年
解析:
要求1000年到2000年之间的闰年,只需要知道求解闰年的方法即可。
闰年的条件:如果N能够被4整除,并且不能被100整除,则是闰年
或者:N能被400整除,也是闰年
即:4年一润并且百年不润,每400年再润一次写法1:
#include <stdio.h> int main() { int year = 0; for(year=1000; year<=2000; year++) { //判断year是否为闰年 if(year%4==0) // 如果year能够被4整除,year可能为闰年 { if(year%100!=0) // 如果year不能内100整除,则一定是闰年 { printf("%d ", year); } } if(year%400 == 0) // 每400年再润一次 { printf("%d ", year); } } return 0; }
写法2:
#include <stdio.h> int main() { int year = 0; for(year=1000; year<=2000; year++) { if(((year%4==0)&&(year%100!=0))||(year%400==0)) { printf("%d ", year); } } return 0; }
练习11
给定两个数,求这两个数的最大公约数
例如:
输入:20 40
输出:20
解析:
最大公约数:即两个数据中公共约数的最大者。
求解的方式比较多,暴力穷举、辗转相除法、更相减损法、Stein算法算法
此处主要介绍:辗转相除法
思路:
例子:18和24的最大公约数
第一次:a = 18 b = 24 c = a%b = 18%24 = 18
循环中:a = 24 b=18
第二次:a = 24 b = 18 c = a%b = 24%18 = 6
循环中:a = 18 b = 6
第三次:a = 18 b = 6 c=a%b = 18%6 = 0
循环结束
此时b中的内容即为两个数中的最大公约数。#include <stdio.h> int main() { int a = 18; int b = 24; int c = 0; while(c=a%b) { a = b; b = c; } printf("%d\n", b); return 0; }
练习12
在屏幕上输出9*9乘法口诀表
解析:
两个循环进行控制
外层循环控制打印多少行
内部循环控制每行打印多少个表达式以及表达式内容,
比较简单,具体参考代码#include <stdio.h> int main() { int i = 0; //控制行数 for(i=1; i<=9; i++) { //打印每一行内容,每行有i个表达式 int j = 0; for(j=1; j<=i; j++) { printf("%d*%d=%2d ", i, j, i*j); } printf("\n"); } return 0; }
练习13
求10 个整数中最大值
解析:
- 采用循环的方式输入一个数组
- 使用max标记数组中的最大值,采用循环的方式依次获取数组中的每个元素,与max进行比较,如果arr[i] 大于max,更新max标记的最大值,数组遍历结束后,max中保存的即为数组中的最大值。
#include <stdio.h> int main() { int arr[10] = {0}; int i = 0; int max = 0; for(i=0; i<10; i++) { scanf("%d", &arr[i]); } // max = arr[0]; for(i=1; i<10; i++) { if(arr[i]>max) max = arr[i]; } printf("max = %d\n", max); return 0; }
练习14
计算1/1-1/2+1/3-1/4+1/5 …… + 1/99 - 1/100 的值,打印出结果
解析:
从上述表达式可以分析出
- 该表达式主要由100项,基数项为正,偶数项为负
- 设置一个循环从1~100,给出表达式中的每一项:1.0/i, 注意此处不能使用1,否则结果全部为0
- 然后使用flag标记控制奇偶项,奇数项为正,偶数项为负
- 然后将所有的项相加即可
#include <stdio.h> int main() { int i = 0; double sum = 0.0; int flag = 1; for(i=1; i<=100; i++) { sum += flag*1.0/i; flag = -flag; } printf("%lf\n", sum); return 0; }
后言
本篇较为详细的将了分支语句中的重点,以及14道测试题检测学习情况。希望对你有所帮助。