我需要解释以下代码:
int a[2][3][2] = { 1,2,3,
4,5,6,
7,8,9,
10,11,12 };
std::cout << a[0][5][0];
就multi dimensional arrays
而言,第一个索引表示行计数,第二个索引表示列计数,第三个索引表示数组计数。但是,这里的代码给了我11
作为输出,而且更令人震惊的是
for(int i=0; i<12; i++)
std::cout<<a[0][0][i];
打印数组的所有元素。我无法在网络上的任何地方找到这种访问的解释。有人请澄清我!
答案 0 :(得分:1)
这样想。
a [2] [3] [2]实际上只是一个[12],分为2组和3组。
a [0] [5] [0]实际上是[0] [0] [5 * 2] = a [0] [0] [10]
这是因为数组被加载到连续的内存中。
答案 1 :(得分:1)
故事的寓意是......“没有勺子”(矩阵)。
没有行,列和页面。只是一个具有线性序列的存储器,其中元素一个接一个地存储。
多维数组只是一个“投影”,而构思或页面/行/列只是一个抽象。
a[k][j][i]
只是意味着(间接水平分开)*(a + k*Y*X + j*X + i)
其中Z,X和Y是尺寸的大小。我们最有可能称之为“页面”,“行”和“列”。
请注意。独立于Z,Y和X,将k = 0,j = 0,i = 11,在等效表达式中非常有意义,并且将引用12值。
答案 2 :(得分:1)
只要您处于a[2][3][2]
的范围内,您期望的结果才会保留。也就是说,当您执行a[0][0][0]
到a[1][2][1]
时,您的假设将保持不变。但是一旦你越过那个边界,你看到的结果就不再相同了。
这里实际发生的是a[i][j][k]
在技术上与第一个之后的k+j*2+i*2*3
元素相同,考虑到您在代码中使用的数字。这使得可以使您的数组的表示看起来像“3D”但实际上在内存中它们是“在线”或在一维数组中。因此,通过执行此操作*2
和*2*3
,您实际上是跳转到“下一个”子阵列。
当你超出a[2][3][2]
的范围时,为什么它不起作用?以a[i][j][k]
k=4
为例,它等同于i*2*3 + j*2 + k = i*2 + (j+1)*3 + 1
。所以就好像它已“跳”到下一行/列/无论如何。
您可以通过想象一个表并遍历该行,在二维数组上更好地将其可视化,一旦超出该行的最后一列,您就会落在它下面的行上。
但是,当你走出多维数组的边界时,或当你从你所在的行“掉落”时,C不会发出警告。
的更新强>
你说a[0][5][0]
不存在是正确的。在这种情况下会发生的是,您实际上会在a
旁边读取内存中的其他内容。例如,假设您的代码中有a
和b
,当您在代码中处理a
和b
时,会发生什么事情。是a
和b
只是一些记忆。让我们说a
是一个总共有12个元素的数组,当你超出这12个元素时,C只会假设数组和你说的一样大,然后去取一块后面的内存。 15“块”并将给你。所以a[15]
实际存在,但它不属于数组。它可能属于b
,如果它们在内存上彼此相邻,或者它可以完全属于其他东西。
技术术语是当你将 a
声明为12个整数的数组时,它会将12个整数(12 * 4个字节)的内存分配给彼此并且标记为a
为您。 a
将指向那段记忆的开始;它是一个指针。当你执行a[x]
或a[i][j][k]
时,你会得到指向第x段记忆的指针。如果x大于12,它将超出a并抓住那里的任何东西并认为它是一个整数。 (虽然它可能是别的东西;这就是为什么当你做这种事情时你可能会得到垃圾,因为它实际上可能是别的东西而且它们把它解释为好像它是一个整数)。
答案 3 :(得分:0)
多维数组存储在连续内存位置的内存中,因此您的数组在内存中看起来像:
1 2 3 4 5 6 7 8 9 10 11 12
由于C不提供数组绑定检查,因此可以在数组限制之后访问内存,甚至是未分配的内存(这会使有时错误)。
访问a [x] [y] [z]是使用x,y,z,值和内存地址中数组a的大小相对于a计算的(如您所知,a是指向数组中的第一个元素,在这种情况下为[0] [0] [0]。