前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >详解C语言中的分支语句(下)

详解C语言中的分支语句(下)

作者头像
埋头编程
发布2024-10-16 17:15:29
850
发布2024-10-16 17:15:29
举报
文章被收录于专栏:C/C++

1.序言

续接上回,我们讲到了三个表达式之间的比较。我们想要得到中间的那个表达式是否真的大于右边的表达式,并且小于左边的表达式。

详解C语言中的分支语句(上)

代码语言:javascript
复制
//我们一开始是这样写的
int a = 10;
int b = 30;
int c = 20;

if (a < b < c)
{
	printf("认真学习\n");
}

a<b<c 在数学上是不成立,可我们居然能屏幕上打印出“认真学习”。很显然程序出现了bug,那到底问题出在哪里了呢?其实编译器在看到 a<b<c这个表达式时,它是这样拆解的:(a<b)<c,这样拆解的结果就会导致,a<b这个表达式成立,我们说过关系运算符所得到值要不就是1(真)或0(假)。那a<b这个关系表达式的值就为1,接着,它和 c 进行比较,也就是1 < c。看到这里,我相信读者们就知道为什么屏幕上仍会打印出"认真学习"。

那话又说回来,我们有办法解决这个问题吗?

答案是肯定有的,用逻辑运算符!!!

2.逻辑运算符

2.1逻辑运算符的分类

&& :逻辑与 (两侧的表达式都为真,则为真,否则为假) ||:逻辑或(两侧的表达式都为假,则为假,否则为真) ! : 逻辑非(改变单个表达式的真假)

2.1 逻辑非(!)

逻辑非的真值表
逻辑非的真值表

例子:比如我们有一个变量叫 flag,如果flag为假,要做一个什么事,就可以这样写代码:

代码语言:javascript
复制
#include<stdio.h>
int main()
{
	int flag = 0;
	
	if(!flag) 
	{
		printf("今天有没有好好吃饭啊\n");
	}
	return 0;
}

这里就用到了!。意思是如果 flag 为假,那么 !flag 就为真。!flag 为真就执行if里面的语句。

所以上面的代码的意思是当 flag 为假时,就执行if语句中的代码。

2.2 逻辑与(&&)

逻辑与的真值表
逻辑与的真值表

**&&**就是与运算符,如果用人话替待它,那就是我们口中常说的“并且”的意思。&&是一个双目运算符,使用的方式是a&&b。

只有当&&两边的表达式都为真的时候,整个表达式(a&&b)才为真,只要有一个为假,那整个表达式的值就为假。

比如最开始我们举的那个例子,正确写法应该是:

代码语言:javascript
复制
int a = 10;
int b = 30;
int c = 20;

if (b > a && b < c)
{
	printf("认真学习\n");
}
return 0;

a<b<c中文是这样表述的:b大于a,并且b小于c。(希望读者们,不要写出一开始的那个错误例子,一定要表述好后在动手写!)

再举一个例子,比如:如果我们说3月到5月,是春天,那用代码怎么实现?

代码语言:javascript
复制
#include<stdio.h>
int main()
{
	int month = 0;
	scanf("%d", &month);
	if(month >= 3 && month <= 5)
	{
		printf("春季\n");
	}
	return 0;
}

这个表达式的意思是month既要大于等于3,又要小于等于5,必须同时满足。

2.3 逻辑或(||)

逻辑或的真值表
逻辑或的真值表

|| 就是或运算符,也就是"或者"的意思。|| 也是一个双目运算符,使用方式是 a || b, || 两边的表达式只要有一个为真,整个表达式的值就为真,两边表达式的都为假时,整个表达式的值才为假。

例子:我们要说一年中月份是12月或者1月或者2月是冬天,那我们怎么用代码表示呢?

代码语言:javascript
复制
#include<stdio.h>
int main()
{
	int month = 0;
	scanf("%d", &month);
	if(month == 12 || month == 1 || month == 2)
	{
		printf("冬季\n");
	}
	return 0;
}

2.4 逻辑运算符的综合练习(闰年的判断)

题目:输入一个年份year,判断year是否为闰年 思路:判断闰年的条件(二者居其一,即可): 1.年份数能被4整除,但不能被100整除; 2.年份数能被400整除。

