其他运算符
本节涉及的一些运算符(例如取地址/解引用、成员访问、下标、函数调用)需要更多基础概念,才能讲得严谨。
本节现在补上这些运算符的主线语义,细节章节后续再逐项加深。
1. 取地址与解引用:& 和 *
一元 & 产生对象的地址;一元 * 对指针解引用,访问该地址指向的对象。两者互为配对关系,但不是任意场景都可互换:只有“可取地址的左值表达式”才能使用 &;空指针或无效地址使用 * 会导致未定义行为。
int x = 10;
int *p = &x;
*p = 20; /* 修改 x */2
3
运行结果:该代码块主要用于语法或结构说明,单独运行通常无终端输出。
在项目代码里,解引用前先确认指针有效,是最基本的防御式写法。
2. 成员访问:. 和 ->
. 用于结构体或联合体对象本身,-> 用于指向结构体或联合体对象的指针。a->b 与 (*a).b 语义等价,但后者更容易出错(括号不能省)。
struct point {
int x;
int y;
};
struct point p1 = {1, 2};
struct point *pp = &p1;
pp->x = 3;
p1.y = 4;2
3
4
5
6
7
8
9
10
运行结果:该代码块主要用于语法或结构说明,单独运行通常无终端输出。
当一个接口以“对象指针”作为输入时,统一使用 -> 能减少视觉噪声。
3. 下标访问:[]
a[b] 定义为 *(a + b)。这条规则解释了为什么数组对象在表达式中常“退化”为首元素指针,也解释了指针加偏移后可直接使用下标语法。
int arr[4] = {10, 20, 30, 40};
int *p = arr;
int n1 = arr[2];
int n2 = p[2];2
3
4
5
运行结果:该代码块主要用于语法或结构说明,单独运行通常无终端输出。
二者结果一致,但越界访问仍然是未定义行为。下标语法不会自动做边界检查,工程上应在逻辑层显式约束索引范围。
4. 函数调用:()
函数调用表达式会先对被调函数表达式和实参求值,再进入被调函数执行。C 标准没有规定实参求值的先后顺序,因此实参之间不应依赖彼此副作用。
int add(int a, int b) {
return a + b;
}
int main(void) {
int s = add(3, 4);
return s == 7 ? 0 : 1;
}2
3
4
5
6
7
8
运行结果:该代码块主要用于语法或结构说明,单独运行通常无终端输出。
像 f(i++, i++) 这类写法可读性差且风险高,应避免。
5. 使用建议
这些运算符看似基础,实际是内存模型和对象语义的核心入口。写代码时优先保证“对象有效、边界清楚、求值关系可读”,比炫技式写法更符合标准和工程最佳实践。
1. 习题
本节暂不设置习题:请先完成本章其他小节的练习。