运算符、表达式和语句
第一节:运算符
运算符是C语言中用于执行特定操作的符号,比如加法、比较等。运算符作用于一个或多个操作数(数据值),产生结果。在这里,我们需要强调一个关键术语:数据对象(data object),它指的是内存中存储数据的实体,如变量或数组元素,这些是运算符操作的基本目标。
C语言的运算符按功能分类,主要包括:
- 算术运算符
- 关系运算符
- 逻辑运算符
- 位运算符
- 赋值运算符
- 其他运算符(如条件运算符、sizeof等)
1.1 算术运算符
这些用于基本的数学计算。假设我们有两个整数变量a = 10,b = 3。
| 运算符 | 描述 | 示例 | 结果 |
|---|---|---|---|
| + | 加法 | a + b | 13 |
| - | 减法 | a - b | 7 |
| * | 乘法 | a * b | 30 |
| / | 除法 | a / b | 3 |
| % | 取模(余数) | a % b | 1 |
注意事项:
- 对于整数,除法会丢弃小数部分(例如10/3=3)。
- 如果操作数是浮点数(如double),结果会保留小数。
- 优先级:*、/、%高于+、-。括号()可以改变优先级。
示例代码:
#include <stdio.h>
int main() {
int a = 10, b = 3;
printf("a + b = %d\n", a + b); // 输出: 13
printf("a / b = %d\n", a / b); // 输出: 3
return 0;
}
1.2 关系运算符
用于比较两个值,返回真(1)或假(0)。
| 运算符 | 描述 | 示例 | 结果(假设a=10, b=3) |
|---|---|---|---|
| == | 等于 | a == b | 0 |
| != | 不等于 | a != b | 1 |
| > | 大于 | a > b | 1 |
| < | 小于 | a < b | 0 |
| >= | 大于等于 | a >= b | 1 |
| <= | 小于等于 | a <= b | 0 |
注意:不要把赋值(=)和等于(==)混淆!
示例:
if (a > b) {
printf("a 大于 b\n");
}
1.3 逻辑运算符
用于组合多个条件,返回真或假。
| 运算符 | 描述 | 示例(假设x=1, y=0) | 结果 |
|---|---|---|---|
| && | 逻辑与(AND) | x && y | 0 |
| || | 逻辑或(OR) | x || y | 1 |
| ! | 逻辑非(NOT) | !x | 0 |
短路求值:&&只在左边真时检查右边;||只在左边假时检查右边。这能避免不必要的计算或错误。
示例:
if (a > 0 && b > 0) {
printf("两者都正\n");
}
1.4 位运算符
操作二进制位,适合底层编程。
| 运算符 | 描述 | 示例(a=5:0101, b=3:0011) | 结果(二进制) |
|---|---|---|---|
| & | 按位与 | a & b | 0001 (1) |
| | | 按位或 | a | b | 0111 (7) |
| ^ | 按位异或 | a ^ b | 0110 (6) |
| ~ | 按位取反 | ~a | 1010... (负数,取决于系统) |
| << | 左移 | a << 1 | 1010 (10) |
| >> | 右移 | a >> 1 | 0010 (2) |
示例:左移相当于乘2,右移相当于除2(对于正数)。
1.5 赋值运算符
用于给变量赋值。在赋值运算符中,我们需要强调左值(lvalue)和右值(rvalue)的概念。左值是指可以出现在赋值运算符左侧的表达式,它表示一个可修改的内存位置(如变量名),而右值是指出现在右侧的表达式,它是一个临时值或常量,不能被修改。例如,在a = b + 1;中,a是左值,b + 1是右值。
| 运算符 | 描述 | 示例 | 等价于 |
|---|---|---|---|
| = | 简单赋值 | 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 |
还有位运算赋值如 &=, |= 等。
1.6 其他运算符
-
条件运算符(三元):条件 ? 值1 : 值2。如果条件真,返回值1,否则值2。 示例:max = (a > b) ? a : b;
-
sizeof:返回类型或变量的大小(字节)。 示例:sizeof(int); // 通常4
-
逗号运算符:, 用于顺序执行表达式,返回最后一个。 示例:a = (b=3, b+2); // a=5
-
自增/自减:++ 和 --。
- 前置:++a 先加后用。
- 后置:a++ 先用后加。
优先级总结:从高到低:( ) > ++/-- > * / % > + / - > << / >> > && / || > 赋值
第二节:表达式
表达式是运算符和操作数的组合,计算出一个值。每个表达式都有类型和值。在表达式中,操作数通常是数据对象,如变量或常量。表达式也可以分类为左值或右值:如果表达式表示一个可修改的位置(如数组元素),它是左值;否则,它是右值(如字面量或计算结果)。
2.1 表达式类型
- 常量表达式:如 5 + 3 = 8。
- 变量表达式:如 a + b。
- 函数调用:如 printf("hello") 返回值。
2.2 求值顺序
C语言不保证表达式中函数调用的顺序(除了逻辑运算符的短路)。小心副作用(如++)。
2.3 类型转换
在表达式中,当不同类型的数据参与运算时,会发生类型转换,以确保兼容性。类型转换分为两种:
-
隐式转换(自动转换):由编译器自动进行。通常,低精度类型向高精度类型转换(称为类型提升),如int转为double。规则包括:
- 整数提升:char/short转为int。
- 浮点数:int转为float或double。
- 在算术运算中,两个操作数会转换为共同类型(通常更高的类型)。
-
显式转换(强制转换):使用(类型)表达式手动转换,可能丢失精度。 示例:(int)3.14 结果为3。
注意事项:
- 隐式转换可能导致意外结果,如整数除法丢失小数。
- 在赋值时,右值会转换为左值的类型。
- 避免不必要的转换以防精度丢失或溢出。
示例:
int x = 10;
double y = 3.5;
double z = x + y; // x 隐式转为 double,结果13.5
int w = (int)y; // 显式转为 int,结果3
2.4 常见错误
- 忘记括号导致优先级错。
- 整数溢出(值太大超出类型范围)。
第三节:语句
语句是程序的基本执行单位,以;结束。语句执行动作。
3.1 表达式语句
任何表达式加;就是语句。通常用于赋值或调用。 示例:a = 5; printf("hi");
3.2 复合语句(块)
用{}包围多个语句,视为一个语句。用于if、循环等。 示例:
{
int x = 1;
x++;
}
3.3 控制语句
虽然本章焦点是基础语句,但简单介绍条件和循环(详细在下一章)。
- if语句:if (条件) 语句; else 语句;
- switch:多分支选择。
- 循环:while (条件) 语句; do 语句 while(条件); for(初始化;条件;更新) 语句;
示例:简单if
if (a > b) {
printf("a大");
} else {
printf("b大");
}
3.4 空语句和标签语句
- 空语句:只是;。小心使用。
- 标签:用于goto(不推荐用goto)。
注意:语句必须在函数内执行。
总结与进阶
这一章我们从运算符入手,构建表达式,再到语句,形成C程序的基本框架。记住:多练习代码,调试错误是最好的老师。
进阶阅读:运算符重载(C++才有)、高级表达式优化。