在C++里,数组和指针的算术运算是紧密相关的概念,但初学者常常分不清它们的行为。数组名在表达式中通常会转换为指向首元素的指针,而指针支持加减整数、相减等运算,其步长由指向的类型决定。

指针算术的基本规则
指针加上或减去一个整数n时,实际移动的字节数是n乘以sizeof(所指向的类型)。两个同类型指针相减,得到的是它们之间的元素个数,而不是字节差。
#include <iostream>
using namespace std;
int main() {
int arr[5] = {1, 2, 3, 4, 5};
int* p = arr; // 数组名退化为指针
p = p + 2; // 移动2个int,指向arr[2]
cout << *p << endl; // 输出3
int* q = arr + 4; // 指向arr[4]
ptrdiff_t diff = q - p; // 同类型指针相减
cout << diff << endl; // 输出2,表示相隔2个元素
return 0;
}
数组下标的本质
表达式arr[i]在编译期通常被解释为*(arr + i)。因为arr退化为指针,所以下标运算其实就是指针算术。同样,p[i]等价于*(p + i)。
- arr + i 得到第i个元素的地址
- *(arr + i) 解引用得到元素值
- 数组名不能进行自增等修改,因为它不是可修改的左值
数组名与指针变量的差异
虽然数组名常表现为指针,但它和指针变量不同。用sizeof运算时,数组名得到整个数组大小,指针变量只得到指针本身大小。
#include <iostream>
using namespace std;
int main() {
int arr[5];
int* p = arr;
cout << sizeof(arr) << endl; // 输出20(假设int为4字节)
cout << sizeof(p) << endl; // 输出8(64位平台指针大小)
return 0;
}
注意事项
进行指针算术时必须保证结果仍指向同一数组范围内或尾后位置,否则行为未定义。遍历数组推荐用标准库容器和迭代器,减少手动运算错误。
指针算术是C++贴近硬件效率的体现,但也需要开发者自己保证边界安全。
简单遍历示例
#include <iostream>
using namespace std;
int main() {
double data[3] = {1.1, 2.2, 3.3};
for (double* it = data; it != data + 3; ++it) {
cout << *it << " "; // 利用指针自增遍历
}
return 0;
}
掌握数组与指针算术的联系,能帮助你理解C++底层内存布局,也能在阅读老旧代码或系统级程序时更加从容。