ThatManK Mobile Article
运算符与表达式
5. 运算符与表达式
运算符是 C 语言中用于执行各种操作的符号或关键字。运算符与操作数结合形成表达式,表达式可以计算出一个值。理解各种运算符及其优先级与结合性,是编写正确和高效 C 程序的基础。
5.1 算术运算符
算术运算符用于执行基本的数学计算,包括加、减、乘、除和取模(余数)等操作。
常见算术运算符
| 运算符 | 描述 | 示例 | 解释 |
| :---: | :---: | :---: | :---: |
| + | 加法 | a + b | 将两个操作数相加 |
| - | 减法 | a - b | 从第一个操作数中减去第二个操作数 |
| * | 乘法 | a * b | 将两个操作数相乘 |
| / | 除法 | a / b | 将第一个操作数除以第二个操作数 |
| % | 取模(余数) | a % b | 计算第一个操作数除以第二个操作数的余数 |
示例与详细解释
#include <stdio.h>
int main() {
int a = 15;
int b = 4;
int sum, difference, product, quotient, remainder;
// 加法
sum = a + b; // 15 + 4 = 19
printf("a + b = %d\n", sum);
// 减法
difference = a - b; // 15 - 4 = 11
printf("a - b = %d\n", difference);
// 乘法
product = a * b; // 15 * 4 = 60
printf("a * b = %d\n", product);
// 除法
quotient = a / b; // 15 / 4 = 3 (整数除法,舍去小数部分)
printf("a / b = %d\n", quotient);
// 取模
remainder = a % b; // 15 % 4 = 3
printf("a %% b = %d\n", remainder);
return 0;
}
输出:
a + b = 19
a - b = 11
a * b = 60
a / b = 3
a % b = 3
注意事项
- 整数除法:当两个整数相除时,结果也是一个整数,任何小数部分都会被舍去。
- 取模运算:取模运算仅适用于整数类型,计算两个整数相除后的余数。
更多示例
#include <stdio.h>
int main() {
float x = 5.5;
float y = 2.2;
float result;
// 加法
result = x + y; // 5.5 + 2.2 = 7.7
printf("x + y = %.1f\n", result);
// 减法
result = x - y; // 5.5 - 2.2 = 3.3
printf("x - y = %.1f\n", result);
// 乘法
result = x * y; // 5.5 * 2.2 = 12.1
printf("x * y = %.1f\n", result);
// 除法
result = x / y; // 5.5 / 2.2 = 2.5
printf("x / y = %.1f\n", result);
return 0;
}
输出:
x + y = 7.7
x - y = 3.3
x * y = 12.1
x / y = 2.5
5.2 关系运算符
关系运算符用于比较两个值,结果是一个布尔值(真或假)。这些运算符常用于条件判断和循环控制。
常见关系运算符
| 运算符 | 描述 | 示例 | 解释 |
| ------ | -------- | -------- | -------------------------------- |
| == | 等于 | a == b | 如果 a 等于 b,结果为真(1) |
| != | 不等于 | a != b | 如果 a 不等于 b,结果为真(1) |
| > | 大于 | a > b | 如果 a 大于 b,结果为真(1) |
| < | 小于 | a < b | 如果 a 小于 b,结果为真(1) |
| >= | 大于等于 | a >= b | 如果 a 大于等于 b,结果为真(1) |
| <= | 小于等于 | a <= b | 如果 a 小于等于 b,结果为真(1) |
示例与详细解释
#include <stdio.h>
int main() {
int a = 10;
int b = 20;
// 等于
if (a == b) {
printf("a 等于 b\n");
} else {
printf("a 不等于 b\n");
}
// 不等于
if (a != b) {
printf("a 不等于 b\n");
}
// 大于
if (a > b) {
printf("a 大于 b\n");
} else {
printf("a 不大于 b\n");
}
// 小于
if (a < b) {
printf("a 小于 b\n");
}
// 大于等于
if (a >= 10) {
printf("a 大于等于 10\n");
}
// 小于等于
if (b <= 20) {
printf("b 小于等于 20\n");
}
return 0;
}
输出:
a 不等于 b
a 不大于 b
a 小于 b
a 大于等于 10
b 小于等于 20
更多示例
#include <stdio.h>
int main() {
int x = 5;
int y = 5;
int z = 10;
// 使用关系运算符进行比较
printf("x == y: %d\n", x == y); // 1(真)
printf("x != z: %d\n", x != z); // 1(真)
printf("z > y: %d\n", z > y); // 1(真)
printf("x < z: %d\n", x < z); // 1(真)
printf("y >= x: %d\n", y >= x); // 1(真)
printf("z <= 10: %d\n", z <= 10); // 1(真)
return 0;
}
输出:
x == y: 1
x != z: 1
z > y: 1
x < z: 1
y >= x: 1
z <= 10: 1
注意事项
- 布尔值:C 语言中,真用
1表示,假用0表示。 - 类型兼容性:在比较时,操作数应尽量类型一致,避免隐式类型转换带来的问题。
5.3 逻辑运算符
逻辑运算符用于连接两个或多个条件表达式,产生一个布尔值结果。这些运算符在条件判断和控制结构中尤为重要。
常见逻辑运算符
| 运算符 | 描述 | 示例 | 解释 |
| ------ | ------------- | -------- | ------------------------------------------------------ |
| && | 逻辑与(AND) | a && b | 如果 a 和 b 都为真,结果为真(1) |
| | | | 逻辑或(OR) |
| ! | 逻辑非(NOT) | !a | 如果 a 为假,结果为真(1);如果 a 为真,结果为假(0) |
示例与详细解释
#include <stdio.h>
int main() {
int a = 10;
int b = 20;
int c = 30;
// 逻辑与运算
if (a < b && b < c) {
printf("a < b 且 b < c\n");
}
// 逻辑或运算
if (a > b || b < c) {
printf("a > b 或 b < c\n");
}
// 逻辑非运算
if (!(a > b)) {
printf("!(a > b) 即 a <= b\n");
}
return 0;
}
输出:
a < b 且 b < c
a > b 或 b < c
!(a > b) 即 a <= b
更多示例
#include <stdio.h>
int main() {
int x = 5;
int y = 10;
// 逻辑与
if (x > 0 && y > 0) {
printf("x 和 y 都是正数\n");
}
// 逻辑或
if (x < 0 || y > 0) {
printf("x 是负数 或 y 是正数\n");
}
// 逻辑非
if (!(x == y)) {
printf("x 不等于 y\n");
}
return 0;
}
输出:
x 和 y 都是正数
x 是负数 或 y 是正数
x 不等于 y
注意事项
- 短路评估:逻辑与和逻辑或运算符具有短路特性。例如,
a && b,如果 a 为假,b 将不再被计算。 - 优先级:逻辑运算符的优先级低于关系运算符,高于赋值运算符。使用括号可以明确运算顺序。
5.4 位运算符
位运算符用于对整数类型的位(0 和 1)进行操作。这些运算符在底层编程、硬件控制和高效算法实现中非常有用。
常见位运算符
| 运算符 | 描述 | 示例 | 解释 |
| :---: | :---: | :---: | :---: |
| & | 按位与 | a & b | 对应位都为 1 时结果为 1,否则为 0 |
| | | 按位或 | a | b |
| ^ | 按位异或 | a ^ b | 对应位不同则为 1,相同则为 0 |
| ~ | 按位取反 | ~a | 对每一位取反,即 0 变 1,1 变 0 |
| << | 左移 | a << 2 | 将位向左移动指定的位数 |
| >> | 右移 | a >> 2 | 将位向右移动指定的位数 |
示例与详细解释
#include <stdio.h>
int main() {
unsigned char a = 5; // 二进制:00000101
unsigned char b = 9; // 二进制:00001001
unsigned char result;
// 按位与
result = a & b; // 00000101 & 00001001 = 00000001
printf("a & b = %d\n", result); // 输出 1
// 按位或
result = a | b; // 00000101 | 00001001 = 00001101
printf("a | b = %d\n", result); // 输出 13
// 按位异或
result = a ^ b; // 00000101 ^ 00001001 = 00001100
printf("a ^ b = %d\n", result); // 输出 12
// 按位取反
result = ~a; // ~00000101 = 11111010
printf("~a = %d\n", result); // 输出 250(对于unsigned char)
// 左移
result = a << 2; // 00000101 << 2 = 00010100
printf("a << 2 = %d\n", result); // 输出 20
// 右移
result = b >> 2; // 00001001 >> 2 = 00000010
printf("b >> 2 = %d\n", result); // 输出 2
return 0;
}
输出:
a & b = 1
a | b = 13
a ^ b = 12
~a = 250
a << 2 = 20
b >> 2 = 2
更多示例
#include <stdio.h>
int main() {
unsigned int x = 12; // 二进制:00001100
unsigned int y = 5; // 二进制:00000101
unsigned int z;
// 按位与
z = x & y; // 00001100 & 00000101 = 00000100 (4)
printf("x & y = %u\n", z);
// 按位或
z = x | y; // 00001100 | 00000101 = 00001101 (13)
printf("x | y = %u\n", z);
// 按位异或
z = x ^ y; // 00001100 ^ 00000101 = 00001001 (9)
printf("x ^ y = %u\n", z);
// 按位取反
z = ~x; // ~00001100 = 11110011... (对于unsigned int, 结果依系统而定)
printf("~x = %u\n", z);
// 左移
z = x << 1; // 00001100 << 1 = 00011000 (24)
printf("x << 1 = %u\n", z);
// 右移
z = y >> 1; // 00000101 >> 1 = 00000010 (2)
printf("y >> 1 = %u\n", z);
return 0;
}
输出:
x & y = 4
x | y = 13
x ^ y = 9
~x = 4294967283
x << 1 = 24
y >> 1 = 2
应用场景
- 位掩码:使用按位与操作提取特定位的数据。
#include <stdio.h>
int main() {
unsigned char flags = 0b10101100; // 假设这是一个标志位
unsigned char mask = 0b00001000; // 掩码,提取第四位
unsigned char result = flags & mask;
if (result) {
printf("第四位是1\n");
} else {
printf("第四位是0\n");
}
return 0;
}
输出:
第四位是1
- 设置、清除和切换位:
#include <stdio.h>
int main() {
unsigned char flags = 0b00000000; // 初始状态
// 设置第三位
flags |= 0b00000100; // 00000000 | 00000100 = 00000100
printf("设置第三位后: %u\n", flags); // 输出 4
// 清除第三位
flags &= ~0b00000100; // 00000100 & 11111011 = 00000000
printf("清除第三位后: %u\n", flags); // 输出 0
// 切换第二位
flags ^= 0b00000010; // 00000000 ^ 00000010 = 00000010
printf("切换第二位后: %u\n", flags); // 输出 2
// 再次切换第二位
flags ^= 0b00000010; // 00000010 ^ 00000010 = 00000000
printf("再次切换第二位后: %u\n", flags); // 输出 0
return 0;
}
输出:
设置第三位后: 4
清除第三位后: 0
切换第二位后: 2
再次切换第二位后: 0
注意事项
- 优先级:位运算符的优先级低于算术运算符,高于赋值运算符。使用括号可以明确运算顺序。
- 类型:位运算符仅适用于整数类型(
int、char、long等)。
5.5 赋值运算符
赋值运算符用于将右侧的值赋给左侧的变量。C 语言提供了多种赋值运算符,以简化变量的赋值操作。
常见赋值运算符
| 运算符 | 描述 | 示例 | 解释 |
| ------ | -------------- | ------------ | ------------------- |
| = | 简单赋值 | a = b | 将 b 的值赋给 a |
| += | 加后赋值 | 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 <<= 2 | 等价于 a = a << 2 |
| >>= | 右移后赋值 | a >>= 2 | 等价于 a = a >> 2 |
| &= | 按位与后赋值 | a &= b | 等价于 a = a & b |
| | = | 按位或后赋值 | a |
| ^= | 按位异或后赋值 | a ^= b | 等价于 a = a ^ b |
##### 示例与详细解释
@@H20@@
**输出**:
@@H21@@
##### 注意事项
- **操作顺序**:赋值运算符具有从右到左的结合性。
- **优先级**:赋值运算符的优先级较低,通常与括号结合使用以确保正确的运算顺序。
##### 5.6 条件运算符
**条件运算符**(又称三元运算符)是一种简洁的条件判断方法,语法形式为条件 ? 表达式1 : 表达式2。根据条件的真假,选择执行表达式 1 或表达式 2。
##### 条件运算符的语法
@@H22@@
- **条件**:一个布尔表达式,如果为真(非零),则执行表达式 1;否则执行表达式 2。
- **表达式 1** 和 **表达式 2**:可以是任何类型的表达式。
##### 示例与详细解释
@@H23@@
**输出**:
@@H24@@
##### 更多示例
@@H25@@
**输出**:
@@H26@@
##### 注意事项
- **可读性**:虽然条件运算符可以简化代码,但过度使用或嵌套使用可能会降低代码的可读性。应在保持简洁的同时,确保代码清晰易懂。
- **类型一致性**:条件运算符的两个表达式(表达式 1 和表达式 2)应尽量类型一致,以避免不必要的类型转换。
##### 5.7 运算符优先级与结合性
在 C 语言中,**运算符优先级**决定了表达式中不同运算符的计算顺序,而**结合性**决定了当具有相同优先级的运算符出现在表达式中时,运算的方向。
##### 运算符优先级
不同运算符具有不同的优先级。优先级高的运算符会先被计算。以下是常见运算符的优先级列表(从高到低)。
| 优先级 | 运算符 | 描述 |
| ------ | ---------------------------------------------------- | ---------------------------- |
| 1 | () [] -> . | 函数调用、数组下标、成员访问 |
| 2 | ! ~ ++ -- - + & | 单目运算符 |
| 3 | / % | 乘法、除法、取模 |
| 4 | + - | 加法、减法 |
| 5 | << >> | 左移、右移 |
| 6 | < <= > >= | 关系运算符 |
| 7 | == != | 相等运算符 |
| 8 | & | 按位与 |
| 9 | ^ | 按位异或 |
| 10 | | |
| 11 | && | 逻辑与 |
| 12 | | |
| 13 | ?: | 条件运算符(三元运算符) |
| 14 | = += -= *= /= %= <<= >>= &= ^= | = |
| 15 | , | 逗号运算符 |
运算符结合性
结合性决定了当表达式中存在多个相同优先级的运算符时,运算的顺序。
| 结合性 | 运算符 |
| -------- | -------------------------------------------------------- |
| 从左到右 | () [] -> .、算术运算符、关系运算符、逻辑运算符等 |
| 从右到左 | 赋值运算符、条件运算符(三元运算符)等 |
示例与详细解释
示例 1:优先级高的运算符先计算
#include <stdio.h>
int main() {
int a = 5;
int b = 10;
int c;
// 运算符优先级示例
c = a + b * 2; // 先计算 b * 2,再加 a
printf("a + b * 2 = %d\n", c); // 输出 25
c = (a + b) * 2; // 使用括号改变优先级,先计算 a + b,再乘以2
printf("(a + b) * 2 = %d\n", c); // 输出 30
return 0;
}
输出:
a + b * 2 = 25
(a + b) * 2 = 30
示例 2:结合性示例
#include <stdio.h>
int main() {
int x = 1;
int y = 2;
int z = 3;
int a, b;
// 从左到右结合性
a = x = y + z; // y + z = 5, x = 5, a = 5
printf("a = %d, x = %d\n", a, x); // 输出 a = 5, x = 5
// 赋值运算符的右到左结合性
b = a = x = 10; // x = 10, a = 10, b = 10
printf("a = %d, b = %d, x = %d\n", a, b, x); // 输出 a = 10, b = 10, x = 10
return 0;
}
输出:
a = 5, x = 5
a = 10, b = 10, x = 10
示例 3:条件运算符的优先级与结合性
#include <stdio.h>
int main() {
int a = 5, b = 10, c = 15;
int result;
// 条件运算符的优先级较低,需要使用括号确保运算顺序
result = a > b ? a : b > c ? b : c;
// 等价于: result = (a > b) ? a : (b > c ? b : c)
printf("Result: %d\n", result); // 输出 15
return 0;
}
输出:
Result: 15
运算符优先级表
以下是 C 语言中常见运算符的优先级和结合性列表,便于查阅和参考。
| 优先级 | 运算符 | 描述 | 结合性 |
| ------ | ---------------------------------------------------- | ---------------------------- | ---------- |
| 1 | () [] -> . | 函数调用、数组下标、成员访问 | 从左到右 |
| 2 | ! ~ ++ -- - + * & | 单目运算符 | 从右到左 |
| 3 | * / % | 乘法、除法、取模 | 从左到右 |
| 4 | + - | 加法、减法 | 从左到右 |
| 5 | << >> | 左移、右移 | 从左到右 |
| 6 | < <= > >= | 关系运算符 | 从左到右 |
| 7 | == != | 相等运算符 | 从左到右 |
| 8 | & | 按位与 | 从左到右 |
| 9 | ^ | 按位异或 | 从左到右 |
| 10 | | | 按位或 |
| 11 | && | 逻辑与 | 从左到右 |
| 12 | | | |
| 13 | ?: | 条件运算符(三元运算符) | 从右到左 |
| 14 | = += -= *= /= %= <<= >>= &= ^= | = | 赋值运算符 |
| 15 | , | 逗号运算符 | 从左到右 |
5.8 总结
运算符与表达式是 C 语言编程中的核心概念。通过理解不同运算符的功能、优先级和结合性,能够编写出逻辑正确且高效的代码。以下是本节的关键点:
- 算术运算符:用于基本的数学计算,如加、减、乘、除和取模。
- 关系运算符:用于比较两个值,返回布尔值(真或假)。
- 逻辑运算符:用于连接多个条件表达式,产生布尔值结果。
- 位运算符:用于对整数类型的位进行操作,适用于底层编程和高效算法。
- 赋值运算符:用于将值赋给变量,提供多种简化赋值的方式。
- 条件运算符:一种简洁的条件判断方法,通常用于简化
if-else语句。 - 运算符优先级与结合性:决定表达式中运算的顺序和方向,确保代码按预期执行。