简体   繁体   English

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

[英]What exactly happens when accessing a 2D array

I've been coding for quite a while, but just realized that my interperation of a very elementary operation may be confused. 我已经编码了一段时间了,但是才意识到我对一个非常基本的操作的困惑可能会引起混淆。

int array[10][10];

array[1][1] = 0;

This is sample enough - address of array + (10 * 1 + 1) * sizeof(int) is assigned 0. 这足够样本-数组+(10 * 1 + 1)* sizeof(int)的地址分配为0。

But what about when doing dynamic arrays? 但是,当进行动态数组时呢?

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;

In this example, the compiler has to reference an array on the first layer of the array to get to the second pointer to get to memory. 在此示例中,编译器必须引用数组第一层上的数组才能到达第二个指针才能到达内存。 Again, this process is straight forward. 同样,此过程很简单。

My question here is: How does the compiler know that memory is contiguous and therefore it can just do simple math instead of a reference in the first example, but not the second? 我的问题是:编译器如何知道内存是连续的,因此它只能执行简单的数学运算,而不是第一个示例中的引用,而不能在第二个示例中进行引用?

If the answer is: because the compiler knows the size of the array beforehand, so be it, but is there a way to tell the compiler that the dynamic array is a single allocation and therefore it can do the simpler math instead of the extra deref and extra memory fragmenting allocations? 如果答案是:因为编译器事先知道了数组的大小,那么就可以了,但是有一种方法可以告诉编译器动态数组是单个分配,因此它可以执行更简单的数学运算而不是额外的deref和额外的内存碎片分配? Or does this require VLA support to get right as per this post which goes like: 或者,这是否需要VLA支持,以得到正确的按照这个职位它是这样:

double (*A)[n] = malloc(sizeof(double[n][n]));

Another website listed this as a possibility as well: 另一个网站也列出了这种可能性:

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

arr  = (int **)malloc(sizeof(int *) * r);
arr[0] = (int *)malloc(sizeof(int) * c * r);

Which really got me wondering about how the compiler is figuring things out, or if this is just another way of using VLA support. 真正让我想知道编译器如何解决问题,或者这是否只是使用VLA支持的另一种方式。

For C++, there is boost and nested vectors, but they are even heavier than the above so again, I would avoid those if possible. 对于C ++,有boost和nested向量,但是它们甚至比上面的还要重,因此,如果可能的话,我会避免使用它们。


Update 更新

Honestly, what I should do here is just compile my above examples and take a gander at the assembler output. 老实说,我在这里应该做的只是编译上面的示例,并在汇编输出中轻描淡写。 That would answer all my questions in no time at all. 那将立即回答我所有的问题。 My misconception was that I assumed that all n-dim array access was done just by doing math similiar to how it is done with compile time known arrays. 我的误解是,我假设所有n维数组访问都是通过与在编译时已知的数组中进行数学运算类似的方式完成的。 I did not realize that [][] was doing double duty as **array with appropriate indexing between each dereference for dynamic allocs, while doing [i*dim+j] for compile time known types. 我没有意识到[] []作为**array ,在对动态分配的每个取消引用之间都进行了适当的索引编制,而对[i * dim + j]进行了双重处理,而对编译时已知的类型却做了相应的索引。 Dynamic 2+ Dimension arrays is just not something I ever have had to do. 动态2维数组不是我必须要做的事情。

The types int ** and int[10][10] are not the same. int **int[10][10]的类型不同。

The type int ** doesn't contain any information about how many elements there are, because it is not an array type, it is a pointer type (specifically a pointer to an int * ). int **类型不包含有关有多少个元素的任何信息,因为它不是数组类型,而是指针类型(特别是指向int *的指针)。 int[10][10] contains all the information the compiler needs to know how many elements there are. int[10][10]包含编译器需要知道所有元素的所有信息。

You'll notice this if you try using sizeof on a pointer vs an array. 如果您尝试在指针vs数组上使用sizeof ,则会注意到这一点。 The following program demonstrates this: 下面的程序演示了这一点:

#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;
}

Dynamic memory isn't allocated at compile time, it is compiled at run-time, so a compiler changing the way the dynamic memory is created, could end up modifying the behaviour of your program, (IE. by allocating more than is available in a contiguous block, and having malloc return null). 动态内存不是在编译时分配的,而是在运行时编译的,因此,更改动态内存创建方式的编译器最终可能会修改程序的行为(即,通过分配比一个连续的块,并且malloc返回null)。

You can get a contiguous block of memory yourself of course, by allocating enough memory for 100 ints , and then doing the arithmatic yourself: 当然,您可以为100 ints分配足够的内存,然后自己进行算术运算,从而获得连续的内存块:

int * mem = malloc( 10 * 10 * sizeof( int ) );

Now mem is a contiguous block of 100 ints 现在mem是100个整数的连续块

int * array[10];
for ( int i = 0; i < 10; i++ )
    array[i] = &mem[10*i];

Now you have an array of 10 int * s that can be used to index into mem, just like before (this array is allocated statically, but if you wanted to return it from this function you would want to allocate it dynamically instead). 现在,您有一个10 int * s的数组,可以像以前一样用于索引到mem(此数组是静态分配的,但是如果要从此函数返回它,则需要动态分配它)。

Because the types are completely different. 因为类型完全不同。

In the first case, the type in an array with two dimensions, and the length of each dimension is known, so the address can be computed directly, and referenced once. 在第一种情况下,具有二维的数组中的类型以及每个维度的长度是已知的,因此可以直接计算地址,并引用一次。

In the second case, the type is completely different, the type is a double pointer. 在第二种情况下,类型完全不同,类型是双指针。 A pointer to an array of pointers to some type, in your case, an int . 指向某种类型的指针的数组的指针,在您的情况下为int

All that the compiler knows is that array is a pointer to an array, of some unknown size, of pointers to int . 编译器只知道array是一个指向array的指针,该数组的大小未知,指向int的指针。 array is a array是一个

int **array;

And array[x] is a pointer to an int. 并且array[x]是一个指向int的指针。 Note that it's just a pointer to an int . 注意,它只是一个指向int的指针。 It says nothing about how many int s it's pointing to. 它没有指出它要指向多少个int

It can just be a single int , or it may not. 它可以只是一个int ,也可以不是。 And each pointer to an int could point to a different number of int 's. 每个指向int指针都可以指向不同数量的int

For example, array[0] may point to ten ints. 例如,array [0]可能指向十个整数。 array[1] may point to twenty int s. array [1]可能指向20个int There's nothing that requires array[x] to point to the same number of int s as array[y]. 没有什么要求array [x]指向与array [y]相同数量的int

That job belongs to you, the programmer. 那个工作属于你,程序员。 The compiler doesn't know anything. 编译器一无所知。 It is up to you to properly allocate each pointer to an int , to the right number of int s, for each such pointer, and then allocate the right number of pointers to int s in the first place. 您需要为每个此类指针正确地将每个指针分配给一个int ,并为其分配正确数量的int ,然后首先将正确数量的指针分配给int The compiler doesn't know how many of each there are, it's your job to keep track of that, in some form or fashion, in order to write bug-free code. 编译器不知道每个有多少个,您的工作就是以某种形式或方式跟踪它,以便编写无错误的代码。

Welcome to C++. 欢迎使用C ++。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM