我知道C中的数组是按行主顺序分配的。因此,对于2 x 3阵列:
0 1
2 3
4 5
以
的形式存储在内存中0 1 2 3 4 5
然而,如果我有一个2 x 3 x 2阵列怎么办:
0 1
2 3
4 5
和
6 7
8 9
10 11
这些如何存储在内存中?就像是连续的:
0 1 2 3 4 5 6 7 8 9 10 11
还是其他方式?或者它取决于什么?
答案 0 :(得分:26)
在低级别,没有多维数组这样的东西。只有一个平坦的内存块,大到足以容纳给定数量的元素。在C中,多维数组在概念上是一个数组,其元素也是数组。所以如果你这样做:
int array[2][3];
从概念上讲,你最终得到:
array[0] => [0, 1, 2]
array[1] => [0, 1, 2]
这会导致元素在内存中连续排列,因为array[0]
和array[1]
实际上并不包含任何数据,它们只是对两个内部数组的引用。请注意,这意味着只有[0, 1, 2]
条目实际占用内存空间。如果将此模式扩展到下一个维度,则可以看到:
int array[2][3][2];
...将为您提供如下结构:
array[0] => [0] => [0, 1]
[1] => [0, 1]
[2] => [0, 1]
array[1] => [0] => [0, 1]
[1] => [0, 1]
[2] => [0, 1]
继续在内存中连续排列元素(如上所述,只有[0, 1]
条目实际占用内存中的空间,其他所有内容只是对其中一个条目的引用的一部分)。如您所见,无论您有多少维度,此模式都将继续。
只是为了好玩:
int array[2][3][2][5];
给你:
array[0] => [0] => [0] => [0, 1, 2, 3, 4]
[1] => [0, 1, 2, 3, 4]
[1] => [0] => [0, 1, 2, 3, 4]
[1] => [0, 1, 2, 3, 4]
[2] => [0] => [0, 1, 2, 3, 4]
[1] => [0, 1, 2, 3, 4]
array[1] => [0] => [0] => [0, 1, 2, 3, 4]
[1] => [0, 1, 2, 3, 4]
[1] => [0] => [0, 1, 2, 3, 4]
[1] => [0, 1, 2, 3, 4]
[2] => [0] => [0, 1, 2, 3, 4]
[1] => [0, 1, 2, 3, 4]
答案 1 :(得分:17)
所有“尺寸”都连续存储在内存中。
考虑
int arr[4][100][20];
您可以说arr[1]
和arr[2]
(int[100][20]
类型)是连续的
或者arr[1][42]
和arr[1][43]
(类型int[20]
)是连续的
或者arr[1][42][7]
和arr[1][42][8]
(int
类型)是连续的
答案 2 :(得分:13)
是的,你是对的 - 它们是连续存放的。考虑这个例子:
#include <stdio.h>
int array3d[2][3][2] = {
{{0, 1}, {2, 3}, {3, 4}},
{{5, 6}, {7, 8}, {9, 10}}
};
int main()
{
int i;
for(i = 0; i < 12; i++) {
printf("%d ", *((int*)array3d + i));
}
printf("\n");
return 0;
}
输出:
0 1 2 3 3 4 5 6 7 8 9 10
答案 3 :(得分:8)
是的,它们只是按顺序存储。您可以像这样测试:
#include <stdio.h>
int main (int argc, char const *argv[])
{
int numbers [2][3][4] = {{{1,2,3,4},{5,6,7,8},{9,10,11,12}}
,{{13,14,15,16},{17,18,19,20},{21,22,23,24}}};
int i,j,k;
printf("3D:\n");
for(i=0;i<2;++i)
for(j=0;j<3;++j)
for(k=0;k<4;++k)
printf("%i ", numbers[i][j][k]);
printf("\n\n1D:\n");
for(i=0;i<24;++i)
printf("%i ", *((int*)numbers+i));
printf("\n");
return 0;
}
这意味着对具有维度(N,M,L)的多索引数组的访问将转换为ondimensional访问,如下所示:
array[i][j][k] = array[M*L*i + L*j + k]
答案 4 :(得分:6)
我想你已回答了自己的问题。多维数组以行主顺序存储。
参见ANSI C规范第3.3.2.1节(还有一个具体的例子):
连续的下标运算符指定a的成员 多维数组对象。如果E是一个n维数组(n = 2)尺寸为i x j“x ... x”k,则为E(除了a之外的其他用途 lvalue)转换为指向(n-1)维数组的指针 尺寸j“x ... x”k。如果将unary *运算符应用于此 指针明确地或隐式地作为下标的结果 结果是指向(n-1)维的数组,它本身就是 如果用作左值而不是左值,则转换为指针。它跟随 从这个角度来看,数组以行主要顺序存储(最后一个下标 变化最快)。
对于您的示例,您可以尝试一下并查看 - http://codepad.org/10ylsgPj
答案 5 :(得分:3)
假设你有一个数组char arr[3][4][5]
。它是由4个5个字符阵列组成的3个数组的数组。
为简单起见,我们假设arr[x][y][z]
中的值为xyz
,而arr[1][2][3]
中的值为123
。
所以内存中的布局是:
| 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19
--+--------------------------------------------------------------------------------
00| 000 001 002 003 004 010 011 012 013 014 020 021 022 023 024 030 031 032 033 034
20| 100 101 102 103 104 110 111 112 113 114 120 121 122 123 124 130 131 132 133 134
40| 200 201 202 203 204 210 211 212 213 214 220 221 222 223 224 230 231 232 233 234
arr[0]
,arr[1]
和arr[2]
一个接一个地出现,但是char[4][5]
类型中的每个元素(这些是表格中的三行)。
arr[x][0] - arr[x][3]
也是一个接一个地出现,其中的每个元素都是char[5]
类型(这些是表中每一行的四个部分,000 - 004是{{的一个元素1}})
arr[0][0]
是5个字节,一个接一个地出现。
答案 6 :(得分:2)
回答OP对主要问题的评论(会有点长,所以我决定回答,而不是评论):
C中的数组是否应声明为
array[ny][nx]
,其中ny
和nx
是y和x方向上的元素数。此外,这是否意味着我的3D数组应声明为array[nz][ny][nx]
?
在数学中,MxN矩阵具有M行和N列。矩阵元素的常用符号是a(i,j), 1<=i<=M, 1<=j<=N
。所以你问题中的第一个矩阵是一个3x2矩阵。
实际上,它与通常用于例如GUI元素。 800x600位图水平(沿X轴)具有800个像素,垂直(沿Y轴)具有600个像素。如果有人想将其描述为矩阵,那么在数学符号中它将是600x800矩阵(600行,800列)。
现在,C中的多维数组存储在内存中,a[i][j+1]
位于a[i][j]
旁边,而a[i+1][j]
是N个元素。通常说“最后一个下标变化最快”,或者通常称为“按行存储”:二维矩阵中的一行(即具有相同第一索引的元素)已连续放置在内存中而一列(相同的第二个索引) )由远离彼此的元素组成。重要的是要了解性能方面的考虑:访问邻居元素通常要快得多(由于HW缓存等),因此例如应该组织嵌套循环,使最里面的循环遍历最后一个索引。
回到问题:如果你的2D数组的心理图片(抽象)是Carthesian坐标中的格子,那么是的,你可以把它想象成C中的array[NY][NX]
。但是如果你需要将真实的2D或3D数据描述为数组,索引的选择可能取决于其他因素:数据格式,方便的符号,性能等。例如,如果位图的内存中表示是array[NX][NY]
您需要使用的格式,您将以这种方式声明,也许您甚至不需要知道位图变为“转置”类型:)
答案 7 :(得分:-3)
3d数组是扩展的2d数组。
例如我们有一个数组 - int arr(3)(5)(6);
这是一个由两个2d数组组成的数组,其中数组有一个2行数组,有4行3列。