C++ 为什么我们不';传递动态2d数组时不需要列数?
假设我有两个数组,并将它们传递给一个函数:C++ 为什么我们不';传递动态2d数组时不需要列数?,c++,c,arrays,C++,C,Arrays,假设我有两个数组,并将它们传递给一个函数: void func(int arr1[][4], int **arr2) { // <- I need to give n in only one, why? ... } int main() { int n = 5, m = 4; int arr1[n][m]; int **arr2 = (int**)malloc(n * sizeof(int*)); for(int i = 0;i < n;i++)
void func(int arr1[][4], int **arr2) { // <- I need to give n in only one, why?
...
}
int main() {
int n = 5, m = 4;
int arr1[n][m];
int **arr2 = (int**)malloc(n * sizeof(int*));
for(int i = 0;i < n;i++)
arr2[i] = (int*)malloc(m * sizeof(int));
func(arr1, arr2);
return 0;
}
void func(int arr1[][4],int**arr2){/实际上恰恰相反,您只能省略其中一个索引(在多维数组的情况下),即最里面的索引
这是因为,数组作为函数参数传递时,会衰减为指向第一个元素的指针。引用C11
,第§6.3.2.1章
除非它是sizeof
运算符、\u
运算符或
一元&
运算符,或是用于初始化数组的字符串文字,一个具有
类型“”的数组已转换为类型为“”指针指向类型“”的表达式
数组对象的初始元素,并且不是左值。[…]
因此,像
void func(int arr1[][5], int **arr2) //an array of array of 5 ints
及
是等效的。实际上恰恰相反,您只能省略其中一个索引(在多维数组的情况下),即最里面的索引
这是因为,数组作为函数参数传递时,会衰减为指向第一个元素的指针。引用C11
,第§6.3.2.1章
除非它是sizeof
运算符、\u
运算符或
一元&
运算符,或是用于初始化数组的字符串文字,一个具有
类型“”的数组已转换为类型为“”指针指向类型“”的表达式
数组对象的初始元素,并且不是左值。[…]
因此,像
void func(int arr1[][5], int **arr2) //an array of array of 5 ints
及
是等效的。实际情况与您所说的相反:您不必传递行数。假设数组索引的工作方式如下:
int arr[MAX_ROW][MAX_COL]; /* with both 3 */
col
--------------->
| 0,0 0,1 0,2
row | 1,0 1,1 1,2
V 2,0 2,1 2,2
当您传递int arr[][MAX\u COL]
时,编译器知道下一行将从哪里开始,例如,当您处理arr[row][COL]
这样的地址时
如果您使用指针手动执行此操作,它看起来像:&arr[0][0]+行*MAX\u COL+COL
。在该示例中,您还必须知道数组的列大小MAX\u COL
,以计算下一行
原因是,数组在内存中是连续的。上面的数组在内存中表示为:
| row = 0 | row = 1 | row = 2 |
| 0,0 0,1 0,2 | 1,0 1,1 1,2 | 2,0 2,1 2,2 |
编译器还必须知道行偏移量,因为当您将声明为int arr[MAX_SIZE]
的数组传递给函数void foo(int arr[])
时,它会衰减为指向数组开头的指针int*arr
。对于数组(2D数组)的情况,它也会衰减为指向其第一个元素的指针,即指向单个数组的指针int(*arr)[MAX\u COL]
简而言之:使用int arr[][MAX_COL]
编译器拥有使用arr[row][COL]
对数组进行寻址所需的所有信息。实际上,与您所说的情况相反:您不必传递行数。假设数组索引是这样工作的:
int arr[MAX_ROW][MAX_COL]; /* with both 3 */
col
--------------->
| 0,0 0,1 0,2
row | 1,0 1,1 1,2
V 2,0 2,1 2,2
当您传递int arr[][MAX\u COL]
时,编译器知道下一行将从哪里开始,例如,当您处理arr[row][COL]
这样的地址时
如果您使用指针手动执行此操作,它看起来像:&arr[0][0]+行*MAX\u COL+COL
。在该示例中,您还必须知道数组的列大小MAX\u COL
,以计算下一行
原因是,数组在内存中是连续的。上面的数组在内存中表示为:
| row = 0 | row = 1 | row = 2 |
| 0,0 0,1 0,2 | 1,0 1,1 1,2 | 2,0 2,1 2,2 |
编译器还必须知道行偏移量,因为当您将声明为int arr[MAX_SIZE]
的数组传递给函数void foo(int arr[])
时,它会衰减为指向数组开头的指针int*arr
。对于数组(2D数组)的情况,它也会衰减为指向其第一个元素的指针,即指向单个数组的指针int(*arr)[MAX\u COL]
简而言之:使用int arr[][MAX_COL]
编译器拥有使用arr[row][COL]
对数组进行寻址所需的所有信息。实际上,您只有一个int数组(即int arr1[][5]
)和一个指向int指针的指针,即int**arr2
。即使像arr1[10]这样的数组[5]
,当作为参数传递给函数时,会衰减为指向元素所在内存开头的指针,内存布局和编译器处理这些指针访问的方式存在(很大)差异
顺便说一句,它主要应该是intn=5,m=4;intarr1[m][n]
,而不是intn=5,m=4;intarr1[n][m]
关于内存布局:
格式为int[10][5]
的二维整数数组表示为10个连续的“行”,每个行由5个“列”(即整数值)组成。该数组的大小为10*5*sizeof(int)
,一个“行”的大小为5*sizeof(int)
指向intint**p
的指针只是一个指针;它的大小是sizeof(int**)
,即使你有一系列完整的指针lilep=malloc(10*sizeof(int*))
;注意sizeof(int*)中的“*”
,当你创建一个指向整数的指针序列,而不是一个整数序列时。这是内存布局的主要区别:它不是一个二维整数数组,而是一个指向整数的一维指针数组。如果你真的为“10”分配了10行整数,每行可以位于内存的不同部分。管理10x5整型值的(扩展)量所需的空间为“10*sizeof(int*)+10*5*sizeof(int)”
关于访问:
让我们假设一个int arr[][5]
类型的变量,它是一个二维整数数组,其中