C++中多维数组与指针的地址及值相关疑问
int main() { int A[2][2][2] = { {{1, 2}, {3, 4}}, {{4, 5}, {5, 6}} }; cout << A << endl; // 假设输出为400 cout << *A << endl; // 400 cout << **A << endl; // 400 cout << ***A << endl; // 1 cout << &A[0][1] << endl; // 408 }
疑问
数组与指针有诸多相似特性,我认为A是指向二维int数组的指针,指向地址400,解引用一次得到指向一维数组的指针仍指向400。现存在两个疑问:
- 普通指针解引用会得到指向地址存储的值,但多维数组并非如此?地址400存储的值是1,但A、*A、**A都输出400。
- 对于最后一行cout,A[0][1]是指向int的指针,解引用后得到地址408处的值3;但& A[0][1]输出408,该地址存储的是int值3,为何看起来像是存储指针类型?希望得到相关原理的解释。
原理解释
问题1:多维数组名的隐式转换逻辑
C++中数组名在绝大多数语境下会隐式转换为指向数组首元素的指针,但数组本身和指针并非同一事物,这点在多维数组中表现得更清晰:
A是int[2][2][2]类型的三维数组,用cout输出时,它会自动转换成指向其首元素的指针(类型为int(*)[2][2],即指向二维数组的指针),指向的地址是数组首元素的起始地址400,因此输出400。- 解引用
*A得到的是A的首元素,也就是int[2][2]类型的二维数组。这个二维数组名同样会隐式转换为指向其首元素的指针(类型为int(*)[2],即指向一维数组的指针),而该一维数组的起始地址同样是400,所以输出还是400。 - 再解引用
**A得到的是二维数组的首元素,也就是int[2]类型的一维数组。这个一维数组名又会自动转换成指向其首元素的指针(类型为int*),指向的起始地址依旧是400,因此输出400。 - 只有
***A是对指向int的指针做解引用,直接取出地址400处存储的int值1,所以输出1。
普通指针解引用是直接取指向地址的内容,但多维数组的每一层解引用得到的还是数组类型,而数组名又会自动转成指针,因此才会出现多次解引用后输出地址的情况,本质和普通指针逻辑一致,只是多了数组到指针的隐式转换步骤。
问题2:&A[0][1]的类型与地址含义
首先纠正一个误解:A[0][1]不是指针,它是int[2]类型的一维数组。
A[0]是三维数组的第一个元素(int[2][2]类型的二维数组),A[0][1]是这个二维数组的第二个元素(int[2]类型的一维数组),它的起始地址是408(因为A[0][0]包含两个int,占8字节,400+8=408)。- 取
&A[0][1]得到的是指向这个一维数组的指针(类型为int(*)[2])。cout输出指针时只会打印其存储的地址值,也就是该一维数组的起始地址408,和这个地址里存储的int值3没有关系——指针的地址值就是它指向对象的起始位置,不管对象是int还是数组。
你觉得“像是存储指针类型”是混淆了指针的地址值和它指向的内容:&A[0][1]本身是一个指针,它的值是408,而408这个地址里存储的是int[2]数组的第一个元素3,两者是完全不同的概念。
内容的提问来源于stack exchange,提问作者AZYZ
相关产品推荐
相关产品推荐

