运算符
算数运算符、关系运算符、逻辑运算符、位运算符、特殊运算符以及其优先级和结合性
文章目录
一、算术运算符
1.1 算术运算符列表
+
:加法运算,取正。-
:减法运算,取负。*
:乘法运算。/
:除法运算。%
:取模(求余)运算。++
:自加1运算。--
:自减1运算。
注意事项:
- 取正:一目加法运算,如
+a
。 - 取负:一目减法运算,如
-a
。 - 取模运算:左右两个操作数必须是整型。
- 自加/自减运算:
- 可以操作整型、浮点型、指针类型。
- 前缀(如
++a
):先自加/自减,然后参与表达式运算。 - 后缀(如
a++
):先参与表达式运算,然后再自加/自减。
1.2 示例代码
#include <stdio.h>
int main() {
int a = 5;
int c = 3;
// 除法和取模运算
printf("5/3 = %d, 5%%3 = %d\n", a / c, a % c);
// 后缀自加
printf("a++: %d\n", a++); // 输出5,a变为6
// 前缀自加
printf("++a: %d\n", ++a); // 输出7,a变为7
// 演示一目取负
int b = -100;
printf("-b: %d\n", -b); // 输出100
return 0;
}
输出示例:
5/3 = 1, 5%3 = 2
a++: 5
++a: 7
-b: 100
解释:
-
除法和取模运算:
printf("5/3 = %d, 5%%3 = %d\n", a / c, a % c);
5 / 3
结果为1
(整型除法)。5 % 3
结果为2
(取模运算)。
-
后缀自加:
printf("a++: %d\n", a++);
- 输出
5
,然后a
自加1
变为6
。
- 输出
-
前缀自加:
printf("++a: %d\n", ++a);
a
先自加1
变为7
,然后输出7
。
-
一目取负:
int b = -100; printf("-b: %d\n", -b);
-b
结果为100
,表示取反操作。
二、关系运算符
关系运算符用于比较两个值,结果是布尔值(真或假)。
运算符 | 描述 | 示例 | 结果描述 |
---|---|---|---|
> | 大于 | a > b | 判断a是否大于b |
< | 小于 | a < b | 判断a是否小于b |
>= | 大于等于 | a >= b | 判断a是否大于或等于b |
<= | 小于等于 | a <= b | 判断a是否小于或等于b |
== | 等于 | a == b | 判断a是否等于b |
!= | 不等于 | a != b | 判断a是否不等于b |
在这些关系运算符中,表达式的结果为布尔值(真或假),用于条件判断。例如:
a == b
:判断a是否等于b。
注意:
- 判断两个数是否相等使用的== , 是两个等号 ,而不是一个
- 关系运算符的表达式值为布尔值
- 在数学中100< a <200 , 在代码中需要拆开 ,a > 100 && a < 200。
示例代码
#include <stdio.h>
int main() {
int a = 100;
int b = 200;
printf("a > b: %d\n", a > b); // 输出 0(假)
printf("a < b: %d\n", a < b); // 输出 1(真)
printf("a >= b: %d\n", a >= b); // 输出 0(假)
printf("a <= b: %d\n", a <= b); // 输出 1(真)
printf("a == b: %d\n", a == b); // 输出 0(假)
printf("a != b: %d\n", a != b); // 输出 1(真)
return 0;
}
输出结果:
a > b: 0
a < b: 1
a >= b: 0
a <= b: 1
a == b: 0
a != b: 1
三、逻辑运算符
逻辑运算符用于组合或反转布尔值。
运算符 | 描述 | 示例 | 结果描述 |
---|---|---|---|
! | 逻辑反 | !(x > 9) | 如果x大于9,则表达式为假;反之为真 |
&& | 逻辑与 | a > 100 && a < 200 | 两边表达式同时为真则为真,否则为假 |
|| | 逻辑或 | a > 100 || a < 200 | 任意一边表达式为真则为真 |
== | 判断两个数是否相等 | a == b | 判断a是否等于b |
注意:
在逻辑与的运算中,如果左边为假则直接判断为假,右边的表达式将不会执行
在逻辑或的运算中, 如果左边为真则表达式直接判断为真, 右边的表达式将不会
3.1 示例代码
#include <stdio.h>
int main() {
int a = 100;
int b = 200;
printf("!(a > 50): %d\n", !(a > 50)); // 输出 0(假)
printf("a > 50 && a < 200: %d\n", a > 50 && a < 200); // 输出 1(真)
printf("a > 150 || a < 50: %d\n", a > 150 || a < 50); // 输出 0(假)
// 逻辑运算符的短路特性
if (a < 50 && (b = b + 300)) {
// 如果左边为假,则右边不被执行
}
printf("a = %d, b = %d\n", a, b); // a = 100, b = 200
if (a > 50 || (b = b + 300)) {
// 如果左边为真,则右边不被执行
}
printf("a = %d, b = %d\n", a, b); // a = 100, b = 200
return 0;
}
输出结果:
!(a > 50): 0
a > 50 && a < 200: 1
a > 150 || a < 50: 0
a = 100, b = 200
a = 100, b = 200
四、 位运算符
下面是位运算符的示例说明:
运算符 | 描述 | 示例 | 结果描述 |
---|---|---|---|
~ | 位逻辑反 | ~a | 对a进行按位取反 |
& | 位逻辑与 | a & b | 对a和b的每一位进行逻辑与操作 |
| | 位逻辑或 | a | b | 对a和b的每一位进行逻辑或操作 |
^ | 位逻辑异或 | a ^ b | 对a和b的每一位进行逻辑异或操作 |
<< | 左移 | a << 4 | 对a的二进制表示向左移动4位 |
>> | 右移 | a >> 2 | 对a的二进制表示向右移动2位 |
注意:位运算符操作的是操作数的每一个二进制位。
4.1 详细举例说明
下面是对位运算符的详细描述:
~
(位逻辑反):位逻辑反操作符对操作数的每个二进制位进行取反操作,即将0变为1,将1变为0。- 例如
- 如果
a
的二进制表示是0000 0000 0000 0000 0000 0000 0000 0011
, - 则
~a
的结果是1111 1111 1111 1111 1111 1111 1111 1100
。
&
(位逻辑与):位逻辑与操作符对操作数的每个二进制位进行逻辑与操作。如果两个操作数的对应位都为1,则结果的对应位为1,否则为0。- 例如:
- 如果
a
的二进制表示是0011
,b
的二进制表示是0101
, - 则
a & b
的结果是0001
。
|
(位逻辑或):位逻辑或操作符对操作数的每个二进制位进行逻辑或操作。如果两个操作数的对应位中至少有一个为1,则结果的对应位为1,否则为0。例如,如果a
的二进制表示是0011
,b
的二进制表示是0101
,则a | b
的结果是0111
。
^
(位逻辑异或):位逻辑异或操作符对操作数的每个二进制位进行逻辑异或操作。如果两个操作数的对应位相同,则结果的对应位为0,如果不同则为1。例如,如果a
的二进制表示是0011
,b
的二进制表示是0101
,则a ^ b
的结果是0110
。
<<
(左移):左移操作符将操作数的二进制表示向左移动指定的位数,并用0填充右侧的空位。例如,如果a
的二进制表示是0011
,则a << 4
的结果是0011 0000
。
int a = 3 ;
a ‐> 0000 0000 0000 0000 0000 0000 0000 0011
a<<4 ‐> 0000 0000 0000 0000 0000 0000 0011 0000
>>
(右移):右移操作符将操作数的二进制表示向右移动指定的位数,并丢弃右侧移出的位。对于无符号数,右侧空出的位用0填充;对于有符号数,右侧空出的位使用符号位填充。
注意:
左移(<<): 将操作数的二进制表示向左移动指定的位数,右侧空出的位补0。
右移(>>): 将操作数的二进制表示向右移动指定的位数,右侧空出的位使用0或符号位填充。对于无符号数,右侧空出的位用0填充;对于有符号数,右侧空出的位使用符号位填充。
五、特殊运算符
5.1 赋值运算符 =
赋值运算符 =
用于将右值赋给左值。
左值必须是一个可以被修改的存储位置,例如变量,而不能是常量或无法直接赋值的类型(如数组)。
下面是一些示例和注意事项:
-
初始化:
int a, b; int x[5];
-
示例 1:
a = 100; // 正确,对变量 a 进行赋值
-
错误示例:
100 = a; // 错误,左值不能是常量 x = 123; // 错误,数组不可以直接赋值
-
连续赋值:
a = b = 100; // 正确,先把 100 赋值给 b,再把 b 赋值给 a
5.2 复合运算符
复合运算符是将赋值与算术或位运算结合在一起,简化代码并提高效率。
常见的复合运算符如下:
-
加减乘除:
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;
-
位运算:
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;
5.3 条件运算符(三目运算符)
条件运算符是唯一一个需要三个操作数的运算符。语法为:表达式1 ? 表达式2 : 表达式3
。
它根据表达式1的真假来决定整个表达式的值。
-
语法:
表达式1 ? 表达式2 : 表达式3;
- 如果表达式1为真,整个表达式的值为表达式2。
- 如果表达式1为假,整个表达式的值为表达式3。
-
示例:
int a = 100; int b = 250; int max = a > b ? a : b; // 如果 a > b 为真,max 的值为 a,否则为 b
5.4 总结表
运算符 | 描述 | 示例 | 结果描述 |
---|---|---|---|
= | 赋值运算符 | a = 100 | 将 100 赋值给 a |
+= | 加赋值 | a += b | 将 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 | 将 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 ? a : b | 如果 a > b 为真,则取 a,否则取 b |
注意:位运算符操作的是操作数的每一个二进制位。例如,~a
是对 a 的每一个二进制位取反,a & b
是对 a 和 b 的每一位进行逻辑与操作,a | b
是对 a 和 b 的每一位进行逻辑或操作,a ^ b
是对 a 和 b 的每一位进行逻辑异或操作,a << 4
是将 a 的二进制表示向左移动 4 位,a >> 2
是将 a 的二进制表示向右移动 2 位。
5.5 sizeof
运算符
sizeof
是一个用于计算变量或变量类型在内存中所占字节数的运算符。它看起来像一个函数,但实际上是一个编译时运算符。
5.5.1 使用示例:
-
计算变量类型的大小:
printf("sizeof(long): %ld\n", sizeof(long)); // 计算 long 类型的大小
-
计算变量的大小:
int a; printf("sizeof(a): %ld\n", sizeof(a)); // 计算变量 a 的大小
-
计算数组的大小:
int buf[5]; printf("sizeof(buf): %ld\n", sizeof(buf)); // 计算数组 buf 的大小
-
计算结构体的大小:
struct node { int a; // 4 bytes char b; // 1 byte double c; // 8 bytes }; printf("sizeof(struct node): %ld\n", sizeof(struct node)); // 计算结构体 node 的大小
注意事项:
sizeof
计算的是变量或数据类型在内存中占用的字节数。- 对于不同的编译器或平台,数据类型的大小可能会有所不同。
- 结构体的大小可能会受到内存对齐的影响。
5.5.2 示例代码和结果描述
#include <stdio.h>
int main() {
// 计算基本类型的大小
printf("sizeof(long): %ld\n", sizeof(long)); // 输出 long 类型的大小
// 计算变量的大小
int a;
printf("sizeof(a): %ld\n", sizeof(a)); // 输出变量 a 的大小
// 计算数组的大小
int buf[5];
printf("sizeof(buf): %ld\n", sizeof(buf)); // 输出数组 buf 的大小
// 定义结构体并计算其大小
struct node {
int a; // 4 bytes
char b; // 1 byte
double c; // 8 bytes
};
printf("sizeof(struct node): %ld\n", sizeof(struct node)); // 输出结构体 node 的大小
return 0;
}
预期输出:
sizeof(long): 8
sizeof(a): 4
sizeof(buf): 20
sizeof(struct node): 16
注意,上述输出仅为示例,实际大小可能因编译器和系统架构的不同而有所变化。例如,在某些系统中,long
类型可能占用 4 个字节,而不是 8 个字节。结构体的大小也可能因内存对齐而有所不同。
5.6 return 运算符
return
运算符用于退出函数。如果在主函数(main
函数)中遇到 return
,则程序进程结束;如果在其他函数中遇到 return
,则返回到被调用的位置。
5.6.1 语法
return [expression];
- expression:可选。指定要返回的值,其类型必须与函数的返回类型匹配。
5.6.2 使用示例
-
在主函数中使用
return
:int main(int argc, char const *argv[]) { int a = 5; int b = 10; int sum = a + b; printf("Sum: %d\n", sum); return 0; // 退出程序进程 }
-
在其他函数中使用
return
:int add(int x, int y) { return x + y; // 返回 x 和 y 的和 } int main(int argc, char const *argv[]) { int result = add(5, 10); // 调用 add 函数并返回结果 printf("Result: %d\n", result); return 0; }
注意事项:
return
必须出现在函数体内部。- 如果函数声明了返回类型,则
return
语句必须返回相应类型的值。如果函数的返回类型是void
,则return
语句不能返回任何值。 - 在
main
函数中,返回值通常为 0 表示程序成功结束,非 0 表示程序异常结束。
5.6.3 示例代码和结果描述
#include <stdio.h>
// 一个示例函数,用于计算两个整数的和
int add(int x, int y) {
return x + y; // 返回两个整数的和
}
int main(int argc, char const *argv[]) {
// 在主函数中调用 add 函数并输出结果
int result = add(5, 10); // 调用 add 函数并将返回值赋给 result
printf("Result: %d\n", result); // 输出结果
return 0; // 退出程序进程
}
预期输出:
Result: 15
在上述示例中:
add
函数返回两个整数的和。- 在
main
函数中,调用add
函数,并输出结果。 main
函数最后使用return 0
退出程序进程,表示程序成功结束。
六、优先级与结合性
使用命令man operator
可以查看到优先级:
在表达式中,当多个运算符同时出现时,运算符的优先级和结合性决定了运算的顺序。一般情况下,先计算优先级高的运算符,优先级相同的运算符根据结合性进行计算。
6.1 运算符优先级和结合性示例
- 算术运算符:乘除(
*
、/
)的优先级高于加减(+
、-
)。 - 逻辑运算符:逻辑与(
&&
)的优先级高于逻辑或(||
)。 - 赋值运算符:赋值(
=
)的优先级低于算术和逻辑运算符。
6.2 逗号表达式
逗号表达式用于在一条语句中包含多个表达式,逗号运算符的优先级最低。逗号表达式从左向右依次运算每个表达式,整个逗号表达式的值取决于最后一个表达式
的值。
6.2.1 语法
表达式1 = (表达式2, 表达式3, 表达式4, ......, 表达式n);
6.2.2 示例
#include <stdio.h>
int main() {
int a = 10;
int c = 250;
// 逗号表达式:从左到右依次执行表达式,整个表达式的值是最后一个表达式的值
int b = (a++, a = a + c, a, 300);
printf("b: %d\n", b); // 输出 b 的值
printf("a: %d\n", a); // 输出 a 的值
return 0;
}
输出结果:
b: 300
a: 261
说明:
a++
:先使用a
的当前值(10),然后a
自增,a
变为 11。a = a + c
:计算a + c
,即 11 + 250,结果为 261,并赋值给a
,所以a
变为 261。a
:此时a
的值是 261。300
:整个逗号表达式的值取最后一个表达式的值,即 300。
注意事项:
- 逗号表达式从左向右依次运算每一个表达式。
- 整个表达式的值取决于最后一个表达式的值。
练习:
练习1:
int a=10;
int b=11;
printf("a= %d,b= %d \n",a^b^a,a^b^b);