在 C 中取消分配二维数组

Deallocating 2D array in C

无论出于何种原因,我在尝试释放我创建的二维数组时遇到以下错误:

Error in `./a.out': free(): invalid next size (fast): 0x0000000001759310 *** Aborted (core dumped)

我打印出数组的内容,它们是正确的,我可以访问所有元素。但是,我还不能释放它。通过释放循环时会发生错误,即释放双*。非常感谢任何帮助。

谢谢!

代码如下:

/*allocation*/
double **block_mat = (double **) malloc (sizeof(double *) * num_blocks);
int i;
for (i = 0; i <num_blocks; i++){
    block_mat[i] = (double *) malloc (sizeof(double) * s);
}

/*freeing*/
for (i = 0; i < num_blocks; i++){
    free(block_mat[i]);
}

免费(block_mat);

编辑: 发现错误!我分配的内存不足......所以当我打印出我的数组时,它们看起来一切都很好......我分配了大小为 s 的数组,但改为使用 s^2。谢谢大家!

这是不正确的:

free(my_matrix);
free(my_matrix->vals);
free(my_matrix->cols);
free(my_matrix->rows);

顺序至少应该是这样的:

free(my_matrix->vals);
free(my_matrix->cols);
free(my_matrix->rows);
free(my_matrix);

你确定这些指针都是用不同的 mallocs 分配的吗?

free(my_matrix->vals);
free(my_matrix->cols);
free(my_matrix->rows);
free(my_matrix);
for (i = 0; i < num_blocks; i++){
    free(block_mat[i]);
}
free(block_mat);

如果其中两个是同一个指针,那么您正在尝试释放某物两次。

您为每个 block_mat[i]s 双打分配 space。稍后,您访问

block_mat[i][block_index] = 0;
block_index++;

但你永远不会检查 block_index 是否越界,但确实如此。

如果写入超过 s 分配的双精度数,则可能会破坏后续指针的内部控制数据,该指针通常位于 malloc 返回的指针之前,并且需要free.

完好无损

您有几个问题会影响分配。第一,如果调用 strtol 失败怎么办?

    s = (int)strtol(argv [3], &ptr, 10);

您应该检查转换:

#include <errno.h>
...
else {
    errno = 0;
    long tmp = strtol(argv [3], &ptr, 10);
    if ((errno == ERANGE && (tmp == LONG_MIN || tmp == LONG_MAX)) ||
        (errno != 0 && tmp == 0)) {
        perror ("strtol");
        exit (EXIT_FAILURE);
    }

    if (ptr == argv[3]) {
        fprintf (stderr, "No digits were found\n");
        exit (EXIT_FAILURE);
    }
    s = (int)tmp;
}

接下来,通过分配和释放,您走在了正确的轨道上,但是不要使用 malloc 的 return。投射 return 只会增加难以调试错误的机会。在分配指针到指针到双精度的指针时,您需要根据需要分配尽可能多的指针。 (num_blocks) 在你的情况下。在计算分配的大小时,您可以简单地取消引用正在分配的变量,这再次减少了出错的机会:

int i;
double **block_mat = malloc (sizeof *block_mat * num_blocks);
/* check allocation for failure */

for (i = 0; i <num_blocks; i++){
    block_mat[i] = malloc (sizeof **block_mat * s);
    /* check allocation for failure */
}

/*freeing*/
for (i = 0; i < num_blocks; i++){
    free (block_mat[i]);
}
free(block_mat);

注意: 您必须在开始引用元素之前初始化 block_mat 中的所有值,以防止以后引用未分配的值。 (例如 double result = block_mat[i][j] * Pi;)考虑添加:

    block_mat[i] = malloc (sizeof **block_mat * s);
    /* check for failure */
    block_mat[i] = 0.0;

注意:分配数值矩阵时,考虑使用calloc而不是malloc,因为它会将所有值初始化为'0'并防止无意中取消引用未赋值的值——这是 未定义的行为。使用 calloc 你会得到:

int i;
double **block_mat = calloc (num_blocks, sizeof *block_mat);
/* check allocation for failure */

for (i = 0; i <num_blocks; i++){
    block_mat[i] = calloc (s, sizeof **block_mat);
    /* check allocation for failure */
}

/*freeing*/
for (i = 0; i < num_blocks; i++){
    free (block_mat[i]);
}
free(block_mat);

注意:s 大于 1 时,您将在每个指针处分配 space 多于一个双精度值。注意会阻止您这样做,但您有责任处理每个值的偏移量。 (例如 result = *(block_mat[i] + j + n * sizeof **block_mat) * Pi;,其中 n 是 0 <= n < s)如果您在每个指针中存储多个双精度数,请考虑改用 pointer-to-struct。例如:

typedef struct point {
    double x;
    double y;
    double z;
} point;