续接上回,我们讲到了三个表达式之间的比较。我们想要得到中间的那个表达式是否真的大于右边的表达式,并且小于左边的表达式。
//我们一开始是这样写的
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。看到这里,我相信读者们就知道为什么屏幕上仍会打印出"认真学习"。
那话又说回来,我们有办法解决这个问题吗?
答案是肯定有的,用逻辑运算符!!!
&& :逻辑与 (两侧的表达式都为真,则为真,否则为假) ||:逻辑或(两侧的表达式都为假,则为假,否则为真) ! : 逻辑非(改变单个表达式的真假)
例子:比如我们有一个变量叫 flag,如果flag为假,要做一个什么事,就可以这样写代码:
#include<stdio.h>
int main()
{
int flag = 0;
if(!flag)
{
printf("今天有没有好好吃饭啊\n");
}
return 0;
}
这里就用到了!。意思是如果 flag 为假,那么 !flag 就为真。!flag 为真就执行if里面的语句。
所以上面的代码的意思是当 flag 为假时,就执行if语句中的代码。
**&&**就是与运算符,如果用人话替待它,那就是我们口中常说的“并且”的意思。&&是一个双目运算符,使用的方式是a&&b。
只有当&&两边的表达式都为真的时候,整个表达式(a&&b)才为真,只要有一个为假,那整个表达式的值就为假。
比如最开始我们举的那个例子,正确写法应该是:
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月,是春天,那用代码怎么实现?
#include<stdio.h>
int main()
{
int month = 0;
scanf("%d", &month);
if(month >= 3 && month <= 5)
{
printf("春季\n");
}
return 0;
}
这个表达式的意思是month既要大于等于3,又要小于等于5,必须同时满足。
|| 就是或运算符,也就是"或者"的意思。|| 也是一个双目运算符,使用方式是 a || b, || 两边的表达式只要有一个为真,整个表达式的值就为真,两边表达式的都为假时,整个表达式的值才为假。
例子:我们要说一年中月份是12月或者1月或者2月是冬天,那我们怎么用代码表示呢?
#include<stdio.h>
int main()
{
int month = 0;
scanf("%d", &month);
if(month == 12 || month == 1 || month == 2)
{
printf("冬季\n");
}
return 0;
}
题目:输入一个年份year,判断year是否为闰年 思路:判断闰年的条件(二者居其一,即可): 1.年份数能被4整除,但不能被100整除; 2.年份数能被400整除。
#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;
}
C语言逻辑运算符还有一个特点,它总是先对左边的表达式求值后,再向右边,对右边的表达式依次求值,这个顺序是保证的。
那在C语言中,短路是什么? 我们在上面说过,逻辑运算符是从最左边的表达式开始运算的。那如果左边表达式的值已经满足了逻辑运算符的取值特点(参考上面写的各逻辑运算符的真值表),就不再对右边的表达式求值了。这种情况就被称为短路。
如果你听到这里,对短路现象还是一知半解的话,那请耐心看完下面的例子!
如我们在前面写的代码:
if(month == 12 || month == 1 || month == 2)
如果month==12,则不用再判断month是否等于1或者2了,整个表达式的结果也就是1.
所以, || 操作符的左操作数的结果不为0时,就无需执行右操作数。
像这种仅仅根据左操作数的结果就能知道整个表达式的结果,不再对右操作数进行计算成为短路求值。
为了方便读者们能够更好的吸收这块知识点,我把所有短路求值的规律写在下面: II:如果遇到左操作数为1时,则无需计算右操作数的真值,整个表达式的值为1; &&:如果遇到左操作数为0时,则无需计算右操作数的真值,整个表达式的值为0。
练习:阅读下面的代码,计算代码输出的结果
#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;
}
答案:
除了if语句外,C语言还提供了switch语句来实现分支结构。
switch语句是一种特殊形式的if…else结构,用于判断条件有多个结果的情况。它把多重的else…if改成了更易用、可读性更好的形式。
语法结构:
switch (expression)
{
case value1:statement
case value2:statement
...
default:statement
}
上面代码中,根据表达式expression不同的值,执行相应的case语句分支。如果找不到对应的值,就执行default分支
注意:
练习:输入任意一个整数值,计算除3之后的余数
//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;
}
#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语句中的写法:
可能有的读者就会问,那如果我就是不写break会发生什么?
下面我们就来探讨一下这个问题。
前面的代码中,如果我们去掉case语句中的break,会发生什么?
#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;
}
诶呦,这完全不是我们想要的结果啊。我们输入3,按道理来说,它只会给我们打印“余数为0”,可这为什么会把剩下的两个也一并打印了? 这个就是不写break的弊端 仔细研究一下这个代码,当执行到scanf语句时,我们在屏幕上输入一个3。这步就意味着我们给num赋值为3了,接着就开始执行switch语句。 通过switch语句后面的整型表达式得出的值,根据case后面的值进行匹配。我们这里就进入到了case 0中,之后就打印了"余数为0",就在这时我们得到了我们想要的结果。不过,一件可怕的事情也随之发生,你会发现switch语句并没有退出,而是接着执行了case 1分支里面的语句,接着就打印了“余数为1”。后面的过程类似,就不再赘述了。
究其原因,你会发现就因为没在每个case语句执行完后加上个break,就酿成了这种错误。可想而知,break对于switch语句的重要性。
在使用switch语句的时候,我们可能会遇到一种情况,比如switch后的表达式的值,没有一个case后面的值能够与之匹配。这个时候,switch语句有两种处理方法:第一种,不处理(冷暴力);第二种,加一个default字句。
例子:打印星期,如果day的输入不是1~7的值,我们就要提示:输入错误。
#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;
}
细心的读者可能就会发现,我每次写代码时,都会把default写在switch语句的最后一个分支。这个写法是固定的吗?其实不然。
在switch语句中case语句和default语句是没有顺序要求的,只要你的顺序和语法满足实际需求即可。
不过要养成良好的编程习惯的话,建议把default写在最后。
在分支语句中,我们学习了
希望读者们能够快乐地生活,快乐地学习。学习很难,但坚持一定很酷!