C语言运算符与表达式
一、运算符概述
在C语言中,运算符用于对变量和常量进行操作。C语言提供了多种运算符,可以执行数学运算、逻辑判断、位操作等任务。
运算符分类
- 算术运算符:执行基本数学运算
- 关系运算符:比较两个值的大小
- 逻辑运算符:组合多个条件
- 位运算符:对整数的二进制位进行操作
- 赋值运算符:给变量赋值
- 其他运算符:包括条件运算符、逗号运算符、sizeof运算符等
二、算术运算符
算术运算符用于执行数学运算。
| 运算符 | 描述 | 示例 |
|---|---|---|
| + | 加法 | x + y |
| - | 减法 | x - y |
| * | 乘法 | x * y |
| / | 除法 | x / y |
| % | 取模 | x % y |
| ++ | 前缀/后缀自增 | ++x 或 x++ |
| -- | 前缀/后缀自减 | --x 或 x-- |
#include <stdio.h>
int main_function() {
int x = 10, y = 3;
printf("x + y = %d\n", x + y); // 13
printf("x - y = %d\n", x - y); // 7
printf("x * y = %d\n", x * y); // 30
printf("x / y = %d\n", x / y); // 3 (整数除法)
printf("x %% y = %d\n", x % y); // 1
// 自增运算符示例
int a = 5;
printf("a++ = %d\n", a++); // 先使用a的值5,然后a变为6
printf("++a = %d\n", ++a); // a先变为7,然后使用a的值7
// 浮点数除法示例
float m = 10.0, n = 3.0;
printf("m / n = %f\n", m / n); // 3.333333
return 0;
}
三、关系运算符
关系运算符用于比较两个值,返回布尔值(0或1)。
| 运算符 | 描述 | 示例 |
|---|---|---|
| == | 等于 | a == b |
| != | 不等于 | a != b |
| > | 大于 | a > b |
| < | 小于 | a < b |
| >= | 大于等于 | a >= b |
| <= | 小于等于 | a <= b |
#include <stdio.h>
int main_function() {
int x = 10, y = 20;
printf("%d == %d: %d\n", x, y, x == y); // 0
printf("%d != %d: %d\n", x, y, x != y); // 1
printf("%d > %d: %d\n", x, y, x > y); // 0
printf("%d < %d: %d\n", x, y, x < y); // 1
printf("%d >= %d: %d\n", x, y, x >= y); // 0
printf("%d <= %d: %d\n", x, y, x <= y); // 1
return 0;
}
四、逻辑运算符
逻辑运算符用于组合多个条件。
| 运算符 | 描述 | 示例 |
|---|---|---|
| && | 逻辑与 | p && q |
| ! | 逻辑非 | !p |
#include <stdio.h>
int main_function() {
int p = 1, q = 0;
printf("%d && %d: %d\n", p, q, p && q); // 0
printf("%d || %d: %d\n", p, q, p || q); // 1
printf("!%d: %d\n", p, !p); // 0
printf("!%d: %d\n", q, !q); // 1
// 短路求值示例
int m = 0, n = 1;
if(m != 0 && n/m > 1) {
printf("This won't be printed\n");
}
return 0;
}
五、位运算符
位运算符直接操作整数的二进制位。
| 运算符 | 描述 | 示例 |
|---|---|---|
| & | 按位与 | a & b |
| 按位或 | ||
| ^ | 按位异或 | a ^ b |
| ~ | 按位取反 | ~a |
| << | 左移 | a << n |
| >> | 右移 | a >> n |
#include <stdio.h>
int main_function() {
unsigned char p = 0b0011, q = 0b0101; // 3和5的二进制表示
printf("p & q: %d\n", p & q); // 0001 (1)
printf("p | q: %d\n", p | q); // 0111 (7)
printf("p ^ q: %d\n", p ^ q); // 0110 (6)
printf("~p: %d\n", ~p & 0xFF); // 11111100 (252), 只取低8位
printf("p << 1: %d\n", p << 1); // 0110 (6)
printf("p >> 1: %d\n", p >> 1); // 0001 (1)
// 使用位运算实现快速乘除
int w = 10;
printf("w * 8 = %d\n", w << 3); // 左移3位相当于乘以8
printf("w / 4 = %d\n", w >> 2); // 右移2位相当于除以4
return 0;
}
六、赋值运算符
赋值运算符用于给变量赋值。
| 运算符 | 描述 | 示例 |
|---|---|---|
| = | 简单赋值 | a = b |
| += | 加后赋值 | a += b |
| -= | 减后赋值 | a -= b |
| *= | 乘后赋值 | a *= b |
| /= | 除后赋值 | a /= b |
| %= | 取模后赋值 | a %= b |
| <<= | 左移后赋值 | a <<= b |
| >>= | 右移后赋值 | a >>= b |
| &= | 按位与后赋值 | a &= b |
| ^= | 按位异或后赋值 | a ^= b |
| = | 按位或后赋值 |
#include <stdio.h>
int main_function() {
int a = 10;
a += 5; // 等价于 a = a + 5
printf("a += 5: %d\n", a); // 15
a -= 3; // 等价于 a = a - 3
printf("a -= 3: %d\n", a); // 12
a *= 2; // 等价于 a = a * 2
printf("a *= 2: %d\n", a); // 24
a /= 4; // 等价于 a = a / 4
printf("a /= 4: %d\n", a); // 6
a %= 4; // 等价于 a = a % 4
printf("a %%= 4: %d\n", a); // 2
a <<= 2; // 等价于 a = a << 2
printf("a <<= 2: %d\n", a); // 8
a |= 1; // 等价于 a = a | 1
printf("a |= 1: %d\n", a); // 9
return 0;
}
七、其他运算符
1. 条件运算符(三元运算符)
语法:条件表达式 ? 表达式1 : 表达式2
2. 逗号运算符
语法:表达式1, 表达式2, ..., 表达式n
3. sizeof运算符
返回变量或类型的大小(以字节为单位)
4. 地址运算符
&:取地址运算符 *:指针运算符
#include <stdio.h>
int main_function() {
// 条件运算符示例
int x = 10, y = 20;
int max_val = (x > y) ? x : y;
printf("较大的数是: %d\n", max_val); // 20
// 逗号运算符示例
int a = 5, b = 10, c = (a++, b++, a + b);
printf("c = %d, a = %d, b = %d\n", c, a, b); // c=15, a=6, b=11
// sizeof运算符示例
printf("int 类型大小: %zu 字节\n", sizeof(int));
printf("double 类型大小: %zu 字节\n", sizeof(double));
printf("变量x大小: %zu 字节\n", sizeof(x));
// 地址运算符示例
int val = 30;
int *ptr = &val;
printf("val的值: %d\n", val);
printf("val的地址: %p\n", &val);
printf("ptr指向的值: %d\n", *ptr);
return 0;
}
八、运算符优先级和结合性
当表达式中有多个运算符时,C语言会根据运算符的优先级和结合性来决定运算顺序。
运算符优先级表(从高到低)
| 类别 | 运算符 | 结合性 |
|---|---|---|
| 后缀 | () [] -> ++ -- | 从左到右 |
| 一元 | + - ! ~ ++ -- (type)* & sizeof | 从右到左 |
| 乘除 | * / % | 从左到右 |
| 加减 | + - | 从左到右 |
| 移位 | << >> | 从左到右 |
| 关系 | < <= > >= | 从左到右 |
| 相等 | == != | 从左到右 |
| 位与 | & | 从左到右 |
| 位异或 | ^ | 从左到右 |
| 位或 | ||
| 逻辑与 | && | 从左到右 |
| 逻辑或 | ||
| 条件 | ?: | 从右到左 |
| 赋值 | = += -= *= /= %= <<= >>= &= ^= | = |
| 逗号 | , | 从左到右 |
#include <stdio.h>
int main_function() {
int a = 5, b = 10, c = 15;
// 优先级示例
int result1 = a + b * c; // 等价于 a + (b * c)
printf("a + b * c = %d\n", result1); // 155
int result2 = (a + b) * c;
printf("(a + b) * c = %d\n", result2); // 225
// 结合性示例
int d = a = b; // 从右到左结合,等价于 a = b; d = a;
printf("d = %d, a = %d\n", d, a); // 都是10
int e = a + b + c; // 从左到右结合,等价于 (a + b) + c
printf("e = %d\n", e); // 35
// 复杂表达式示例
int f = a++ + b * (c - a);
printf("f = %d, a = %d\n", f, a); // f=60, a=11
return 0;
}
九、表达式
表达式是由运算符和操作数组成的式子,可以计算出一个值。
表达式类型
- 算术表达式:由算术运算符组成,如
a + b * c - 关系表达式:由关系运算符组成,如
a > b - 逻辑表达式:由逻辑运算符组成,如
a && b || c - 赋值表达式:由赋值运算符组成,如
a = b + c - 条件表达式:由条件运算符组成,如
a > b ? a : b - 逗号表达式:由逗号运算符组成,如
a = (b++, c--)
表达式求值顺序
- 确定运算符的优先级
- 相同优先级的运算符根据结合性确定顺序
- 注意运算符的副作用(如自增自减)
#include <stdio.h>
int main_function() {
// 算术表达式示例
int a = 10, b = 20, c = 30;
int result = a * b + c / a - b % a;
printf("算术表达式结果: %d\n", result); // 200 + 3 - 0 = 203
// 关系表达式示例
if(a < b && b < c) {
printf("a < b < c 成立\n");
}
// 逻辑表达式示例
int flag1 = 1, flag2 = 0;
if(flag1 || !flag2) {
printf("逻辑表达式为真\n");
}
// 赋值表达式示例
int m, n, o;
m = n = o = 100; // 从右到左赋值
printf("m=%d, n=%d, o=%d\n", m, n, o);
// 条件表达式示例
int max_num = (a > b) ? a : b;
printf("较大的数是: %d\n", max_num);
// 逗号表达式示例
int p = (a++, b++, c++, a + b + c);
printf("p=%d, a=%d, b=%d, c=%d\n", p, a, b, c); // p=63, a=11, b=21, c=31
return 0;
}
十、常见问题与注意事项
- 整数除法:两个整数相除结果仍是整数,小数部分被截断
- 运算符优先级混淆:使用括号明确运算顺序
- 自增自减的副作用:避免在同一个表达式中多次修改同一个变量
- 浮点数比较:由于精度问题,避免直接比较浮点数是否相等
- 短路求值:逻辑与和逻辑或运算符的短路特性
- 类型溢出:注意数据类型的范围,避免溢出
- 未定义行为:如
i = i++这样的表达式结果未定义
#include <stdio.h>
#include <math.h>
int main_function() {
// 整数除法问题
int x = 5, y = 2;
float z = x / y; // 结果是2.0而不是2.5
printf("错误的除法: %.1f\n", z);
// 正确的做法
z = (float)x / y;
printf("正确的除法: %.1f\n", z);
return 0;
}
总结
掌握C语言的运算符和表达式是编写高效、正确程序的关键。以下是本文的要点总结:
- 运算符多样性:C语言提供了丰富的运算符类型,满足各种运算需求。
- 表达式灵活性:通过组合不同的运算符和操作数,可以构建复杂的表达式。
- 优先级与结合性:理解运算符的优先级和结合性是写出正确表达式的基础。
- 类型转换:混合类型运算时需要注意类型转换规则。
- 效率考量:位运算和复合赋值运算通常效率更高。
- 陷阱警示:自增/自减运算、整数除法、浮点数比较等问题需要特别注意。
记住,清晰可读的表达式往往比"聪明"但晦涩的写法更有价值。在保证正确性的前提下,适当考虑效率,这样的代码才是高质量的C语言代码。