指针加减法本质是按所指类型大小缩放的地址运算,p + n 实际增加 n sizeof(p) 字节;仅对同数组指针相减合法,结果为元素个数差;数组下标访问等价于指针算术,但越界行为未定义。

指针加减法本质是按类型大小缩放的地址运算
在 C++ 中,p + n 不是简单地给地址加 n 字节,而是加 n * sizeof(*p) 字节。比如 int* 指针加 1,实际地址增加 4(或 8)字节;char* 加 1 才真加 1 字节。这是偏移能“对齐元素”的根本原因。
常见错误是把指针当普通整数用,比如对 int* p 写 (char*)p + 2 想跳过 2 个字节——这会破坏类型语义,后续解引用极易越界或读错数据。
- 确保指针类型与目标数组元素类型一致,否则
+n的步长会出错 - 偏移后必须仍在同一数组(或末尾的“一格”内),否则行为未定义(UB)
-
p - q只对指向同一数组的指针合法,结果是ptrdiff_t类型,表示元素个数差
用 ptr + i 替代 arr[i] 实现等价访问
数组名退化为指针后,arr[i] 本质上就是 *(arr + i)。两者完全等价,编译器生成的汇编通常也一样。
实操中,用指针算术遍历更灵活:比如处理子区间、跳过前 N 个元素、或配合 STL 算法(如 std::sort(arr + 2, arr + 5))。
-
int arr[5] = {10,20,30,40,50}; int* p = arr + 2;→*p是30,*(p + 1)是40 - 不要写
arr + 10访问arr[10]—— 即使编译通过,运行时大概率踩内存 - 用
std::distance(p, q)替代手动相减,更安全且语义清晰(尤其对迭代器)
小心 sizeof 和指针类型混用导致的偏移失效
新手常误以为 sizeof(ptr) 能帮算偏移,但 sizeof(int*) 是指针本身大小(通常 8),和它指向的 int 大小(通常 4)无关。真正决定 +1 步长的是 sizeof(*ptr)。
典型陷阱:用 void* 做通用指针并尝试加减——C++ 不允许 void* 算术运算(C 允许但不推荐)。必须先转成带类型的指针。
- 错误:
void* v = arr; int* p = (int*)v + 1;→ 这里(int*)v + 1是合法的,但v + 1直接报错 - 正确方式:始终用目标类型声明指针,或用
reinterpret_cast<int>(v) + 1</int> - 结构体数组偏移时,
struct S* ps的+1会跳过整个sizeof(S),不是字段偏移
多维数组的指针偏移要分清层级
对于 int a[3][4],a 类型是 int[4][4]?不对——a 是 int (*)[4](指向含 4 个 int 的数组的指针)。所以 a + 1 跳过一整行(16 字节),*a + 1 才是第一行第二个元素。
想用指针模拟二维访问,关键看你怎么声明指针:
-
int (*p)[4] = a;→p + 1指向下一行首地址,(*p)[2]是第一行第 3 个元素 -
int* q = &a[0][0];→q + i * 4 + j对应a[i][j],适合线性遍历 - 别用
int** pp指向a——a不是二级指针,强制转换会导致严重 UB
最易被忽略的是:指针偏移的合法性完全依赖程序员保证——编译器几乎不检查越界。哪怕 ptr + 1000 在语法上合法,只要超出了分配的内存范围,就是未定义行为,调试时可能静默失败或崩溃在奇怪的地方。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











