多维数组如何在内存中格式化?

在C中,我知道我可以使用下面的代码在堆上动态分配一个二维数组:

int** someNumbers = malloc(arrayRows*sizeof(int*)); for (i = 0; i < arrayRows; i++) { someNumbers[i] = malloc(arrayColumns*sizeof(int)); } 

显然,这实际上创建了一个指向一堆单独的一维整数数组的指针的一维数组,“系统”可以找出我的意思,当我要求:

 someNumbers[4][2]; 

但是当我静态声明一个二维数组,如下面的行…:

 int someNumbers[ARRAY_ROWS][ARRAY_COLUMNS]; 

…是否在堆栈上创建了类似的结构,还是完全是另一种形式? (也就是说,它是一个指针的一维数组吗?如果不是,它是什么,以及如何得到它的引用?)

另外,当我说“系统”时,究竟是什么负责确定呢? 内核? 或者C编译器在编译时将其整理出来?

一个静态的二维数组看起来像一个数组数组 – 它只是连续地放在内存中。 数组与指针不是同一个事物,但是因为通常可以互换使用它们,所以有时可能会引起混淆。 编译器保持正确的轨道,但是,这使得一切都很好地排队。 你必须小心静态二维数组,如你所说,因为如果你试图传递一个函数采取int **参数,坏事情将发生。 这里有一个简单的例子:

 int array1[3][2] = {{0, 1}, {2, 3}, {4, 5}}; 

在内存中看起来像这样:

 0 1 2 3 4 5 

完全一样:

 int array2[6] = { 0, 1, 2, 3, 4, 5 }; 

但是,如果您尝试将array1传递给此函数:

 void function1(int **a); 

你会得到一个警告(和应用程序将无法正确访问数组):

 warning: passing argument 1 of 'function1' from incompatible pointer type 

因为2D数组与int **不一样。 可以说,一个数组自动衰减到一个指针只有“一层”。 您需要声明该函数为:

 void function2(int a[][2]); 

要么

 void function2(int a[3][2]); 

让一切开心。

这个相同的概念扩展到n维数组。 尽管在你的应用程序中利用这种有趣的业务通常只会使其更难理解。 所以要小心。

答案是基于这样的想法,即C没有真正的二维数组 – 它有数组的阵列。 当你声明这个:

 int someNumbers[4][2]; 

您要求someNumbers是一个4个元素的数组,其中数组的每个元素的类型为int [2] (本身是一个2个int的数组)。

难题的另一部分是数组总是在内存中连续放置。 如果您要求:

 sometype_t array[4]; 

那么总是看起来像这样:

 | sometype_t | sometype_t | sometype_t | sometype_t | 

(4个sometype_t对象相邻放置,两者之间没有空格)。 所以在你的someNumbers数组中,它看起来像这样:

 | int [2] | int [2] | int [2] | int [2] | 

而每个int [2]元素本身就是一个数组,看起来像这样:

 | int | int | 

总的来说,你得到这个:

 | int | int | int | int | int | int | int | int | 
 unsigned char MultiArray[5][2]={{0,1},{2,3},{4,5},{6,7},{8,9}}; 

在内存中等于:

 unsigned char SingleArray[10]={0,1,2,3,4,5,6,7,8,9}; 

在回答你的同时也是这样:虽然编译器正在做大部分的繁重工作。

在静态分配数组的情况下,“系统”将是编译器。 它将像任何堆栈变量一样保留内存。

在malloc'd数组的情况下,“系统”将是malloc(通常是内核)的实现者。 所有的编译器将分配的是基指针。

编译器总是要按照他们声明的那样来处理类型,除了在Carl给出的例子中可以找出可互换的用法。 这就是为什么如果你将一个[] []传递给一个函数,它必须假定它是一个静态分配的平面,其中**被假定为指向指针的指针。

要访问特定的二维数组,请考虑数组声明的内存映射,如下面的代码所示:

  0 1 a[0]0 1 a[1]2 3 

要访问每个元素,只需将您感兴趣的数组作为参数传递给函数就足够了。 然后使用偏移量列来单独访问每个元素。

 int a[2][2] ={{0,1},{2,3}}; void f1(int *ptr); void f1(int *ptr) { int a=0; int b=0; a=ptr[0]; b=ptr[1]; printf("%d\n",a); printf("%d\n",b); } int main() { f1(a[0]); f1(a[1]); return 0; }