将内存分配给 C 中的二维数组的最佳方法?

Best way to allocate memory to a two-dimensional array in C?

memory-managementspeed 这两个角度来看,为 C 中的 two-d array 分配内存的最佳方法是什么?

此外,two-d array(并为其分配内存)或 double pointer 哪个更好用?有人可以详细解释一下,里面发生了什么,为什么一个方法比另一个好?

给定一个固定的大小,你可以简单地说twoDimArray[100][100],这将在堆栈上分配它。然而,当在堆上分配时,(无论是因为大小非常大还是因为大小是动态的)你有更多的选择。

您可以分配一个指针数组,然后循环为每一行分配内存。这对于缓存局部性来说是有问题的,但是如果大小非常大并且您的访问是顺序的,那就很好了;它允许合理数量的碎片而不会对性能产生巨大影响,因为数组的数组可以与数组本身分开,每个数组可以彼此分开。在线性访问场景中,您 大部分 不会在内存区域之间跳转;相反,您甚至可以在移动到新区域之前访问整条线路。

第二种方式是将访问线性化,一次分配;即,为 sizex * sizey 分配足够的内存,然后用 (positiony * sizex) + positionx 索引它;也就是说,倒数一些行,然后跨过一些列。这对于随机访问非常有用,并且可以改善缓存局部性,因为内存是连续的,但如果没有足够的连续内存可用,它可能会失败(如果您需要的内存多于缓存,则缓存局部性优势不适用)。

data_type (*mat)[size_2] = malloc(size_1 * size_2 * sizeof(data_type));

这将为数组的数组(“二维数组”)分配连续的内存。如果您不需要可笑的1 数量的space,这就是您要走的路。您将减少内存碎片,提高缓存友好性并避免因使用 malloc.

而导致的过多开销

1 对于荒谬的某些(特定于应用程序的)定义

为了获得最佳性能和最佳可读性,此类数组应始终分配为连续的内存块:

type (*array) [X][Y] = malloc( sizeof(type[X][Y]) );

你应该避免这种情况:

// BAD METHOD, not a real array

type** lookup_table = malloc( X*sizeof(type*) );
for(size_t i=0; i<Y; i++)
{
  lookup_table[i] = malloc( Y*sizeof(type) );
}

前者更快,原因有很多。它分配在一个连续的内存块中,而不是在整个堆上分段。分段版本阻止了所有形式的代码优化和高效的片上数据缓存使用,而且实际分配也慢得多。

上面的 "bad" 版本有一个优点,那就是当您希望单个维度具有可变长度时,例如在查找 table 字符串时。然后你必须使用那个表格。但是如果你想要一个真正的二维数组,没有理由不使用前者。


注意第一个版本一般写成

type (*array) [Y] = malloc( sizeof(type[X][Y]) );

为了更方便地使用:array[i][j],而不是可读性较差的 (*array)[i][j]