指针的数组表示法

3
我制作了一个返回指向新创建矩阵的指针的函数。现在我想让这个函数返回类型为status_t的错误代码,而不是指针。为了实现这一点,必须添加另一个指针级别,并通过引用返回矩阵。然而,我不明白为什么会出现分段错误。这是我的工作代码的一部分(a),以及我的失败尝试(b):

(a)

int **create_matrix(size_t dimension) {
    int **p;
    size_t e;
    size_t h;

    if (dimension == 0)
        return NULL;

    for (h = 0; h < dimension; ++h) {
        if ((p[h] = malloc(dimension * sizeof(int))) == NULL) { 
            for (e = h; e >= 0; --e) {  
                free(p[e]);
                p[e] = NULL;
            } <-------- missing closing brace
            return NULL;
        }
    }
    return p;
}
(b)
status_t create_matrix(size_t dimension, int ***p) {
    size_t e;
    size_t h;

    if (p == NULL)
        return ERROR_NULL_POINTER;

    for (h = 0; h < dimension; ++h) {
        if (((*p)[h] = malloc(dimension * sizeof(int))) == NULL) { 
            for (e = h; e >= 0; --e) {  
                free((*p)[e]);
                (*p)[e] = NULL;
            } <-------- missing closing brace
            return ERROR_NO_MEMORY;
        }
    }
}

谢谢!


当你创建矩阵时,为什么要调用free()函数? - Andrew Henle
如果内存分配函数 malloc 失败了,那么就会出现内存泄漏。我正在努力避免这种情况。 - Juan Hirschmann
1个回答

3

(a) 并没有完全“运作”:

首先,它有更多的 {},所以它甚至无法编译。您可能忘记了终止外部的 for 循环。

int ** p;
...
    if ((p[h]=...))

这里将在初始化之前对p解除引用。使用未初始化变量的值是未定义行为。在使用它之前,您需要为p分配一个值(可能是通过动态分配另一个数组)。

要确定版本(b)是否存在相同的问题,我们需要看到调用代码,但猜测它也是UB。

内部循环中还有另一个问题:

        for (e = h; e >= 0; --e)

e 是一个无符号整数类型 size_t,因此条件 e >= 0 总是成立。

你使用的编译器(及编译选项)是什么?使用 gcc -Wall -Wextra -pedantic 我得到了这两个都有警告

修正后的代码应该是这样的:

int **create_matrix(size_t dimension) {
    int **p = calloc(dimension, sizeof *p);
    if (!p) {
        return NULL;
    }

    for (size_t i = 0; i < dimension; i++) {
        if (!(p[i] = calloc(dimension, sizeof *p[i]))) {
            while (i--) {
                free(p[i]);
            }
            free(p);
            return NULL;
        }
    }

    return p;
}

版本(b)可以定义为:
status_t create_matrix_2(size_t dimension, int ***p) {
    if (!p) {
        return ERROR_NULL_POINTER;
    }
    if (!(*p = create_matrix(dimension))) {
        return ERROR_NO_MEMORY;
    }
    return SUCCESS_OR_SOMETHING;
}

我不确定你希望返回什么表示成功; 你的版本(b)那里缺少了一个返回语句。

你说得对,*p[e] 是我在发帖时打错的,我会进行编辑。我正在使用gcc版本7.4.0,并使用标志“-ansi -pedantic -Wall”。我不明白你所说的p在初始化之前被解引用是什么意思,我该如何解决这个问题?谢谢。 - Juan Hirschmann
1
@JuanHirschmann 看看我的修正版。在使用 p 的值之前,你需要先给 p 赋一个值。这有什么不清楚的吗? - melpomene
@JuanHirschmann 我已经从我的答案中删除了*p[e]这部分,但我发现另一个问题:e >= 0 总是为真。 - melpomene

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