在** my_vector和*** my_vector上应用free()之间的区别

我发现了一个释放矩阵记忆的函数:

void free_matrix(int ***matrix, int rows, int cols) {
    int row;

    if (matrix != NULL && *matrix != NULL) {
        for (row = 0; row < rows; row++) {
            free((*matrix)[row]);
            (*matrix)[row] = NULL;
        }
        free(*matrix);
        *matrix = NULL;
    }    
}

我这样称呼方法:

int **my_vector = create_matrix(5, 5);
free_matrix(&my_vector, 5, 5);

我不太明白为什么作者决定使用***矩阵而不是**矩阵,因为在我创建矩阵的其他方法中,他正是这样做的:

void fill_matrix(int **matrix, int rows, int cols) {
    int row = 0;
    int col = 0;

    for (row = 0; row < rows; row++) {
        for (col = 0; col < cols; col++) {
            matrix[row][col] = ((row + 1) * 10) + col;
        }
    }
}

int **create_matrix(int rows, int cols) {
    int row;
    int **matrix = malloc(rows * sizeof(int *));

    for (row = 0; row < rows; row++) {
        matrix[row] = malloc(cols * sizeof(int));
    }
    return matrix;
}

必须有一个原因,为什么突然作者决定使用int ***矩阵而不是int **矩阵.

最佳答案 作者传递矩阵指针的地址,以允许free_matrix矩阵在调用者的范围内将指针重置为NULL.它是一种防止在释放后访问矩阵数据的预防措施,但是如果调用者制作了矩阵指针的副本,它仍然可以通过副本访问它来调用未定义的行为.

正如Olaf所建议的那样,矩阵应该实现为2D数组,以便更简单地分配和释放:

/* allocating a pointer to a 2D array matrix[rows][cols] filled to 0 */
int (*matrix)[cols] = calloc(sizeof(*matrix), rows);
/* free the matrix */
free(matrix); matrix = NULL;

但是,如果大小不是常量,将这些矩阵作为函数参数传递所需的语法或更糟糕的返回它们并不是那么明显,需要符合C99的编译器.

为了澄清***方法的可疑优势,让我们来看看更常见的2星解决方案:

void free_matrix(int **matrix, int rows, int cols) {
    int row;

    if (matrix != NULL) {
        for (row = 0; row < rows; row++) {
            free(matrix[row]);
        }
        free(matrix);
    }    
}

int main(void) {
    int **my_vector = create_matrix(5, 5);
    fill_matrix(my_vector, 5, 5);
    free_matrix(my_vector, 5, 5);
    if (my_vector) {
        /* trying to access the freed data will invoke undefined behavior */
    }
    return 0;
}

在上面的代码中,free_matrix没有将my_vector重置为NULL,因此程序员可能会尝试访问它并调用未定义的行为(崩溃或其他任何东西),而在发布的代码中,三星级的free_matrix会将my_vector重置为NULL很容易测试.

点赞