繁体   English   中英

3D数组如何存储在C中?

[英]How are 3D arrays stored in C?

我知道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

或者是其他方式? 还是取决于什么?

在较低的层次上,没有多维数组这样的东西。 只有一个平坦的内存块,大到足以容纳给定数量的元素。 在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]

所有“尺寸”都连续存储在存储器中。

考虑

    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类型)是连续的

是的,你是对的 - 它们是连续存储的。 考虑这个例子:

#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

是的,它们只是按顺序存储。 您可以像这样测试:

#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]

我想你已回答了自己的问题。 多维数组以行主顺序存储。

请参阅ANSI C规范第3.3.2.1节(还有一个具体示例):

连续的下标运算符指定多维数组对象的成员。 如果E是具有维度ixj“x ... x”k的n维数组(n = 2),则E(用作除左值之外的值)被转换为指向(n-1)维数组的指针尺寸为j“x ... x”k。 如果将unary *运算符显式地应用于此指针,或者由于下标而隐式应用于该指针,则结果是指向的(n-1)维数组,如果将其用作除左值之外的其他数据本身将转换为指针。 由此得出,数组以行主要顺序存储(最后一个下标变化最快)。

对于您的示例,您可以尝试一下并查看 - http://codepad.org/10ylsgPj

假设你有一个数组char arr[3][4][5] 它是由3个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是arr[0][0]一个元素

arr[x][y][0] - arr[x][y][4]是一个接一个地出现的5个字节。

回答OP对主要问题的评论(会有点长,所以我决定回答,而不是评论):

C中的array[ny][nx]是否应声明为array[ny][nx] ,其中nynx是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] in您需要使用的格式,您将以这种方式声明它,也许您甚至不需要知道位图变为“转置”:)

3d数组是扩展的2d数组。

例如,我们有一个数组 - int arr(3)(5)(6);

这是一个由两个2d数组组成的数组,其中数组将具有4行和3列的2d数组。

暂无
暂无

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

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