深入理解 C++ 中的指针与自增表达式:*a++、(*a)++ 和 *++a 的区别解析
一、运算符优先级与结合性
首先,运算符优先级决定了表达式的解析方式:
后缀自增
a++
的优先级高于解引用*
前缀自增
++a
的优先级也高于解引用*
括号
()
拥有最高优先级,可以改变默认运算顺序
基于此:
*a++
等价于*(a++)
(*a)++
等价于 对*a
的值做后缀自增*++a
等价于*(++a)
二、逐个拆解分析
2.1 *a++
—— 指针先用后自增
含义:
指针
a
当前指向一个地址解引用
*a
得到该地址的值后缀自增
a++
先使用当前指针值,然后指针向后移动一格
执行顺序:
取
a
当前值(指向arr[0]
)解引用得到
arr[0]
的值:10
a
自增,指向arr[1]
代码示例:
int arr[] = {10, 20, 30};
int* a = arr; // 指针 a 指向数组首元素 arr[0]std::cout << *a++ << std::endl; // 输出 10
std::cout << *a << std::endl; // 输出 20,说明 a 指向下一个元素了
2.2 (*a)++
—— 值先用后自增,指针不变
含义:
*a
访问当前指针指向的值对该值进行后缀自增(值加一)
指针本身不发生变化
执行顺序:
取
*a
当前值(例如20
)输出该值
将该值加一存回内存(即
arr[1]
变成21
)
代码示例:
int arr[] = {10, 20, 30};
int* a = arr; // 指针 a 指向数组首元素 arr[0]std::cout << (*a)++ << std::endl; // 输出 10
std::cout << *a << std::endl; // 输出 11,值被修改了
2.3 *++a
—— 指针先自增再解引用
含义:
前缀自增:指针
a
先向后移动一格解引用新位置的值
执行顺序:
指针
a
自增,指向arr[2]
解引用
*a
,得到30
代码示例:
int arr[] = {10, 20, 30};
int* a = arr; // 指针 a 指向数组首元素 arr[0]std::cout << *++a << std::endl; // 输出 20
std::cout << *a << std::endl; // a 现在指向 arr[2]
三、总结和源码
表达式 | 含义 | 指针移动 | 访问的值 | 值是否变化 |
---|---|---|---|---|
*a++ | 先取当前指针指向的值,再指针后移 | 指针后移 | 当前指针指向的值 | 否 |
(*a)++ | 当前指针指向的值后缀自增 | 指针不变 | 当前指针指向的值 | 是,值 +1 |
*++a | 指针先前缀自增,再取新地址值 | 指针前移 | 新指针指向的值 | 否 |
完整示例代码
注意!连续执行和分开执行如果不重置指针指向结果也会不一样,上文是分开执行的,下面是连续执行的结果:
#include <iostream>int main() {int arr[] = {10, 20, 30};int* a = arr;std::cout << "*a++: " << *a++ << std::endl; // 输出 10,a 指向 arr[1]std::cout << "*a after *a++: " << *a << std::endl; // 输出 20std::cout << "(*a)++: " << (*a)++ << std::endl; // 输出 20,arr[1] 变成 21std::cout << "*a after (*a)++: " << *a << std::endl; // 输出 21std::cout << "*++a: " << *++a << std::endl; // a 指向 arr[2],输出 30std::cout << "*a after *++a: " << *a << std::endl; // 输出 30return 0;
}