为什么需要多维阵列中更高尺寸的尺寸范围?

时间:2016-02-09 10:46:01

标签: c++ c

根据帖子,

Passing a 2D array to a C++ function

int array[10][10];
void passFunc(int a[][10]) //  <---Notice 10 here
{
    // ...
}
passFunc(array);

为什么编译器内部的观点要求这个更高的维度。

6 个答案:

答案 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;而下一个开始。所以我们需要:

  1. 单位(int)的尺寸,用于遍历 X 尺寸
  2. 每个平面的尺寸( Y ),以遍历 Y 尺寸
  3. 要遍历 Z 尺寸的平面数
  4. 再次, 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]是一组ba整数数组。

等等。

为什么在将数组传递给函数时可以省略最左边的维度,这是因为“数组衰减”。 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指向的数组的长度,并且无法执行指针运算。