指针算术运算按类型步进而非字节加减:ptr+1增加sizeof(ptr)字节,同类型指针相减得元素个数(ptrdiff_t),且须指向同一数组;void不可参与算术运算。

指针参与算术运算不是“把地址当整数加减”,而是按类型步进——这是最常被误解的起点。
指针加减整数:移动的是“元素个数”,不是字节数
当你写 ptr + 1,编译器不会给地址值加 1,而是加 sizeof(*ptr)。比如:
-
int* p = &arr[0],p + 1指向&arr[1],地址增加 4(32 位)或 8(64 位)字节 -
char* q = str,q + 1地址只加 1,因为sizeof(char) == 1 -
double* r加 1,地址加 8 字节(典型情况)
错误写法:(char*)p + 1 强转后加 1 是字节偏移,但若原意是跳过一个 int,这反而破坏了语义。别靠强转“绕过类型”来算地址——该用什么类型就声明什么类型。
两个同类型指针相减:结果是“元素个数”,不是字节差
p1 - p2 的结果类型是 ptrdiff_t(有符号整型),它表示两个指针之间隔了多少个 *所指类型的元素。
立即学习“C++免费学习笔记(深入)”;
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 合法前提:
p1和p2必须指向同一数组(或数组末尾的下一个位置),否则行为未定义 -
int arr[5]; int* a = &arr[0], *b = &arr[3];→b - a == 3,不是 12 - 不能用于不同数组、malloc 分配的不同块、或非数组内存(如栈变量地址)之间相减
常见误用:&x - &y(x、y 是独立局部变量)——即使编译通过,结果无意义,且可能因栈布局变化而每次不同。
指针比较:只在“可比较范围内”才安全
用 ==、!=、、<code>> 比较指针,仅当它们指向同一对象(或同一数组的连续内存)时才有明确定义。
- 正确:
ptr (遍历数组常用)、<code>p != nullptr - 危险:
p > q,其中p指向堆内存,q指向栈变量——地址数值大小无逻辑关系 -
void*不能直接参与+、-、等运算,必须先转为具体类型指针
注意:std::less<void>()</void> 可用于跨内存区域的“总序比较”,但那是为哈希/容器设计的特殊约定,不反映实际内存顺序。
自增/自减:本质是 ptr = ptr + 1 或 ptr = ptr - 1
ptr++、--ptr 等操作,和加减整数等价,同样遵循类型步进规则。
- 循环中写
for (int* p = arr; p != arr + N; ++p)比for (int i = 0; i 更贴近底层意图 - 但注意:如果
ptr是nullptr或已越界(如&arr[N]再 ++),行为未定义 - 不要对数组名(如
arr++)做自增——arr是右值,不可修改
最容易忽略的一点:所有指针算术的前提是“指向有效内存范围”。越界哪怕一个元素,哪怕只是比较(ptr > &arr[N]),在严格模式(如 ASan)下都会触发诊断。别依赖“好像没崩”来判断正确性。

















