0
简而言之,C++中的多维数组是数组数组,还是仅仅是一个数组,它表现得像多维数组?
我的一位朋友解释说C++中的数组是简单的指针,多维数组也是常数指针,它们的元素由一个以上的索引(即指针指向一个大数组,元素的偏移用多个索引计算)来处理。
我认为多维数组是指向其他数组的指针的一维数组,因为当将多维数组作为函数参数传递时,我经常使用以下语法:
1
| void copy_matrix(int ** matrix); |
如果不是,是否可以在C++中创建数组数组,并在编译时赋值每个子数组的值——相当于下列语句的语义:
1 2 3 4
| int line[2][2];
line[0] = {100, 100};
line[1] = {200, 200}; |
上述语句生成编译时错误。我想到的一个快速(未经测试的)黑客是:
2
然而,我相信必须有一个更优雅的方法来达到同样的结果。我希望能清楚地理解这些概念,并感谢任何输入。
- stackoverflow.com/questions/4810664/how-do-i-use-arrays-in-c应该是一个不错的读物。
- 如果将matrix声明为int matrix[2][2],则void copy_matrix(int ** matrix);也将生成编译器错误。例如,G++抱怨cannot convert 'int (*)[2]' to 'int**' for argument '1' to 'void copy_matrix(int**)'。
- C++ 0x似乎支持您想要的更简单的初始化语法。
大括号列表初始值设定项只能在初始化期间工作,并且不能用于赋值,正如您似乎尝试的那样。
相反,只需一次性初始化多维数组:
1
| int line[2][2] = { {100, 100}, {200, 200} }; |
作为对第一句话的回应:数组是数组,指针是指针,它们不一样。然而,数组确实很容易衰减到指向第一个元素的指针,并且x[n]相当于*(x + n)。这同样适用于多维数组。
数组T[N]在内存中对于T和sizeof(T[N]) == N * sizeof(T)是连续的;因此,数组T[N][M]的数组对于T[N]和T是连续的。
- 除了T[i]这样的东西外,T内存中的任何地方都不是多维数组。EDCOX1〔0〕是C(和C++)想象的图形。C和C++如何对待数组和多维数组(或者说是虐待)是驱使科学程序员疯狂的事情之一。
- @大卫:没错,就语言而言,不允许利用多维数组的内存连续性。但是,同时保证内存实际上是连续的。不过,如果您想考虑内存位置,这仍然是一个有用的保证。
C和C++中的多维数组是数组的数组。但是,由于数组只是一个接一个地在内存中排列它的对象,因此数组只是一个接一个地排列数组。因此,如果将其衰减为指针,可以将其视为单个数组。
通过将数组值放在大括号之间(用逗号分隔)初始化数组。初始化数组的方法与初始化数组的方法相同——将数组的值(它们本身的数组)放在大括号中。
所以:
1 2 3 4
| int line[2][2]={
{ 100, 100 }, // line[0]
{ 200, 200 } // line[1]
}; |
但没有快捷方式可供分配。你必须一个一个的去做(或者使用一些像memcpy这样的功能)。
- 在C和C++中,数组(例如,EDCOX1(3))和多维数组(例如EDCOX1(4))存在巨大的差异。它们在C/C++代码中以相同的方式索引是句法糖。对于不规则数组,如int ** ragged,访问数组元素需要经过两个指针。对于多维数组,您只需要通过一个指针。
- int **是指向指针的指针,而不是数组的数组。int (foo[4])[4];是一个数组,与int foo[4][4];相同。多维数组是数组的数组——即使标准没有特别提到它们,它们也会有精确的语义。
- 虽然a[x][y]与*(*(a+x)+y)相同,因为标准规定如此,但没有一个健全的编译器可以这样计算a[x][y],即使在优化级别0。因为标准还规定数组必须占用一个连续的内存块,所以可以通过两个乘数和一个加法找到a[x][y]:element_size*((column_dimension*x+y)。实际上,内存中没有包含a[x]的内容。相反,它必须被计算出来。
- 我不知道为什么你说没有一个健全的编译器会用这种方式计算a[x][y],它的操作完全相同,在每种情况下都有两个乘法和一个加法(a+s1*x+s2*y)。当然,有一块内存包含a[x],你可以用&a[x]得到它的地址(因为a是一个整数数组,它的每个元素(如a[x])是一个整数数组)。不知怎么的,我们一定是在互相推诿。
- 是的,我怀疑我们是在互相交谈。我所说的"实际上,内存中没有包含a[x]的内容":a[x]是一个地址。在不规则数组中,有一个特定的内存块包含a[x]:它是a[x]。在多维数组中,没有包含此地址的内存块。必须计算a[x]。
- @D.Hammen:我认为你和D.Schwartz是在互相交谈,因为他(正确地)把a[x]当作一维子数组的引用,而你的评论把a[x]当作一维子数组的指针(就好像这是一个"不规则的数组")。所以你是正确的,没有这样的指针存在,但我不认为D.Schwartz意味着它确实存在。要理解的一个关键点是(在本文中)&a[x]返回一个指向子数组的指针——它不返回指向子数组指针的指针。
- @哈曼:在另一张纸条上,你的第一条评论是正确的,但我不明白它与给出的答案有什么关系。是因为不能将多维数组传递给int copy_matrix(int ** matrix);吗?我认为这个答案并没有解决问题的那一部分。我看不出施瓦茨给出的答案有任何问题,除了它没有解决行动计划问题的每一个方面。
- @哈曼:哦,我明白了。你说的是"不规则数组"是"数组数组",D.Schwartz说多维数组是"数组"。我同意施瓦茨的观点(或者两者都可以被认为是正确的),但也许这个问题不值得争论——是否有一个确定的来源?
0
是后者。多维数组和不规则数组在内存表示和索引解释方式上都存在巨大差异。
像int array[L][M][N]这样的多维数组占用一个连续的内存块。访问单个元素array[i][j][k]等同于*(&array[0][0][0]+(i*M+j)*N+k)。查找只涉及一个指针取消引用。
像int *** ragged这样的不规则数组是int**指针的一维数组。这些int**指针中的每一个都是int*指针的一维数组,每个都是一个一维的整数数组。这里,array[i][j][k]相当于*(*(*(array+i)+j)+k)。查找涉及三个指针取消引用。
- 您将数组与指针数组混淆。如果一个int数组占用一个连续的内存块,那么数组也会占用一个连续的内存块。我不知道你为什么提出不规则阵列,它们与问题无关。
- 我不会混淆数组和指针数组。这只是在争论"数组"一词的含义。对我和大多数科学程序员来说,数组的数组是Type **,而Type foo[Size1][Size2]则不是数组。它是一个Size&215;Size2矩阵:单个实体。例如,惯性张量或应力-能量张量不是数组。
- Type **是指向指针的指针。在C或C++中,数组包含一个接一个地存储在内存中的对象。Type foo[Size1][Size2]是一个数组数组。它与(Type foo[Size1])[size2]完全相同,后者显然是一个数组。
这是一段时间以来,我最后一个编码的C++(更多的Java人现在),但如果我记得正确的多维数组确实是数组的数组。
可以这样初始化数组:int行[2][2]=100,100,200,200
P.S.:方形制动器只是简单化:a[x]与*(a+x)相同,a[x][y]与*(a+x+y)相同。
P.P.S.:略微修正初始化
- C和C++中的多维数组不是数组的数组。不规则数组是数组的数组。大的不同。
- 不规则数组不是C/C++数组。C/C++数组必须是相同类型变量的向量。不规则数组包含类型不同的元素。多维数组实际上是数组的数组。即使标准从未提到它们,它们的工作方式也完全相同,因为数组可以是任何类型的数组,包括本身就是数组的数组,这仅仅是因为没有任何东西禁止这样做。
- @大卫·施瓦茨:看看最初的问题。OP询问了void copy_matrix(int ** matrix)的有效性,如果matrix被宣布为int[2][2] matrix,它肯定不会起作用。
- @大卫·施瓦茨:不规则数组包含不同类型的元素。用谷歌搜索"不规则阵列"。double** foo是一个参差不齐的数组。例如,这些可以方便地表示上三角矩阵。
- 多维数组是数组的数组。不规则数组是指向数组的指针数组。在这两种情况下,元素只有一种类型。
- 不,double** foo根本不是数组。它是指向指针向量的指针。在这样一个不规则的数组中,每个指针可以指向任意数量的double,因此它们在内存布局上有所不同(一个可以持有12倍的向量,一个可以持有8倍的向量)。这就是他们衣衫褴褛的原因。不规则数组不是C/C++数组,不是数组数组,它们与这个问题无关,只是混淆。