为何*(&arr + 1) - arr能准确计算数组元素个数?&arr的指向作用解析
为什么
*(&arr + 1) - arr能算出数组的元素个数? 先看一下你给出的代码:
#include <bits/stdc++.h> using namespace std; int main() { int arr[] = {1, 2, 3, 4, 5, 6}; int size = *(&arr + 1) - arr; cout << "Number of elements in arr[] is " << size; return 0; }
这个技巧的核心在于理解C++中数组名和数组指针的区别,咱们一步步拆解开看:
1. 先搞懂&arr到底是什么
平时我们用数组名arr的时候,它大多会自动退化成指向数组第一个元素的指针(类型是int*),但当你给arr取地址&arr时,规则就变了:
&arr的类型是int (*)[6]——翻译成人话就是"一个指向包含6个int的数组的指针",它指向的是整个数组的起始位置,而不是单个元素。- 这个指针的"步长"很关键:指针做加法时,偏移量是它指向类型的大小。所以
&arr加1的话,会直接跳过整个数组的大小(也就是6 * sizeof(int)字节),而不是只跳一个int。
2. 分析&arr + 1的指向
&arr指向原数组arr的开头,执行&arr + 1后:
- 指针会偏移整个数组的内存大小,最终指向的是原数组紧挨着的下一个位置——你可以把它想象成一个和
arr一模一样的"虚拟数组"的开头,而这个位置刚好就是原数组最后一个元素(arr[5])的下一个内存地址,和arr + 6指向的地方完全一致。
3. 解引用*(&arr + 1)的作用
对&arr + 1解引用得到*(&arr + 1),此时这个表达式的结果是那个虚拟数组的数组名,而数组名又会自动退化成指向它第一个元素的指针:
- 这个指针的类型是
int*,指向的就是原数组末尾之后的那个地址(虽然原数组没有arr[6]这个元素,但C++允许指向数组末尾之后的第一个位置,这是合法的)。
4. 指针相减得到元素个数
C++里有个规则:如果两个同类型的指针指向同一个数组(或者数组末尾之后的第一个合法位置),它们相减的结果是两个指针之间的元素个数,而不是字节数。
arr退化为指向第一个元素的int*,*(&arr + 1)退化为指向原数组末尾之后的int*,两者相减就直接得到了数组的元素个数6。
举个更直观的例子:假设sizeof(int)是4字节,原数组arr占用的内存是0x100到0x117(总共24字节):
&arr的值是0x100(类型是数组指针)&arr + 1的值是0x100 + 24 = 0x118*(&arr +1)退化为0x118的int*指针arr退化为0x100的int*指针- 相减计算:
(0x118 - 0x100)/4 = 24/4 = 6,正好是元素个数。
小提醒:这个方法只对编译期大小确定的静态数组有效,如果是
new int[6]这种动态分配的数组,arr本质是int*,&arr就是指向指针的指针,这个技巧就用不了了。
内容的提问来源于stack exchange,提问作者Anujeet Kunturkar




