C/C++ 指针自增、自减全面对比

一、基础概念

指针 p 存放地址*p 取地址对应的值;

++/--前置++p--p)、后置p++p--);

指针自增不是地址+1,而是向后偏移一个指向类型的字节大小

示例:int *p,int占4字节,则 p++ 等价于 p = p + 4

二、四种写法核心区别

1. 后置自增 p++

  1. 先使用原始p的值参与运算;
  2. 运算结束后,指针再向后偏移1个类型单位。
c 复制代码
int arr[] = {10,20,30};
int *p = arr;
int val = *p++; 
// 拆解:先取 *p = 10 赋值给val,再 p = p + 4
// val=10,p现在指向20

2. 后置自减 p--

  1. 先使用原始p的值参与运算;
  2. 运算结束后,指针向前偏移1个类型单位。
c 复制代码
int val = *p--;
// 先取当前*p,再p往前移一位

3. 前置自增 ++p

  1. 指针先偏移,再使用新地址参与运算。
c 复制代码
int arr[] = {10,20,30};
int *p = arr;
int val = *++p;
// 拆解:先 p=p+4 指向20,再取值 *p=20 赋给val
// val=20

4. 前置自减 --p

  1. 指针先向前偏移,再取值/运算。
c 复制代码
int val = *--p;
// p先前移一位,再取新地址的值

三、优先级对比(关键)

++/-- 后置 > * 解引用 > ++/-- 前置

等价括号写法:

  1. *p++*(p++):先取值,后移指针
  2. *++p*(++p):先移指针,后取值
  3. (*p)++:取p指向的值,值自增,指针不变(极易混淆!)
  4. ++(*p):p指向的值先自增,指针不变

易错示例区分

c 复制代码
int a = 5;
int *p = &a;

// 1. *p++
int x = *p++; 
// x=5,p地址+4,a不变

// 2. (*p)++
int y = (*p)++;
// y=5,a变成6,p地址不变

// 3. ++(*p)
int z = ++(*p);
// a先+1=7,z=7,p不变

四、指针自增 vs 自减 行为对比表

表达式 执行顺序 指针变化 典型用途
p++ 先用原地址,后向后移 地址+sizeof(类型) 顺序遍历数组,读完当前再走下一个
++p 先向后移,再用新地址 地址+sizeof(类型) 跳过首元素,从第二个开始遍历
p-- 先用原地址,后向前移 地址-sizeof(类型) 倒序遍历,读完当前看上一个
--p 先向前移,再用新地址 地址-sizeof(类型) 跳过末尾元素,倒序从倒数第二个开始

五、完整代码演示对比

c 复制代码
#include <stdio.h>
int main() {
    int arr[4] = {1,2,3,4};
    int *p = &arr[1]; // p初始指向2

    // 1. *p++
    int v1 = *p++;
    printf("*p++: val=%d, p指向=%d\n", v1, *p); // val=2, p→3
    p = &arr[1]; // 重置

    // 2. *++p
    int v2 = *++p;
    printf("*++p: val=%d, p指向=%d\n", v2, *p); // val=3, p→3
    p = &arr[1];

    // 3. *p--
    int v3 = *p--;
    printf("*p--: val=%d, p指向=%d\n", v3, *p); // val=2, p→1
    p = &arr[1];

    // 4. *--p
    int v4 = *--p;
    printf("*--p: val=%d, p指向=%d\n", v4, *p); // val=1, p→1

    return 0;
}

输出:

复制代码
*p++: val=2, p指向=3
*++p: val=3, p指向=3
*p--: val=2, p指向=1
*--p: val=1, p指向=1

六、核心总结

  1. 后置p++/p--:先使用当前指针地址,运算完再移动指针;
  2. 前置++p/--p:先移动指针,再使用新地址;
  3. (*p)++值自增,指针地址完全不变,和指针移动无关;
  4. 自增向后走数组、自减向前走数组,遍历时根据是否要跳过当前元素选择前置/后置。