【发布时间】:2011-11-11 02:59:08
【问题描述】:
谁能给我一个公式,以便我能理解像"How_are_two-dimensional_arrays_represented_in_memory" 这样的 n 维 (n>=2) 数组的内存表示?
此计算仅适用于二维数组。
如何计算,假设,一个 5D 数组?
好的....
【问题讨论】:
标签: c arrays memory-management
谁能给我一个公式,以便我能理解像"How_are_two-dimensional_arrays_represented_in_memory" 这样的 n 维 (n>=2) 数组的内存表示?
此计算仅适用于二维数组。
如何计算,假设,一个 5D 数组?
【问题讨论】:
标签: c arrays memory-management
C 中的二维数组只不过是一个数组数组。 3维数组是数组数组的数组。以此类推。
C99 standard 中的相关部分是 6.5.2.1,“数组下标”:
连续的下标运算符指定一个元素 多维数组对象。如果 E 是一个 n 维数组 (n ≥ 2) 尺寸为 i × j × 。 . . × k,然后是 E(用作 除了左值)被转换为指向 (n 的指针 - 1) 维度数组 j × 。 . . × k。如果一元 * 运算符显式或隐式应用于此指针 下标的结果,结果是指向的 (n - 1) 维数组,如果使用它本身会转换为指针 除了左值之外。由此得出数组被存储 按行主要顺序(最后一个下标变化最快)。
索引运算符是根据指针算术定义的这一事实引起了一些混乱。这并不意味着数组是“真正的指针”——事实上它们绝对不是。声明一个数组对象根本不会创建任何指针对象(当然,除非它是一个指针数组)。但是引用数组的表达式通常(但不总是)“衰减”为指向数组第一个元素的指针(这是指针 value,而不是指针 object) .
现在简单的数组对象,无论有多少维度,都非常不灵活。在 C99 之前,所有数组对象都必须具有在编译时确定的固定大小。 C99 引入了可变长度数组 (VLA),但即便如此,VLA 的大小在声明时也是固定的(并非所有编译器都支持 VLA,即使在 C99 标准发布 12 年后也是如此)。
如果您需要更灵活的东西,一种常见的方法是声明一个指向元素类型的指针,然后使用malloc() 分配一个数组并让指针指向数组的第一个元素:
int *ptr = malloc(N * sizeof *ptr);
if (ptr == NULL) /* handle allocation failure */
这使您可以使用与声明的固定大小数组对象相同的语法来引用堆分配数组的元素,但在arr[i] 中,表达式arr 衰减为指针,而在@ 987654327@ `ptr 已经是一个指针。
同样的事情可以扩展到更高的维度。您可以分配一个指针数组,然后将每个指针初始化为指向已分配的 whatever 数组的开头。
这为您提供了作用非常类似于二维(或更多)数组的东西,但您必须自己管理内存;这就是更大灵活性的代价。
严格来说,这不是二维数组。正如我上面所说的,二维数组只是一个数组数组。将其视为二维数组可能并非完全不合理,但这与 C 标准中的用法相冲突;这类似于将链表称为一维数组。
comp.lang.c FAQ 是一个很好的资源;涵盖数组和指针的第 6 节特别出色。
【讨论】:
二维数组实际上是指向数组的指针数组。一个二维整数数组a[i][j] 将占用i*sizeof(int*) 用于指针数组,i*j*sizeof(int) 用于最终数组。
一个 3-D 数组 a[i1][i2][i3] 是一个指向数组指针数组的指针数组。第一级数组包含i1指针,第二级包含i1*i2指针,第三级包含i1*i2*i3整数。
通常,大小为i1..iN 的N 维数组将具有N-1 级别的指针数组和1 级别的整数数组。 N 层的数组长度为iN,该层有product of i1..iN-1 数组。
所以,一个 5 维数组:
1 array, length i1, of pointers
i1 arrays, length i2, of pointers
i1*i2 arrays, length i3, of pointers
i1*i2*i3 arrays, length i4, of pointers
i1*i2*i3*i4 arrays, length i5, of ints
希望对您有所帮助(我希望我的索引是正确的)。
您发布的那个维基百科链接指的是/不同类型的多维数组/。默认情况下,C 多维数组就是我刚才描述的方式。您还可以将它们抽象为一维数组。这节省了内存并使整个数组连续,但它使访问元素更加复杂。对于 5-D 示例:
// WARNING I AM CHANGING NOTATION. N1..N5 are the lengths in each direction.
// i1..i5 are the indicies.
int* bigarray = malloc(sizeof(int)*N1*N2*N3*N4*N5);
// now instead of bigarray[i1][i2][i3][i4][i5], write this:
*(bigarray + i1*N2*N3*N4*N5 + i2*N3*N4*N5 + i3*N4*N5 + i4*N5 + i5);
每个术语都有一个偏移量乘以我们需要偏移的元素数量。例如,要增加一个第一维级别,我们需要遍历剩余的四个维度一次以“环绕”,如果您愿意的话。
【讨论】:
int arr[10][10]; 声明 ints 的 10 x 10 二维数组。看不到指针对象。
我记得,对于 C 来说,数组在内存中的存储方式并不是标准化的。但有关数组的一些信息,以及它们如何存储在内存中,请参阅以下两个链接:
http://webster.cs.ucr.edu/AoA/Windows/HTML/Arraysa2.html
http://publications.gbdirect.co.uk/c_book/chapter5/arrays.html
第一个链接更笼统,讨论了存储数组的不同方式,而第二个链接讨论了 C 数组在内存中最可能的布局方式。
【讨论】: