malloc的两种方法的区别

时间:2015-11-02 21:29:39

标签: c

我想创建5 * 5 2D Matrix。我通常使用以下内存分配方式:

int **M  = malloc(5 * sizeof(int *));
for (i = 0; i < 5; i++)
{
    M[i] =  malloc(5 * sizeof(int));
}

在我阅读博客时,我发现了另一种方法:

int **M = malloc(5 * sizeof(int*));
M[0] = malloc((5*5) * sizeof(int));

我的问题是:两种方法有什么区别?哪一个效率更高?

6 个答案:

答案 0 :(得分:5)

对于第二个代码,请注意您需要初始化其他数组成员才能使其正常工作:

    for (int i = 1; i < 5; i++) {
        M[i] = M[0] + i * 5;
    }

所以在第二个代码中,数组成员(通过所有数组)是连续的。访问它们没有任何区别(例如,您仍然使用M[i][j]语法访问它们)。它优于第一个代码,只需要两个malloc调用,并且在评论中提到有利于缓存,这可以大大提高访问性能。

但是如果你打算动态分配大型数组,最好使用第一种方法,因为内存碎片(大的连续内存分配可能不可用或者会加剧内存碎片)。

这种动态分配数组数组的类似例子可以在c-faq中找到:http://c-faq.com/aryptr/dynmuldimary.html

答案 1 :(得分:5)

在看到ouah的答案并看到C FAQ中的示例后,我现在明白了第二种技术的来源,尽管我个人不会在可以帮助它的地方使用它。

您展示的第一种方法的主要问题是数组中的行不保证在内存中相邻; IOW,紧跟在M[0][4]之后的对象不一定是M[1][0]。如果从不同页面分配了两行,则可能会降低运行时性能。

第二种方法保证所有行都是连续分配的,但您必须手动指定M[1]M[4]才能使正常M[i][j]下标工作,如

for ( size_t i = 0; i < 5; i++ )
  M[i] = M[i-1] + 5;

IMO与以下相比,这是一种笨拙的方法:

int (*M)[5] = malloc( sizeof *M * 5 );

这也保证了内存是连续分配的,M[i][j]下标可以不需要任何进一步的工作。

但是,有一个缺点;在不支持可变长度数组的编译器上,必须在编译时知道数组大小。除非您的编译器支持VLA,否则您无法执行类似

的操作
size_t cols;
...
int (*M)[cols] = malloc( sizeof *M * rows );

在这种情况下,M[0] = malloc( rows * cols * sizeof *M[0])然后手动分配M[1]M[rows - 1]将是一个合理的替代品。

答案 2 :(得分:4)

我希望我不会在这里遗漏一些东西,但是我试图回答这个问题&#34;有什么区别......&#34;。如果我完全偏离基础,原谅我,我会纠正我的答案,但这里是:

我试图弄清楚你的两个mallocs中发生了什么,所以我要说的是与我手工绘制的图片(手工制作的答案?)相关联。

第一个选项:

对于第一个选项,您将分配一个大小为5 int * s的内存块。 M,这是一个int **指向该内存块的开头。

然后,遍历每个内存块(int *的大小),并在每个块中放入大小为5 int的内存块的地址。请注意,它们位于内存的一些随机部分(堆)中,有足够的空间可以占用5个整数。

这是关键 - 它是一个不连续的内存块。因此,如果您将内存视为数组,则指向数组中的不同起始位置。

第二个选项

你的第二个int **的分配完全相同。但相反,它分配 25 整数的大小并返回将该数组的地址放在内存块M [0]中。注意:您从未在内存位置M [1] - M [4]中放置任何地址。

那么,会发生什么?你有一个25个整数的连续块,其地址可以在M [0]中找到。当你尝试获得M [1]时会发生什么?你猜对了 - 它是空的或包含垃圾值。更重要的是,它是一个不指向已分配内存空间的值,因此您可以使用Segfault。

enter image description here

答案 3 :(得分:3)

如果要在连续内存中分配5x5数组,正确的方法是

int rows = 5;
int cols = 5;
int (*M)[cols] = malloc(rows * sizeof(*M));

然后,您可以使用正常的数组索引访问该数组,例如

M[3][2] = 6;

答案 4 :(得分:1)

int **M = malloc(5 * sizeof(int *));指的是为指针分配内存M[i] = malloc(5 * sizeof(int));指的是为int变量分配内存。

也许这会帮助您了解正在发生的事情:

int **M  = malloc(5 * sizeof(void *));
/* size of 'void *' and size of 'int *' are the same */
for (i = 0; i < 5; i++)
{
    M[i] =  malloc(5 * sizeof(int));
}

答案 5 :(得分:0)

使用malloc((5*5) * sizeof(int));时的另一个小差异。当然是OP正在寻找的一个侧面问题,但仍然是一个问题。

以下两个与2个操作数的顺序相同仍然导致产品使用size_t数学。

#define N 5
malloc(N * sizeof(int));
malloc(sizeof(int) * N);

考虑一下:

#define N some_large_value
malloc((N*N) * sizeof(int));

sizeof()的结果类型是类型size_t,无符号整数类型,肯定有SIZE_MAX >= INT_MAX,可能更大。所以要避免int溢出不会溢出size_t数学使用

malloc(sizeof(int) * N * N);