《小菜狗 C 语言入门 + 进阶笔记》目录:《小菜狗 C 语言入门 + 进阶笔记》(0)简介
在之前的 (2.15)运算符 文章中讲过各种各样的运算符。
运算符通用于 选择结构
和 循环结构
,使代码更加简洁,更符合现实。
其中最常用的运算符就是关系运算符
和逻辑运算符
,以及三目条件运算符。
怎么区分几目运算符?
在 C 语言中,有的运算符有两个操作数,例如 10+20,10 和 20
都是操作数
,+ 是运算符。我们将这样的运算符称为双目运算符。同理,将有一个操作数的运算符称为单目运算符,将有三个操作数的运算符称为三目运算符。
常见的双目运算符
有 +、-、*、/ 等
,单目运算符
有 ++、-- 等
,三目运算符只有一个,就是 ? :
– x ? y : z -- 如果条件为真 ? 则值为 X : 否则值为 Y
。
1、关系运算符
1.1、定义
用于比较的表达式,称为关系表达式
。
运算符 | 描述 | 实例 |
---|---|---|
== | 检查两个操作数的值是否相等,如果相等则条件为真。 | (A == B) 为假。 |
!= | 检查两个操作数的值是否相等,如果不相等则条件为真。 | (A != B) 为真。 |
> | 检查左操作数的值是否大于右操作数的值,如果是则条件为真。 | (A > B) 为假。 |
< | 检查左操作数的值是否小于右操作数的值,如果是则条件为真。 | (A < B) 为真。 |
>= | 检查左操作数的值是否大于或等于右操作数的值,如果是则条件为真。 | (A >= B) 为假。 |
<= | 检查左操作数的值是否小于或等于右操作数的值,如果是则条件为真。 | (A <= B) 为真。 |
1.2、作用
关系运算符在使用时,它的两边都会有一个表达式
,比如变量、数值、加减乘除运算或表达式等。
例如:
- a+b > c-d
- x > 3/2
- ‘a’+1 < c
- -i-5*j == k+1
关系运算符也可以嵌套使用
。
例如:
- a > (b > c)
- a != (c == d)
关系运算符的作用
就是判明这两个表达式的大小关系
。
**注意:**是判明大小关系,不是其他关系。
1.3、优先级
关系运算符都是双目运算符,其结合性均为左结合
。关系运算符的优先级低于算术运算符,高于赋值运算符。
在六个关系运算符中,<、<=、>、>=
的优先级相同,高于 == 和 !=
,其中 == 和 !=
的优先级相同。
1.4、运算结果
关系运算符的运算结果只有 0 或 1。当条件成立时结果为 1,条件不成立结果为 0。
例如:
- 5>0 成立,其值为 1;
- 34-12>100 不成立,其值为 0;
- (a=3)>(b=5) 由于 3>5 不成立,故其值为 0。
我们将运算结果 1 称为“真”,表示条件成立,将 0 称为“假”,表示条件不成立。
1.5、举例
下面的代码会将关系运算符的结果输出:
#include <stdio.h>
int main(){
char c='k';
int i=1, j=2, k=3;
float x=3e+5, y=0.85;
int result_1 = 'a'+5<c, result_2 = x-5.25<=x+y;
printf( "%d, %d\n", result_1, -i-2*j>=k+1 );
printf( "%d, %d\n", 1<j<5, result_2 );
printf( "%d, %d\n", i+j+k==-2*j, k==j==i+5 );
return 0;
}
运行结果:
1, 0
1, 1
0, 0
解释说明: 对于含多个关系运算符的表达式,如 kji+5,根据运算符的左结合性,先计算 kj,该式不成立,其值为 0,再计算 0i+5,也不成立,故表达式值为 0。
1.6、if 语句的判断条件
if 语句的判断条件中不是必须要包含关系运算符,它可以是赋值表达式,甚至也可以是一个变量。
如程序段:
if (a=b)
printf("%d",a);
else
printf("a=0");
意思是,把 b 的值赋予 a,如果为非 0 则输出该值,否则输出“a=0”字符串。这种用法在后面的程序中会经常出现。
1.7、进阶使用
注意 1:
相等运算符 ==
与赋值运算符 =
是两个不⼀样的运算符,==
才表示等于,而=
表示赋值,不要混淆。
有的程序员喜欢将变量写在等号的右边,如下:
if (3 == x) ...
这样的话,如果把 == 误写成 = ,编译器就会报错。
/* 报错 */
if (3 = x) ...
注意 2:
多个关系运算符不宜连用
。如下:
i < j < k
上面示例中,连续使用两个小于运算符。这是合法表达式,不会报错,但是通常达不到想要的结果,即不是保证变量 j 的值在 i 和 k 之间。因为关系运算符是从左到右计算,所以实际执行的是下面的表达式。
(i < j) < k
上面式子中, i < j 返回 0 或 1 ,所以最终是 0 或 1 与变量 k 进行比较。如果想要判断变量 j 的值是否在 i 和 k 之间,应该使用下面的写法:
i < j && j < k
比如:我们输入⼀个年龄,如果年龄在 18 岁 ~ 36 岁之间,我们输出青年。
如果我们这样写:
#include <stdio.h>
int main()
{
int age = 0;
scanf("%d", &age);
if (18<=age<=36)
{
printf("青年\n");
}
return 0;
}
当我们输入 10 的时候,依然输出 青年!
这是因为,我们先拿 18 和 age 中存放的 10 比较,表达式 18<=10 为假, 18<=age 的结果是 0,再拿 0 和 36 比较,0<=36 为真,所以打印了 青年 ,所以即使当 age 是 10 的时候,也能打印 青年 ,逻辑上是有问题,这个代码应该怎么写呢?如下就是规范代码:
#include <stdio.h>
int main()
{
int age = 0;
scanf("%d", &age);
if (age>=18 && age<=36)
{
printf("青年\n");
}
return 0;
}
2、逻辑操作符
2.1、引入
假设有这样一种情况:我们的软件比较特殊,要求使用者必须成年,并且考试成绩大于等于 60,该怎么写代码呢?
首先我们使用嵌套的 if 语句,类似下面这样的代码:
#include <stdio.h>
int main()
{
int age;
float score;
printf("请输入你的年龄和成绩:");
scanf("%d %f", &age, &score);
if (age >= 18) {
if (score >= 60) {
printf("你满足条件,欢迎使用该软件\n");
} else{
printf("抱歉,你的成绩不及格,不能使用该软件\n");
}
} else {
printf("抱歉,你还未成年,不能使用该软件!\n");
}
return 0;
}
但是在我看来上面代码不够简洁,我们可以将其压缩为一条 if else 语句
:
#include <stdio.h>
int main()
{
int age;
float score;
printf("请输入你的年龄和成绩:");
scanf("%d %f", &age, &score);
if(age>=18 && score>=60){
printf("你满足条件,欢迎使用该软件\n");
}else{
printf("抱歉,你还未成年,或者成绩不及格,不能使用该软件!\n");
}
return 0;
}
&&
为逻辑运算符 – 与
,表示 age>=18
和 score>=60
两个条件必须同时成立才能执行 if 后面的代码,否则就执行 else 后面的代码。
2.2、定义
逻辑运算符提供逻辑判断功能,用于构建更复杂的表达式,主要有下面三个运算符。
运算符 | 描述 | 实例 |
---|---|---|
&& | 称为逻辑与运算符。如果两个操作数都非零,则条件为真。 | (A && B) 为假。 |
|| | 称为逻辑或运算符。如果两个操作数中有任意一个非零,则条件为真。 | (A || B) 为真。 |
! | 称为逻辑非运算符。用来逆转操作数的逻辑状态。如果条件为真则逻辑非运算符将使其为假。 | !(A && B) 为真。 |
2.2.1、逻辑与运算符
&& 就是与运算符,也是并且的意思, && 是⼀个双⽬操作符,使用的⽅式是 a&&b ,&& 两边的表达式都是真的时候,整个表达式才为真,只要有⼀个是假,则整个表达式为假。
如果我们说月份是 3 月 ~ 5 月,是春天。
代码如下:
int month = 0;
scanf("%d", &month);
if (month >= 3 && month <= 5)
{
printf("春季\n");
}
解释:
month 既要大于等于 3,⼜要小于等于 5,必须同时满足。
2.2.2、逻辑或运算符
|| 就是或运算符,也就是或者的意思,|| 也是⼀个双⽬操作符,使用的⽅式是 a || b,|| 两边的表达式只要有⼀个是真,整个表达式就是真,两边的表达式都为假的时候,才为假。
如果我们说月份是 3 月 ~ 5 月,是春天。
代码如下:
int month = 0;
scanf("%d", &month);
if (month == 12 || month==1 || month == 2)
{
printf("冬季\n");
}
解释:
month 从左往右判断,只要有一个条件满足就打印。
2.2.3、逻辑取反运算符
参与运算的表达式为真时,结果为假;参与运算的表达式为假时,结果为真。例如:
!0
解释:
0 为假,非运算的结果为真,也就是 1。
!(5>0)
解释:
5>0 的结果是 1,为真,非运算的结果为假,也就是 0。
2.3、综合举例
#include <stdio.h>
int main(){
int a = 0, b = 10, c = -6;
int result_1 = a&&b, result_2 = c||0;
printf("%d, %d\n", result_1, !c);
printf("%d, %d\n", 9&&0, result_2);
printf("%d, %d\n", b||100, 0&&0);
return 0;
}
运行结果:
0, 0
0, 1
1, 0
2.4、优先级
逻辑运算符和其它运算符优先级从低到高依次为:
赋值运算符(=) < && 和 || < 关系运算符 < 算术运算符 < 非(!)
&& 和 || 低于
关系运算符,! 高于
算术运算符。
按照运算符的优先顺序可以得出:
- a>b && c>d 等价于 (a>b)&&(c>d)
- !b==c||d<a 等价于 ((!b)==c)||(d<a)
- a+b>c&&x+y<b 等价于 ((a+b)>c)&&((x+y)<b)
另外,逻辑表达式也可以嵌套使用,例如 a>b && b || 9>c
,a || c>d && !p
。
逻辑运算符优先级举例:
#include <stdio.h>
int main(){
char c='k';
int i=1,j=2,k=3;
float x=3e+5,y=0.85;
printf( "%d,%d\n", !x*!y, !!!x );
printf( "%d,%d\n", x||i&&j-3, i<j&&x<y );
printf( "%d,%d\n", i==5&&c&&(j=8), x+y||i+j+k );
return 0;
}
运行结果:
0,0
1,0
0,1
详细分析:
- !x 和 !y 分别为 0,!x*!y 也为 0,故其输出值为 0。
- 由于 x 为非 0,故 !!!x 的逻辑值为 0。
- 对 x|| i && j-3 式,先计算 j-3 的值为非 0,再求 i && j-3 的逻辑值为 1,故 x||i&&j-3 的逻辑值为 1。
- 对 i<j&&x<y 式,由于 i<j 的值为 1,而 x<y 为 0 故表达式的值为 1,0 相与,最后为 0。
- 对 i5&&c&&(j=8) 式,由于 i5 为假,即值为 0,该表达式由两个与运算组成,所以整个表达式的值为 0。
- 对于式 x+ y||i+j+k,由于 x+y 的值为非 0,故整个或表达式的值为 1。
2.5、进阶理解
逻辑运算符它总是先对左侧的表达式求值,再对右边的表达式求值。如果左边的表达式满足逻辑运算符的条件,就不再对右边的表达式求值。
如前面的代码:
if (month >= 3 && month <= 5)
表达式中 && 的左操作数是 month >= 3 ,右操作数是 month <= 5 ,当左操作数 month >= 3 的结果是 0 的时候,即使不判断 month <= 5 ,整个表达式的结果也是 0(不是春季)。
所以,对于 && 操作符来说,左边操作数的结果是 0 的时候,右边操作数就不再执行。
对于 || 操作符是怎么样呢?我们结合前面的代码:
if (month == 12 || month==1 || month == 2)
如果 month==12,则不用再判断 month 是否等于 1 或者 2,整个表达式的结果也是 1(是冬季)。所以, || 操作符的左操作数的结果不为 0 时,就⽆需执行右操作数。
3、条件操作符
3.1、引入
如果希望获得两个数中最大的一个,可以使用 if else 语句,例如:
if (a>b) {
max = a;
} else {
max = b;
}
该语句的语义是:
如 a>b 为真,则把 a 赋予 max,否则把 b 赋予 max。
不过,C 语言提供了一种更加简单的方法,叫做条件运算符
。条件表达式通常用于赋值语句之中。
3.2、语法
表达式 1 ? 表达式 2 : 表达式 3
条件操作符的计算逻辑是:
- 如果 表达式 1 为真,
下一条语句是表达式 2
; - 如果 表达式 1 为假,
下一条语句是表达式 3
。
因此上面的 if else 语句等价于:
max = (a>b) ? a : b;
3.3、进阶使用
- 条件运算符
?
和:
是一对运算符
,不能分开单独使用。 - 条件运算符的优先级
低于
关系运算符和算术运算符,但高于
赋值符。
max=(a>b) ? a : b;
可以去掉括号写成
max=a>b ? a : b;
- 条件运算符的结合方向是
自右至左
。例如:
a>b ? a : c>d ? c : d;
应理解为:
a>b ? a : ( c>d ? c : d );
这也就是条件表达式嵌套
的情形,即其中的表达式又是一个条件表达式。
4、容易出错的 if 语句
if 语句,虽然看上去很简单,但是在实际写代码的时候,也是很容易出错的,这⾥就总结 5 种情况。
4.1、在 if 语句的后边加上了分号
#include <stdio.h>
int main()
{
int n = 0;
scanf("%d", &n);
if (n>0);
printf("hehe\n");
return 0;
}
上述的代码,不管 n 是大于 0 还是小于 0,最终都会输出 hehe,因为 if 语句的后边加了⼀个分号,⼀个分号就是⼀个空语句,那么如果 n>0 则执行⼀条空语句。
4.2、判断相等时使用了 =
在 C 语⾔中, = 是赋值, == 是判断相等,这两个操作符⾮常容易混用。
#include <stdio.h>
int main()
{
int n = 0;
if (n = 1) //这⾥不是判断,⽽是赋值,赋值后表达式的结果是1,所以打印 hehe
printf("hehe\n");
if (n == 1) //这⾥是判断,n不等于1,所以不打印 haha
printf("haha\n");
return 0;
}
4.3、判断 3 个变量相等时使用了 ==
#include <stdio.h>
int main()
{
int a = 2;
int b = 2;
int c = 2;
//错误写法
if(a == b == c)
printf("a,b,c相等\n");
else
printf("不相等\n");
//正确的写法
if(a==b && b==c)··
printf("a,b,c相等\n");
else
printf("不相等\n");
return 0;
}
4.4、两个条件的判断条件时没使用 && 或 ||
#include <stdio.h>
int main()
{
int a = 2;
//错误的写法
if(3<=a<=5)
printf("Yes\n");
else
printf("No\n");
//正确的写法
if(a>=3 && a<=5)
printf("Yes\n");
else
printf("No\n");
return 0;
}
4.5、使用位运算代替了逻辑运算符
int a = 1;
if (3<=a & a<= 5) //这种是错误的写法, 操作符 & 是按照对应⼆进制位做与运算的
if (a>=3 && a<=5) //正确的写法
注意 | 和 || 的区别, | 是⼆进制位的或运算, || 是逻辑或运算的。
《小菜狗 C 语言入门 + 进阶笔记》目录:《小菜狗 C 语言入门 + 进阶笔记》(0)简介
每日一更!
公众号、优快云等博客:小菜狗编程笔记
谢谢点赞关注哈!目前在飞书持续优化更新~
日更较慢有需要完整笔记请私我,C/C++/数据结构-算法/单片机51-STM32-GD32-ESP32/嵌入式/Linux操作系统/uboot/Linux内核-驱动-应用/硬件入门-PCB-layout/Python/后期小程序和机器学习!