C++ 为什么多维数组中需要更高维度的维度范围?

C++ 为什么多维数组中需要更高维度的维度范围?,c++,c,C++,C,据邮报报道, int数组[10][10]; void passFunc(int a[][10])/作为函数参数int a[][10]相当于int(*a)[10],意思是:a是指向10int数组的指针。在本例中,它不表示二维数组 如果较高维度留空,则编译器不可能知道指针a指向的数组长度,并且无法执行指针算术 C/C++中的数组是一种类型,但不是一级对象,它们在传递给函数时“衰减”为指向第一个元素的指针 int[10][10]是由10个int[10]数组组成的数组。。。函数声明: void foo

据邮报报道,

int数组[10][10];

void passFunc(int a[][10])/作为函数参数
int a[][10]
相当于
int(*a)[10]
,意思是:
a
是指向10
int
数组的指针。在本例中,它不表示二维数组


如果较高维度留空,则编译器不可能知道指针
a
指向的数组长度,并且无法执行指针算术

C/C++中的数组是一种类型,但不是一级对象,它们在传递给函数时“衰减”为指向第一个元素的指针

int[10][10]
是由10个
int[10]
数组组成的数组。。。函数声明:

void foo(int x[][10]);

typedef int IntArray10[10];
void bar(IntArray10 *x);
对于编译器,它们是相同的


因此,将2d数组传递给函数时,您传递的是指向第一个元素的指针(忽略第一个维度),但元素本身是数组,编译器需要知道其大小。

另一种解释(数组到指针衰减):

假设我们有一个一维数组,我们这样使用它:

int array[10];
int i = array[3];
编译器必须知道在哪里可以找到
数组[3]
。它知道需要跳过3个
int
s才能到达
array[3]
中的一个。所以它起作用了

但如果我们有一个二维数组

int array[2][5];
int i = array[1][1];
要在此处获取
i
,编译器需要跳过多少
int
s?它需要跳过整行,再加上一行。跳过一个很容易,因为我们知道一个
int
的大小。但是我们还需要知道数组中行的大小,行的大小由类型的大小*每行的列数决定。这是一种看待它的方式,这解释了为什么需要后一个维度

让我们把它作为一个小小的脑筋急转弯,从一个维度进一步,到另一个维度

int array[2][2][2];
int i = array[1][1][1];
让我们把尺寸称为X,Y,Z

在这里,我们可以说我们有一个有限的三维空间
int
s。这个单位当然是一个
int
的大小。行的数量由Y定义,平面的数量由Z定义。这使得X成为基本单位,正如我们所说的,它的大小是1
int
。三者的结合产生一个“点”

为了能够到达3D空间中的任何点,我们需要知道每个维度“停止”和下一个维度开始的位置。因此,我们需要:

  • 用于遍历X维度的单位大小(
    int
  • 每个平面(Y)的大小,以遍历Y标注
  • 要遍历Z标注的平面数
  • 同样,X已经给了我们,因为我们使用的是
    int
    。但我们不知道每架飞机的大小,也不知道有多少架飞机。因此,我们需要指定除第一个维度以外的所有维度。这是一般规律

    这也解释了为什么这个问题需要比指针衰减更详细的解释,因为一旦你达到2维以上,你仍然需要知道它是如何工作的。
    换句话说,您需要总大小(维度的乘积)不溢出,并且需要每个大小的维度能够使用连续的
    []
    索引。

    这是必需的,因为在C中不存在多维数组的概念。
    我们可以定义任何东西的数组,甚至是另一个数组。最后一个可以看作是多维数组。
    现在考虑一个二维数组:

    int arrray[5][4];
    
    这将被解释为5个元素的数组,每个元素是4个
    int
    的数组
    在内存中,布局是顺序的:首先是第一个数组的4个元素,然后是第二个,依此类推,直到第五个数组的4个元素。
    要访问第三个数组的第二个元素
    数组[2][1]
    编译器必须跳过前两个数组,但要这样做,需要知道要跳过多少个元素
    即,从数学上讲,第三个数组的第二个元素的地址为:

    //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)
    ,因为这是通过指针算法自动完成的。)

    当使用寻址
    数组[2][1]
    时,编译器会自动执行上面的数学运算,但要执行它,编译器必须知道基数组中有多少元素(可能是数组的数组…

    ,这与参数
    int a[]中的“[]”相反
    ,该函数不接受二维数组,而是指向一维数组的指针-其原型与

    void passFunc(int (*a)[10])
    
    与所有数组一样,
    array
    可以衰减为指向其第一个元素的指针。
    与往常一样,该指针是
    &数组[0]
    ,在本例中,它是指向具有十个
    int
    s的数组的指针,即
    int(*)[10]

    因此,您不需要指定“更高的维度”,而是参数是指向十个元素的数组的指针,而不是二维数组


    (您不能让
    a
    成为指向未指定大小数组的指针,因为编译器需要知道
    a[1]
    相对于
    a[0]
    的位置,也就是说,它需要知道
    sizeof(*a)

    简单地说,因为多维数组从右向左“增长”。你可以这样想:

    int array[10];
    int i = array[3];
    
    int-arr[a]
    a
    整数的数组

    int-arr[b][a]
    是一个
    b
    整数数组

    等等

    至于为什么在将数组传递给函数时可以省略最左边的维度,这是因为“数组衰减”。6.7.6.3/7规定:

    作为“类型数组”的参数声明应调整为 “指向类型的限定指针”

    也就是说,如果将函数参数声明为
    int param[