[英]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]
,其中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]
in您需要使用的格式,您將以這種方式聲明它,也許您甚至不需要知道位圖變為“轉置”:)
3d數組是擴展的2d數組。
例如,我們有一個數組 - int arr(3)(5)(6);
這是一個由兩個2d數組組成的數組,其中數組將具有4行和3列的2d數組。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.