根据帖子,
Passing a 2D array to a C++ function
int array[10][10];
void passFunc(int a[][10]) // <---Notice 10 here
{
// ...
}
passFunc(array);
为什么编译器内部的观点要求这个更高的维度。
答案 0 :(得分:4)
另一种解释(数组到指针衰减):
我们假设我们有一维数组,我们就这样使用它:
int array[10];
int i = array[3];
编译器必须知道在哪里找array[3]
。它知道它需要跳过3 int
s才能到达array[3]
中的那个。int array[2][5];
int i = array[1][1];
。所以它有效。
但是如果我们有一个二维数组,
i
要在此处获取int
,编译器需要跳过多少int
个?它需要跳过整行,再加上一行。跳过一个很容易,因为我们知道一个int array[2][2][2];
int i = array[1][1][1];
的大小。但是我们还需要知道数组中行的大小 - 行的大小取决于类型的大小*每行的列数。这是查看它的一种方式,这解释了为什么你需要后一个维度。
让它成为一个小小的脑筋急转弯,将其进一步推向
int
让我们调用尺寸 X,Y,Z 。
在这里,我们可以说我们有一个有限的3D空间int
s。单位当然是一int
的大小。行数由 Y 定义,平面数由 Z 定义。这就是 X 作为基本单位,正如我们所说的那样,大小为int
。三者的结合产生了一个&#34;点。&#34;
为了能够到达3D空间中的任何一点,我们需要知道每个维度在哪里停止&#34;而下一个开始。所以我们需要:
int
)的尺寸,用于遍历 X 尺寸再次, X 已经提供给我们,因为我们正在使用[]
。但我们不知道每架飞机的大小,也不知道有多少架飞机。所以我们需要指定除第一维之外的所有维度。这是一般规则。
这也解释了为什么这个问题比仅仅指针衰减更精细的解释,因为一旦你达到2个以上的维度,你仍然需要知道它是如何工作的。
换句话说,您需要整体大小(维度的乘积)不溢出,并且您需要每个大小的维度才能使用连续的<div class="container">
<img src="http://bushbyre.e1.siteloft.com/wp-content/uploads/2015/10/Tamar_ST_MAP.jpg" class="park-img" />
<img src="http://anspachmedia.com/wp-content/uploads/2015/08/full-circle.png" class="icon" />
<img src="http://anspachmedia.com/wp-content/uploads/2015/08/full-circle.png" class="icon2" />
</div>
索引。
答案 1 :(得分:3)
C / C ++中的数组是一种类型,但不是第一类对象,它们在传递给函数时“衰减”为指向第一个元素的指针。
int[10][10]
是一个包含10个int[10]
数组的数组......函数声明:
void foo(int x[][10]);
typedef int IntArray10[10];
void bar(IntArray10 *x);
是编译器完全相同的。
当将2d数组传递给函数时,您将传递指向第一个元素的指针(并忽略第一个维度),但元素本身是一个数组,编译器需要知道它的大小。
答案 2 :(得分:3)
与参数int a[][10]
中的“[]”相反,该函数不采用二维数组,而是指向一维数组的指针 - 其原型相当于
void passFunc(int (*a)[10])
array
可以衰减成指向其第一个元素的指针,就像所有数组一样
像往常一样,该指针是&array[0]
,在这种情况下,它是指向具有10 int
s - int (*)[10]
的数组的指针。
所以不是你需要指定“更高维度”,而是参数是指向十个元素的数组而不是二维数组的指针。
(你不能让a
成为指向未指定大小数组的指针,因为编译器需要知道a[1]
相对于a[0]
的位置,即它需要知道sizeof(*a)
。)
答案 3 :(得分:0)
这是必需的,因为在C中不存在多维数组的概念 我们可以定义任何数组,甚至是另一个数组。最后一个可以看作是一个多维数组 现在将二维数组视为:
int arrray[5][4];
这被解释为一个包含5个元素的数组,每个元素都是4 int
的数组
在内存中,布局是顺序的:首先是第一个数组的4个元素,然后是第二个元素,依此类推,直到5个元素的第5个数组。
要访问第3个数组array[2][1]
的第2个元素,编译器必须跳过前2个数组,但这样做需要知道要跳过多少个元素。
即在数学上,第三个数组的第二个元素的地址是:
//pElement2Array3 points the 2nd element of the 3rd array.
//Note that 4 is the number of elements of the base dimension
int *pElement2Array3 = &array[0] + (2 * 4) + 1;
(注意:术语(2 * 4) + 1
不会乘以sizeof(int)
,因为这是通过指针算法自动完成的。)
上面的数学运算由编译器在使用寻址array[2][1]
,时自动执行,但要执行它,编译器必须知道基本数组中有多少个元素(可能是数组数组的数组)。 ..)强>
答案 4 :(得分:0)
简单地说,因为多维数组从右到左“增长”。可以这样想:
int arr [a];
是一个a
整数数组。
int arr [b][a]
是一组b
个a
整数数组。
等等。
为什么在将数组传递给函数时可以省略最左边的维度,这是因为“数组衰减”。 6.7.6.3/7说:
参数声明为''数组类型''应调整为 ''指向类型''的合格指针
也就是说,如果你将一个函数参数声明为int param[10]
或int param[]
,它会被编译器静默/不可见地替换为指向int:int* param
的指针,它指向数组的第一个元素。数组本身仍然由调用者分配。
这样做是为了防止数组按值传递给函数,这样效果非常低,在大多数情况下没有任何意义。
现在对于多维数组的情况,适用上述相同的规则。所以,如果你有int param[10][10]
,它会衰变为指向第一个元素的指针。第一个元素是一个包含10个整数的数组,因此你可以将一个数组指针输入到10个整数的数组中:int (*param)[10]
。
如果你有int param[][10]
就会发生同样的情况,你仍会得到int (*param)[10]
。所以最左边的维度可以是任何东西 - 无论如何它都无关紧要。
但是最左边的其他维度是必需的,否则编译器将不知道阵列将衰减到哪个指针类型。在函数声明的特殊情况之外,没有int(*param)[]
这样的东西,这意味着“指向未知大小的数组的数组指针”。
答案 5 :(得分:-1)
函数参数int a[][10]
相当于int (*a)[10]
,表示: a
是指向10 int
数组的指针。在这种情况下,它不代表2D阵列。
如果较高的维度留空,则编译器无法知道指针a
指向的数组的长度,并且无法执行指针运算。