代码语言:javascript
复制
#include<stdio.h>
int main()
{
	int year = 0;
	scanf("%d", &year);
	
	if((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
	{
		printf("%d年是闰年\n");
	}
	return 0;
}

2.5 短路(一个逻辑运算符的有趣现象)

C语言逻辑运算符还有一个特点,它总是先对左边的表达式求值后,再向右边,对右边的表达式依次求值,这个顺序是保证的。

那在C语言中,短路是什么? 我们在上面说过,逻辑运算符是从最左边的表达式开始运算的。那如果左边表达式的值已经满足了逻辑运算符的取值特点(参考上面写的各逻辑运算符的真值表),就不再对右边的表达式求值了。这种情况就被称为短路。

如果你听到这里,对短路现象还是一知半解的话,那请耐心看完下面的例子!

如我们在前面写的代码:

代码语言:javascript
复制
if(month == 12 || month == 1 || month == 2)

如果month==12,则不用再判断month是否等于1或者2了,整个表达式的结果也就是1.

所以, || 操作符的左操作数的结果不为0时,就无需执行右操作数。

像这种仅仅根据左操作数的结果就能知道整个表达式的结果,不再对右操作数进行计算成为短路求值

为了方便读者们能够更好的吸收这块知识点,我把所有短路求值的规律写在下面: II:如果遇到左操作数为1时,则无需计算右操作数的真值,整个表达式的值为1; &&:如果遇到左操作数为0时,则无需计算右操作数的真值,整个表达式的值为0。

练习:阅读下面的代码,计算代码输出的结果

代码语言:javascript
复制
#include<stdio.h>
int main()
{
	int i = 0, a = 0, b = 2, c = 3, d = 4;
	i = a++ && ++b && d++;
	// i = a++ || ++b ||d++;
	printf("i = %d\na = %d\nb = %d\nc = %d\nd = %d\n", i, a, b, c, d);
	return 0;
}

答案:

&&类型的答案
&&类型的答案
||类型的答案
||类型的答案

3. switch语句

除了if语句外,C语言还提供了switch语句来实现分支结构。

switch语句是一种特殊形式的if…else结构,用于判断条件有多个结果的情况。它把多重的else…if改成了更易用、可读性更好的形式。

语法结构:

代码语言:javascript
复制
switch (expression)
{
	case value1:statement
	case value2:statement
	...
	default:statement
}

上面代码中,根据表达式expression不同的值,执行相应的case语句分支。如果找不到对应的值,就执行default分支

注意:

  1. switch后面的expression必须是整型表达式
  2. case后的值,必须是整型常量表达式

3.1 switch语句与if语句的比较

练习:输入任意一个整数值,计算除3之后的余数

代码语言:javascript
复制
//if...else结构的写法
#include<stdio.h>
int main()
{
	int num = 0;
	scanf("%d", &num);

	if (num % 3 == 1)
	{
		printf("余数为1\n");
	}
	else if(num % 3 ==2)
	{
		printf("余数为2\n");
	}
	else
	{
		printf("余数为0\n");
	}
	return 0;
}
代码语言:javascript
复制
#include<stdio.h>
int main()
{
	int num = 0;
	scanf("%d", &num);

	switch (num % 3)
	{
	case 0:
		printf("余数为0\n");
		break;
	case 1:
		printf("余数为1\n");
		break;
	case 2:
		printf("余数为2\n");
		break;
	}

	return 0;
}

上述代码中,我们要注意switch语句中的写法:

  1. case和后面的数字中间必须有一个空格
  2. 每一个case语句中执行完相应的代码后,需要加上break,才能跳出这个switch语句。

可能有的读者就会问,那如果我就是不写break会发生什么?

下面我们就来探讨一下这个问题。

3.2 switch中的break

前面的代码中,如果我们去掉case语句中的break,会发生什么?

代码语言:javascript
复制
#include<stdio.h>
int main()
{
	int num = 0;
	scanf("%d", &num);

	switch (num % 3)
	{
	case 0:
		printf("余数为0\n");
	case 1:
		printf("余数为1\n");
	case 2:
		printf("余数为2\n");
	}
	return 0;
}
去掉break的情况
去掉break的情况

诶呦,这完全不是我们想要的结果啊。我们输入3,按道理来说,它只会给我们打印“余数为0”,可这为什么会把剩下的两个也一并打印了? 这个就是不写break的弊端 仔细研究一下这个代码,当执行到scanf语句时,我们在屏幕上输入一个3。这步就意味着我们给num赋值为3了,接着就开始执行switch语句。 通过switch语句后面的整型表达式得出的值,根据case后面的值进行匹配。我们这里就进入到了case 0中,之后就打印了"余数为0",就在这时我们得到了我们想要的结果。不过,一件可怕的事情也随之发生,你会发现switch语句并没有退出,而是接着执行了case 1分支里面的语句,接着就打印了“余数为1”。后面的过程类似,就不再赘述了。

究其原因,你会发现就因为没在每个case语句执行完后加上个break,就酿成了这种错误。可想而知,break对于switch语句的重要性

3.3 switch中的default

在使用switch语句的时候,我们可能会遇到一种情况,比如switch后的表达式的值,没有一个case后面的值能够与之匹配。这个时候,switch语句有两种处理方法:第一种,不处理(冷暴力);第二种,加一个default字句

例子:打印星期,如果day的输入不是1~7的值,我们就要提示:输入错误。

代码语言:javascript
复制
#include <stdio.h>
int main()
{
 int day = 0;
 scanf("%d", &day);
 
 switch(day)
 {
 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;
default:
	printf("输入错误\n");
	break;
 }
 
 return 0;
}

3.4 switch语句中的case和default的顺序问题

细心的读者可能就会发现,我每次写代码时,都会把default写在switch语句的最后一个分支。这个写法是固定的吗?其实不然。

在switch语句中case语句和default语句是没有顺序要求的,只要你的顺序和语法满足实际需求即可。

不过要养成良好的编程习惯的话,建议把default写在最后。

4.总结

在分支语句中,我们学习了

  • if语句的写法以及如何应用
  • 关系表达式(<、>、>=、<=、==、!=)
  • 逻辑表达式(&&、||、!、短路问题)
  • switch语句

希望读者们能够快乐地生活,快乐地学习。学习很难,但坚持一定很酷!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-05-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.序言
  • 2.逻辑运算符
    • 2.1逻辑运算符的分类
      • 2.1 逻辑非(!)
        • 2.2 逻辑与(&&)
          • 2.3 逻辑或(||)
            • 2.4 逻辑运算符的综合练习(闰年的判断)
              • 2.5 短路(一个逻辑运算符的有趣现象)
              • 3. switch语句
                • 3.1 switch语句与if语句的比较
                  • 3.2 switch中的break
                    • 3.3 switch中的default
                      • 3.4 switch语句中的case和default的顺序问题
                      • 4.总结
                      领券
                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档