我想了解在c++中动态分配二维数组是如何工作的。
为类型为int
,大小为m * n
的二维数组动态分配内存时,我们写:
int **arr = new int * [m];
,然后在大小m
上运行循环,直到达到列数n
,为每个指针分配一个数组。
我不明白为什么我们假设当我们创建指针数组时,它假设它是行格式。为什么不能是列格式?如果它是列格式,那么当我们遍历它分配数组时,我们将分配行,因此2D数组的顺序将颠倒,而不是m * n
,它将成为n * m
。
系统如何知道这个语句-int **arr = new int * [m]
-它必须以行格式分配,相应的列将在稍后分配?
标准C确实分配了多维的" C数组";在一个单独的块中,不像文本描述的那样。因此,int arr[3][4]
将被分配(等价地)为int arr[12]
,arr[2][1]
将被访问为arr[2*4+1]
。
然而,即使对于小矩阵,这也会造成内存碎片(块太大而无法分配),因此包通常会像您的文本描述的那样独立分配整个列或行。
相反,Fortran将按行分配矩阵,因此在编码时需要认识到这一点。在C语言中没有这样的东西。因此,单个元素的内部分配和访问完全取决于您使用的是哪个包。
由您决定是使用以行为主还是以列为主的2D数组分配方案。在您的代码中:**arr = new int * [m]
m可以是列数或行数。这与系统无关。
更重要的是你什么时候选择行为主还是列为主。这可能取决于您选择的算法或性能要求。例如,如果您通过迭代行来访问2D数组,那么row-major将更有效,因为CPU将在更有效的缓存中缓存行。另一方面,如果按列迭代数组,则选择column-major。
也有其他的方法来分配内存使用它作为一个二维数组-通过调用int* arr = new int[m*n];
然后索引arr[i + j*m]
假设m是行。
你所描述的不是一个二维数组,而是一个指向一维数组的指针的一维数组。由应用程序来决定它们是代表矩阵的行还是列。
在C和c++中,可以定义二维数组,并按行主序存储,这意味着连续存储的元素具有连续的第二个索引。内存中的A[1][0]后面紧跟着A[1][1]。考虑到第一个[第二个]索引通常被引用为表示行[列],这证明了行主命名是合理的。
为了一致性,指向数组的指针数组应该与连续的行相对应。