访问2D阵列时到底发生了什么

Mic*_*gan 2 c c++

我已经编写了很长一段时间,但只是意识到我对一个非常基本的操作的混淆可能会混淆.

int array[10][10];

array[1][1] = 0;
Run Code Online (Sandbox Code Playgroud)

这样就足够了 - 数组地址+(10*1 + 1)*sizeof(int)被赋值为0.

但是在做动态数组的时候呢?

int **array;

// malloc/new the base array of pointers - say 10 as above.
array = malloc(10 * sizeof(int *));

// through pointers and alloc each with ints - again 10 per row as above.
for(int i=0; i<10; i++) 
    array[i] = malloc(10 * sizeof(int);

array[1][1] = 0;
Run Code Online (Sandbox Code Playgroud)

在此示例中,编译器必须引用数组第一层上的数组以获取第二个指针以获取内存.同样,这个过程是直截了当的.

我的问题是:编译器如何知道内存是连续的,因此在第一个例子中它只能做简单的数学而不是引用,而不是第二个?

如果答案是:因为编译器事先知道数组的大小,所以就是这样,但有没有办法告诉编译器动态数组是单个分配,因此它可以做更简单的数学而不是额外的deref和额外的内存碎片分配?或者这是否需要VLA支持才能按照此帖发布,如下所示:

double (*A)[n] = malloc(sizeof(double[n][n]));
Run Code Online (Sandbox Code Playgroud)

另一个网站也列出了这种可能性:

int r=3, c=4;
int **arr;

arr  = (int **)malloc(sizeof(int *) * r);
arr[0] = (int *)malloc(sizeof(int) * c * r);
Run Code Online (Sandbox Code Playgroud)

这真让我想知道编译器如何解决问题,或者这只是使用VLA支持的另一种方式.

对于C++,有增强和嵌套向量,但它们甚至比上面更重,所以我会尽可能避免使用它们.


更新

老实说,我在这里要做的就是编译我的上面的例子,并对汇编器输出做一些看法.那将很快回答我的所有问题.我的误解是我假设所有n-dim数组访问都是通过数学运算来完成的,类似于编译时已知数组的完成方式.我没有意识到[] []正在执行双重任务,因为**array在动态分配的每个解除引用之间进行适当的索引,而对于编译时已知类型执行[i*dim + j].动态2+维度阵列不是我曾经做过的事情.

Pau*_*aul 5

类型int **int[10][10]不一样.

该类型int **不包含有关有多少元素的任何信息,因为它不是数组类型,它是指针类型(特别是指向a的指针int *).int[10][10]包含编译器需要知道有多少元素的所有信息.

如果你尝试使用sizeof指针和数组,你会注意到这一点.以下程序演示了这一点:

#include <stdio.h>                                                             

int main ( int argc, char * argv[] ) { 

    printf( "Size of int[10][10]: %lu\n", sizeof(int[10][10]) );
    printf( "Size of int**: %lu\n", sizeof(int**) );

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

动态内存不是在编译时分配的,它是在运行时编译的,因此编译器改变动态内存的创建方式,最终可能会修改程序的行为(IE.通过分配超过可用的内容)一个连续的块,并且malloc返回null).

当然,你可以通过为内存分配足够的内存来获得连续的内存块100 ints,然后自己进行算术运算:

int * mem = malloc( 10 * 10 * sizeof( int ) );
Run Code Online (Sandbox Code Playgroud)

现在mem是一个100个整数的连续块

int * array[10];
for ( int i = 0; i < 10; i++ )
    array[i] = &mem[10*i];
Run Code Online (Sandbox Code Playgroud)

现在你有一个10 int *秒的数组,可以用来索引到mem,就像之前一样(这个数组是静态分配的,但如果你想从这个函数返回它,你会想要动态地分配它).