有人可以向我解释为什么技术上2D阵列实际上不会衰减到int**
,而当你有一个单维数组时,你会把指针衰减到int*
(如果你有{{1}的数组{1}})。
我理解指针衰减是什么,但我不知道为什么2D数组不会出现这种衰变?
对于刚接触C或C ++的人来说,这是一个常见的混淆,但我发现自己也常常绊倒它。
答案 0 :(得分:6)
他们有不同的内存布局。 2D数组是一个连续的内存,而int**
是一个指针数组。对于2D数组,位置的偏移量计算为rownum * collength + colnum
(反之亦然,具体取决于标记行/列的方式)。这不适用于int**
,它实际上产生两个内存读取;第一个获取列指针,然后读取与该存储器偏移的数据。
顺便提一下,这种不同的布局是必须在接受2D数组的函数中声明数组维度(除了最左边)之外的原因;否则编译器无法生成计算偏移量的代码。
以下是对int**
的内存布局图片的尝试。左列是一个连续的指针数组,其中每个指针都包含一个连续内存和数据的地址。请注意,每列中的数据长度不必相同(尽管对于代码可读性而言可能不一定是好事):
int **array;
int i, j;
int cntr = 1;
array = malloc( 3 * sizeof( int* ));
for ( i = 0; i < 3; i++ ) {
array[i] = malloc( 4 * sizeof( int ));
for ( j = 0; j < 4; j++ )
array[i][j] = cntr++;
}
给出这样的东西:
array ==> |addr1| ==> [1,2,3,4]
|addr2| ==> [5,6,7,8]
|addr3| ==> [9,10,11,12]
相比之下,这就是int[3][4]
的布局。括号只显示每列数据的逻辑中断。整数值在内存中是连续的:
int array[3][4];
int i, j;
int cntr = 1;
for ( i = 0; i < 3; i++ )
for ( j = 0; j < 4; j++ )
array[i][j] = cntr++;
给出这样的东西:
array ==> [1,2,3,4][5,6,7,8][9,10,11,12]
答案 1 :(得分:4)
模式是“N元素数组T
”类型的表达式将转换为“指向T
的指针”类型的表达式。如果T
是一个数组类型,那么你最终会得到一个指向数组的指针。给出像
T arr[M][N];
表达式arr
具有“T
的N元素数组的M元素数组”。除非它是sizeof
,_Alignof
或一元&
运算符的操作数,否则它将转换为类型为“指向{{1}的N元素数组的指针”的表达式}“或T
。
如果有疑问,请写出英文类型,例如“{元素数组的五元素数组的六元素数组T (*)[N]
”,然后替换第一个“n元素数组”使用“指向”指针,给出“指向int
的6元素数组的5元素数组的指针”:
int
答案 2 :(得分:3)
将二维数组转换为指向其第一个元素的指针的结果是指针,而不是数组。由于它不是数组,因此不会进一步转换。
答案 3 :(得分:2)
它确实腐烂了。类型为“T的数组”的表达式衰减为指向其第一个元素的指针。对于T
的二维数组,第一个元素的类型数组为T
。所以:
int arr[5];
在大多数情况下,arr
都有“指向int
”的类型。现在将相同的规则应用于二维数组:
int arr2[5][5];
此处,arr2
具有类型“指向5 int
数组的指针”。请注意,此对象的类型为不“T
数组”,因此它不会进一步衰减。
答案 4 :(得分:1)
如果int* i
== int i[5]
而不是int** i
== int i[5][5]
,那么人们常常会认为这有两个原因。首先,int**
是pointer to a pointer并且与数组的布局方式无关,其次,2D数组实际上是内部的1D数组,它的作用是将第二个数组并排放置。 / p>
这意味着在[2][2]
数组内部正在创建一个[4]
数组,当您尝试访问[0][0]
时,该数组会被转换为[0]
,{{ 1}}将被翻译为[0][1]
,[1]
将被翻译为[1][0]
,[2]
将被翻译为[1][1]
示例:
[3]
这将打印125,因为我将#include <iostream>
void Print(int* i, int element)
{
std::cout << i[element] << std::endl;
}
int main()
{
int i[5][5];
i[2][2] = 125;
Print((i[0]), 12);
}
设置为125并且将被视为等于[2][2]
,因为第一个12
将占用0 - 4,[0]
将占据5-10,依此类推。
答案 5 :(得分:1)
二维数组是数组的数组。
在大多数情况下,“T
数组”转换为“指向T
的指针,因此”T[N]
数组“将转换为”指向{的指针{1}}”。
由于
的内存表示T[N]
与
完全不同int arr[M][N];
int **dptr = malloc(M*sizeof *dptr);
for(int i = 0; i < M; ++i) {
dptr[i] = malloc(N*sizeof *dptr[i]);
甚至无法转换为int[M][N]
。
答案 6 :(得分:-1)
2D数组是一个连续的内存块。当它作为2D数组访问时,您需要行长度从列跳到列。指向指针的指针就是这样。如果第一个指针是指向第二维数组的指针数组,它可以模拟2D数组,但它与2D数组的连续内存块是完全不同的野兽。