我有两种构建2D数组的方法:
int arr[NUM_ROWS][NUM_COLS];
//...
tmp = arr[i][j]
和扁平数组
int arr[NUM_ROWS*NUM_COLS];
//...
tmp = arr[i*NuM_COLS+j];
我正在进行图像处理,因此即使访问时间有所改善也是必要的。哪一个更快?我想第一个,因为第二个需要计算,但第一个需要两个寻址,所以我不确定。
答案 0 :(得分:2)
我认为没有任何性能差异。在这两种情况下,系统将分配相同数量的连续内存。对于计算i*Numcols+j
,您可以为1D数组声明执行此操作,或者系统将在2D情况下执行此操作。唯一关心的是易用性。
答案 1 :(得分:1)
在优化标准代码时,您应该相信编译器的功能。
此外,您应该信任具有快速数字乘法指令的现代CPU。
不要费心去使用其中一种!
我 - 几十年前 - 通过使用指针而不是使用2d阵列计算来极大地优化了一些代码 - >但这将a)只有在存储指针的选项时才有用 - 例如在一个循环和b)具有低影响因为我猜现代cpu应该在一个周期内进行2d阵列访问?值得测量!可能与数组大小有关。在任何情况下,如果适用,使用ptr ++或ptr + = NuM_COLS的指针肯定会更快一点!
答案 2 :(得分:0)
第一种方法几乎总是更快。总的来说(因为总是存在极端情况)处理器和内存架构以及编译器可能内置了优化以帮助2d数组或其他类似的数据结构。例如,GPU针对矩阵(2d数组)数学进行了优化。
所以,一般来说,如果可能的话,我会允许编译器和硬件优化你的内存和地址算法。
...我同意@Paul R,在性能方面还有比数组分配和地址算法更重要的考虑因素。
答案 3 :(得分:0)
由于您的目标是图像处理,因此我认为您的图像对于静态数组来说太大了。关于动态分配数组的正确问题
在C / C ++中,有多种方法可以分配动态2D数组How do I work with dynamic multi-dimensional arrays in C?。为了使这个在C / C ++中工作,我们可以使用malloc和cast(对于C ++,你可以使用new)
方法1:
int** arr1 = (int**)malloc(NUM_ROWS * sizeof(int*));
for(int i=0; i<NUM_ROWS; i++)
arr[i] = (int*)malloc(NUM_COLS * sizeof(int));
方法2:
int** arr2 = (int**)malloc(NUM_ROWS * sizeof(int*));
int* arrflat = (int*)malloc(NUM_ROWS * NUM_COLS * sizeof(int));
for (int i = 0; i < dimension1_max; i++)
arr2[i] = arrflat + (i*NUM_COLS);
方法2基本上创建了一个连续的2D数组:即arrflat[NUM_COLS*i+j]
和arr2[i][j]
应具有相同的性能。但是,由于arrflat[NUM_COLS*i+j]
不是连续的,因此不应期望方法1中的arr[i][j]
和arr1
具有相同的性能。但是,方法1似乎是最常用于动态数组的方法。
一般来说,我使用arrflat[NUM_COLS*i+j]
所以我不必考虑如何分配动态2D数组。
答案 4 :(得分:0)
有两种情况需要考虑:编译时间定义和数组大小的运行时定义。性能差异很大。
静态分配,全局或文件范围,固定大小数组:
编译器知道数组的大小并告诉链接器在数据/内存部分中分配空间。这是最快的方法。
示例:
#define ROWS 5
#define COLUMNS 6
int array[ROWS][COLUMNS];
int buffer[ROWS * COLUMNS];
运行时分配,功能本地范围,固定大小数组:
编译器知道数组的大小,并告诉代码在数组的本地内存(a.k.a.堆栈)中分配空间。通常,这意味着向堆栈寄存器添加值。通常有一两条指令。
示例:
void my_function(void)
{
unsigned short my_array[ROWS][COLUMNS];
unsigned short buffer[ROWS * COLUMNS];
}
运行时分配,动态内存,固定大小数组:
同样,编译器已经计算了数组所需的内存量,因为它是以固定大小声明的。编译器发出代码以调用具有所需数量的内存分配函数(通常作为参数传递)。由于函数调用和查找一些动态内存(可能是垃圾收集)所需的开销,有点慢。
示例:
void another_function(void)
{
unsigned char * array = new char [ROWS * COLS];
//...
delete[] array;
}
运行时分配,动态内存,可变大小:
无论数组的大小如何,编译器都必须发出代码来计算要分配的内存量。然后将该数量传递给内存分配函数。由于计算大小所需的代码,比上面慢一点。
示例:
int * create_board(unsigned int rows, unsigned int columns)
{
int * board = new int [rows * cols];
return board;
}