运算符是一种特殊的符号,用以表示数据的运算、赋值和比较等。
运算符的分类:
功能
分为:算术运算符、赋值运算符、比较(或关系)运算符、逻辑运算符、位运算符、条件运算符、sizeof运算符分类 | 运算符 |
---|---|
算术运算符 | +、-、+、-、*、/、%、++、– |
赋值运算符 | =、+=、-=、*=、/=、%=等 |
比较(或关系)运算符 | >、>=、<、<=、==、!= |
逻辑运算符 | &&、||、! |
位运算符 | &、|、^、~、<<、>> |
条件运算符 | (条件表达式)?结果1:结果2 |
sizeof运算符 | sizeof() |
操作数个数
分为:一元运算符(单目运算符)、二元运算符(双目运算符)、三元运算符 (三目运算符)分类 | 运算符 |
---|---|
一元运算符(单目运算符) | 正号(+)、负号(-)、++、–、!、~ |
二元运算符(双目运算符) | 除了一元和三元运算符剩下的都是二元运算符 |
三元运算符 (三目运算符) | (条件表达式)?结果1:结果2 |
算术运算符专门用于算术运算,主要有下面几种。
举例1:
float x = 6 / 4;
printf("%f\n", x); // 输出 1.000000
float x = 6.0 / 4; // 或者写成 6 / 4.0
printf("%f\n", x); // 输出 1.500000
举例2:%,运算结果的符号与被模数相同
int x1 = 6 % 4; // 2
int x2 = -6 % 4; // -2
int x3 = 6 % -4; // 2
int x4 = -6 % -4; // -2
举例3:自加自减运算
理解:++
运算,表示自增1
。同理,--
运算,表示自减1
,用法与++ 一致。
1、单独使用
前++
和变量后++
,是没有区别的。前++
:例如 ++a
。后++
:例如 a++
。2、复合使用
其他变量放在一起使用
或者和输出语句放在一起使用
,前++
和后++
就产生了不同。前++
:变量先自增1,然后再运算。后++
:变量先运算,然后再自增1。int main() {
// 其他变量放在一起使用
int x = 3;
//int y = ++x; // y的值是4,x的值是4,
int y = x++; // y的值是3,x的值是4
printf("%d\n",x);
printf("%d\n",y);
printf("==========\n");
// 和输出语句一起
int z = 5;
//printf("%d\n",++z);// 输出结果是6,z的值也是6
printf("%d\n",z++);// 输出结果是5,z的值是6
printf("%d\n",z);
return 0;
}
与此对应的:
前--
:变量先自减1,然后再运算。后--
:变量先运算,然后再自减1。连续赋值
。运算符 | 名称 | 实例 | 展开形式 |
---|---|---|---|
+= | 复合加赋值 | a+=b | a=a+b |
-= | 复合减赋值 | a-=b | a=a-b |
*= | 复合乘赋值 | a*=b | a=a*b |
/= | 复合除赋值 | a/=b | a=a/b |
%= | 复合模赋值 | a%=b | a=a%b |
常用的比较运算符:
关系运算符 | 含义 | 举例 |
---|---|---|
> | 大于 | num > 10 |
>= | 大于等于 | num >= 10 |
< | 小于 | num < 10 |
<= | 小于等于 | num <= 10 |
== |
等于 | num == 10 |
!= | 不等于 | num != 10 |
==
”不能误写成“=
”举例:多个关系运算符不宜连用。
i < j < k //期望判断j是否大于i,且小于k
这是合法表达式,不会报错,但是通常达不到想要的结果,即不是保证变量 j 的值在 i 和 k 之间。比如:
//i < j < k
int j = 10;
if(15 < j < 20){
printf("j大于15,且小于20"); //输出此语句
}else{
printf("j不在15到20之间");
}
因为关系运算符是从左到右计算,所以实际执行的是:
(i < j) < k; //i < j 返回 0 或 1 ,所以最终是 0 或 1 与变量 k 进行比较
期望的效果应该写为:
//i < j < k
int j = 10;
if(15 < j && j < 20){
printf("j大于15,且小于20");
}else{
printf("j不在15到20之间"); //输出此语句
}
主要有下面三个运算符:
逻辑运算符 | 描述 | 功能 | 举例 |
---|---|---|---|
&& | 与运算符 | 两个条件都要满足 | num1 >= 10 && num2 >= 20 |
|| | 或运算符 | 两个条件只需满足其一 | num1 >= 10 || num2 >= 20 |
! | 非运算符 | 否定条件 | !(num1 >= 10)(等价于 num1 < 10) |
逻辑运算符提供逻辑判断功能,用于构建更复杂的表达式。
举例:
a | b | a && b | a || b | !a |
---|---|---|---|---|
1(真) | 1(真) | 1(真) | 1(真) | 0(假) |
1(真) | 0(假) | 0(假) | 1(真) | 0(假) |
0(假) | 1(真) | 0(假) | 1(真) | 1(真) |
0(假) | 0(假) | 0(假) | 0(假) | 1(真) |
对于逻辑运算符来说,任何非零值都表示真,零值表示伪。比如, 5 || 0 会返回 1 , 5 && 0 会返回0 。
举例1:短路现象
int i = 0;
int j = 10;
if(i && j++ > 0){
printf("床前明月光");
}else{
printf("我叫郭德纲");
}
printf("%d\n",j); //10
int i = 1;
int j = 10;
if(i || j++ > 0){
printf("床前明月光");
}else{
printf("我叫郭德纲");
}
printf("%d\n",j); //10
运算符 | 描述 | 运算规则 |
---|---|---|
<< | 二进制左移 | 将一个数的各二进制位全部左移指定的位数,左边的二进制位丢弃,右边补0。 |
>> | 二进制右移 | 将一个数的各二进制位全部右移指定的位数,正数左补0,负数左补1,右边丢弃。 |
& | 按位与 | 两个二进制位都为 1,结果为1,否则为0。 |
| | 按位或 | 两个二进制位只要有一个为1(包含两个都为 1 的情况),结果为1,否则为0。 |
^ | 按位异或 | 两个二进制位一个为0,一个为1,结果为1,否则为0。 |
~ | 按位取反 | 将每一个二进制位变成相反值,即 0 变成 1 , 1 变成 0 。 |
举例1:
(1)左移:<<
运算规则:在一定范围内,数据每向左移动一位,相当于原数据*2。(正数、负数都适用)
【注意】当左移的位数n超过该数据类型的总位数时,相当于左移(n-总位数)位
3<<4 类似于 3*2的4次幂 => 3*16 => 48
-3<<4 类似于 -3*2的4次幂 => -3*16 => -48
(2)右移:>>
运算规则:在一定范围内,数据每向右移动一位,相当于原数据/2。(正数、负数都适用)
【注意】
1、如果不能整除,向下取整
。
2、右移运算符最好只用于无符号整数,不要用于负数。因为不同系统对于右移后如何处理负数的符号位,有不同的做法,可能会得到不一样的结果。
69>>4 类似于 69/2的4次幂 = 69/16 =4
-69>>4 类似于 -69/2的4次幂 = -69/16 = -5
练习:高效的方式计算2 * 8的值(经典面试题)
答案:2 << 3 、 8 << 1
举例2:
(1)按位与:&
运算规则:对应位都是1才为1,否则为0。
9 & 7 = 1
-9 & 7 = 7
(2)按位或:|
运算规则:对应位只要有1即为1,否则为0。
9 | 7 //结果: 15
-9 | 7 //结果: -9
(3)按位异或:^
运算规则:对应位一个为1一个为0,才为1,否则为0。
9 ^ 7 //结果为14
-9 ^ 7 //结果为-16
(4)按位取反:~
运算规则:对应位为1,则结果为0;对应位为0,则结果为1。
~9 //结果:-10
~-9 //结果:8
练习:特定位清零
技巧:待清零的位与0,其它位与1
示例:设字符型 x 的当前值为 53,将其最低两位清 0,其余位保持不变
分析:与二进制的0b11111100数值求&运算即可。
int main() {
char x = 53; // 0b00110101
x = x & 252; // 0b11111100
printf("%d", x); //0b00110100
return 0;
}
举例:判断特定位是否为零
技巧:待判定位与 1,其它位与 0;判与运算结果是否为 0
示例:设字符型 x 的当前值为 53,判定其最高位是否为 0
分析:与二进制的0b10000000求&运算,若结果为 0,则最高位为 0,否则为 1
int main() {
char x