栈上数组内存存储疑问:变量地址与值为何完全一致?
栈上数组与动态数组的地址差异解析
栈上数组的地址特性
在栈上创建数组时,以下三个地址值完全相等:
- 栈上数组变量自身的地址(
&automaticArray) - 数组变量的值(隐式转换后的指针,
automaticArray) - 数组首元素的地址(
&automaticArray[0])
栈上创建类型为T、大小为N的数组时,栈中直接分配sizeof(T)*N字节的连续空间存储数组元素,并没有额外存储指向数组的指针。示例代码:
#include <bits/stdc++.h> using namespace std; int main() { int automaticArray[5] {1, 2, 3, 4, 5}; cout << "变量值 = " << automaticArray << ", 变量地址 = " << &automaticArray << ", 首元素地址 = " << &automaticArray[0] << endl; }
输出中三个地址完全一致的核心原因:数组变量automaticArray是数组类型的标识符,当它被当作指针使用时(比如输出到cout),会自动隐式转换为指向数组首元素的指针;而&automaticArray取的是数组变量的地址,由于数组本身就直接存储在栈的这个地址上,所以它和首元素的地址完全重合——数组的起始地址就是它自身的地址,也是首元素的地址。
动态数组的地址特性
在动态内存(堆)中创建数组时,栈上仅存储一个8字节的指针变量(64位系统下),这个指针指向堆中实际的数组空间。因此:
- 栈上指针变量的地址(
&dynamicArray)是栈中的位置 - 指针变量的值(
dynamicArray)是堆中数组的起始地址 - 数组首元素的地址(
&dynamicArray[0])等于指针变量的值,即堆中数组的起始地址
此时栈上变量的地址和另外两个值必然不同。示例代码:
#include <bits/stdc++.h> using namespace std; int main() { int* dynamicArray = new int[5] {0}; cout << "变量值 = " << dynamicArray << ", 变量地址 = " << &dynamicArray << ", 首元素地址 = " << &dynamicArray[0] << endl; }
疑问解答:栈上数组不存在额外存储的指针
以int数组为例,栈上数组的前8字节并没有同时存储指针和元素——因为根本不存在这个额外的指针:
- 数组变量
automaticArray不是指针变量,它是数组类型的实例。当你使用automaticArray时,编译器会自动将其转换为指向首元素的指针,但这个指针是编译期临时生成的语义,并非在栈上实际存储了一个8字节的指针值。 - 栈上只有数组的5个int元素(共20字节),
&automaticArray就是这个20字节空间的起始地址,和&automaticArray[0]完全一致,因为首元素就位于这个空间的起始位置。
查看汇编代码可以更直观验证:栈上数组的初始化是直接将元素值写入栈的连续地址,没有任何存储指针的指令;而动态数组则会先调用operator new分配堆空间,再将返回的地址存入栈上的指针变量中。
内容的提问来源于stack exchange,提问作者Bychkov Arthur
相关产品推荐
相关产品推荐

