由于C/C ++中的数组不是对象并且会退化为指针,编译器使用提供的索引执行指针算术来访问元素。据我了解,当超过第一个维度时,这个过程与静态声明的数组与动态声明的数组之间存在差异。
如果我要在堆栈上声明一个数组,如下所示;
int array[2][3] = { 0, 1, 2, 3, 4, 5 }
//In memory { row1 } { row2 }
这个数组会以行主序格式存储在内存中,因为它被存储在一个连续的内存块中。这意味着当我尝试访问数组中的元素时,编译器必须执行一些加法和乘法运算来确定正确的位置。
因此,如果我要执行以下操作:
int x = array[1][2]; // x = 5
编译器将使用以下公式:
i = 行索引 j = 列索引 n = 单行大小(此处 n = 2)
array = 指向第一个元素的指针
*(array + (i*n) + j)
*(array + (1*2) + 2)
这意味着如果我循环访问该数组中的每个元素,每次按索引访问都会执行额外的乘法步骤。
现在,在堆上声明的数组范式不同,需要多个阶段的解决方案。注意:我也可以在这里使用C++的new运算符,但我认为数据的表示方式没有区别。
int ** array;
int rowSize = 2;
// Create a 2 by 3 2d array on the heap
array = malloc(2 * sizeof(int*));
for (int i = 0; i < 2; i++) {
array[i] = malloc(3 * sizeof(int));
}
// Populating the array
int number = 0;
for (int i = 0; i < 2; i++) {
for (int j = 0l j < 3; j++) {
array[i][j] = number++;
}
}
由于数组现在是动态的,其表示形式是一个一维数组的一维数组。我将尝试绘制一个ASCII图片...
int * int int int
int ** array-> [0] 0 1 2
[1] 3 4 5
这意味着不再涉及乘法,对吗?如果我按照以下方式操作:
int x = array[1][1];
这将对array[1]执行间接/指针算术运算,以访问指向第二行的指针,然后再次执行此操作以访问第二个元素。我这样说是正确的吗?
现在有了一些背景,回到问题。如果我正在为需要快速性能的应用程序编写代码,比如游戏每帧大约需要0.016秒来渲染,那么我是否应该三思而后行,考虑使用堆栈上的数组还是堆上的数组?现在我意识到使用malloc或new运算符会有一次性的成本,但在某个点上(就像Big O分析一样),当数据集变得很大时,通过动态数组迭代避免行主要索引是否更好呢?