指针算术运算的底层逻辑是地址偏移量按所指类型大小自动缩放:int*加1实际偏移sizeof(int)字节(如4字节),确保精准指向下一个同类型元素;ptr + n合法当且仅当指向同一数组且n≤数组长度,arr + size为允许的尾后指针(不可解引用);两指针相减结果为ptrdiff_t类型的元素个数差。

指针算术运算的底层逻辑是什么
C++ 中指针不是普通整数,但支持 +、-、++、-- 等算术运算,其步长由所指类型决定。比如 int* 指针加 1,实际地址偏移 sizeof(int) 字节(通常为 4),而非 1 字节。这是遍历数组安全的前提。
- 指针必须指向合法内存区域(如数组首地址或其后一个位置),否则行为未定义
-
ptr + n合法当且仅当ptr指向数组第 0 个元素且n ≤ 数组长度(ptr + size是允许的“尾后指针”,但不可解引用) -
ptr - ptr2仅在两指针指向同一数组(或同一对象)时有意义,结果是ptrdiff_t类型的元素差
用指针遍历一维数组的正确写法
最常见错误是越界访问或混淆“尾后指针”与“末元素指针”。以下以 int arr[5] = {1,2,3,4,5}; 为例:
- 正确:从首地址开始,用
ptr != arr + 5作循环条件int* ptr = arr; while (ptr != arr + 5) { std::cout << *ptr << " "; ++ptr; } - 错误:用
ptr <= arr + 4—— 虽然对int常见,但若数组为空(size == 0),arr + 4就非法;而arr + 0始终合法 - 更健壮写法(尤其配合容器或模板):
for (int* p = arr; p != std::end(arr); ++p),std::end(arr)返回尾后指针,类型安全
多维数组中指针算术的陷阱
二维数组如 int mat[3][4] 在内存中是连续的 12 个 int,但指针类型必须匹配才能正确步进:
-
int (*row)[4] = mat;:指向“含 4 个 int 的数组”的指针,row + 1跳过一整行(16 字节) -
int<em> p = &mat[0][0];</em>:指向首元素,p + i 4 + j可访问mat[i][j] - 错误:把
int<strong></strong>当作二维数组指针传入——int是指针的指针,内存布局完全不同,强行算术会导致随机读写
与迭代器和范围 for 的对比取舍
原生指针遍历性能不输迭代器,但丢失类型安全和可组合性:
立即学习“C++免费学习笔记(深入)”;
-
std::vector<int>::iterator</int>支持it + n,语义同指针,但编译期能检查是否属于同一容器 -
for (auto& x : vec)最简洁,但无法获取下标或反向遍历(除非额外计数) - 真正需要指针算术的场景:高性能数值计算(如 SIMD 对齐访问)、与 C API 交互、实现底层容器
指针算术本身很简单,难的是时刻记住“它依赖类型大小、依赖数组边界、依赖你对内存布局的精确理解”。哪怕只错一个 + 或 ==,就可能触发未定义行为,且不一定立刻崩溃。


















