动态内存分配问题(在C语言中)

3

考虑以下代码:

#include <stdio.h>
#include <malloc.h>

void allocateMatrix(int **m, int l, int c)
{
    int i;

    m = (int**) malloc( sizeof(int*) * l );
    for(i = 0; i < l; i++)
        m[i] = (int*) malloc( sizeof(int) * c );
}

int main()
{
    int **m;
    int l = 10, c = 10;
    allocateMatrix(m, l, c);
    m[0][0] = 9;
    printf("%d", m[0][0]);

    return 0;
}

上面的代码会生成内存分配错误并崩溃。

但下面的代码将正确地工作,问题是:为什么?

#include <stdio.h>
#include <malloc.h>

int** allocateMatrix(int l, int c)
{
    int i;

    int **m = (int**) malloc( sizeof(int*) * l );
    for(i = 0; i < l; i++)
        m[i] = (int*) malloc( sizeof(int) * c );
    return m;
}

int main()
{
    int **m;
    int l = 10, c = 10;
    m = allocateMatrix(l, c);
    m[0][0] = 9;
    printf("%d", m[0][0]);

    return 0;
}

我无法理解为什么第一段代码会崩溃,因为我只是将指向指针m(保存矩阵第一个内存地址的变量)作为参数传递。实际上,我没有看到这两段代码有任何不同之处。希望能得到任何清晰的解释。

谢谢, Rafael Andreatta


malloc.h 是错误的。mallocstdlib.h 中定义。 - R.. GitHub STOP HELPING ICE
4个回答

7
在第一个示例中,您没有初始化m。您只是更改了它的副本。换句话说,调用者将永远看不到您对m所做的更改。
在第二个示例中,您分配内存,然后返回指向该内存的指针。这是有效的。
您可以尝试通过以下方式修复第一个示例(未经测试但应该有效):
void allocateMatrix(int ***m, int l, int c)
{
    int i;

    *m = malloc( sizeof(int*) * l );
    for(i = 0; i < l; i++)
        (*m)[i] = malloc( sizeof(int) * c );
}


/* ... */

allocateMatrix(&m, l, c);

编辑

我花了一些时间,但我找到了它。通常情况下,C FAQ 对此有所说明。


也许这个答案可以加上一个关于作用域的评论,解释为什么第一个例子不起作用。 - cthom06
让我看看是否理解正确。当我将变量作为参数传递给函数时,在函数内部我正在创建新变量(即参数),并将从传递的变量复制到为参数创建的变量中。我是对的吗?因此,在这种情况下,如果在传递变量m之前没有初始化它,则allocateMemory中的int **m将具有随机值(主函数中int **m获得的垃圾值)。唯一不明白的是,如果在传递参数之前初始化int **m,为什么它会起作用...谢谢。 - rafaame
@rafaame 我认为你已经正确理解了第一部分。对于第二部分,如果在调用函数之前初始化 m,那么在函数完成后,它将包含有效内存的地址,而不是“垃圾值”。 - cnicutar

1
函数allocateMatrix接收传递变量m的副本,而不是从主函数传递的变量。因此,在第一个示例中,m未初始化,当您尝试访问它时,会出现分段错误。

1

这是一个棘手的问题,发生在以下情况下:

void allocateMatrix(int **m, int l, int c);

你的间接级别有误。如果你传递一个指针,实际上传递的是指向值的引用。然而,实际的指针值被复制到堆栈上,即仍然是按值传递。因此,你的分配函数有一个堆地址的本地副本,但在前面的范围内,它从未重新分配给m

要解决这个问题,你可以使用第二种情况或者这种方法:

void allocateMatrix(int ***m, int l, int c)
{
    int i;
    *m = (int**) malloc( sizeof(int*) * l );
    for(i = 0; i < l; i++)
        (*m)[i] = (int*) malloc( sizeof(int) * c );
}

并通过 &m

我还想指出,在C语言中,你最好不要转换malloc的结果,尽管在C++中是必须的。请参见this answer


在C语言中,强制类型转换通常被认为是有害的。 - R.. GitHub STOP HELPING ICE

0

因为在第一个例子中,主函数中的变量m没有被改变。要改变它,你必须将它作为引用(在C++中)或指针(在普通C中)传递。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接