C中具有指针的int矩阵-内存分配混乱

时间:2020-03-06 14:27:52  来源:igfitidea点击:

我在生成int矩阵而不产生内存泄漏时遇到了一些问题。我希望能够通过read_matrix()将给定的(全局)矩阵动态地调整为任意大小。但后来我希望以后可以释放内存。因此,在我的主要方法中,第二个printf应该导致总线错误,因为它没有分配任何内存。我将如何创建这个?

int**       first_matrix;
int**       second_matrix;
int**       result_matrix;

int** read_matrix(int size_x, int size_y)
{
    int** matrix;
    matrix = calloc(size_x, sizeof(int*));
    for(int i = 0;i<size_x;i++) {
        matrix[i] = calloc(size_y, sizeof(int));
    }
    for(int i = 0;i<size_x;i++) {
        for(int j = 0;j<size_y;j++) {
            matrix[i][j] = i*10+j;
        }
    }
    return matrix;
}

int main(int stackc, char** stack)
{
    first_matrix = read_matrix(10,10);
    printf("9:3 %d - 4:6 %d \n", first_matrix[9][3], first_matrix[4][6]);
    free(*first_matrix);
    free(first_matrix);
    printf("9:3 %d - 4:6 %d \n", first_matrix[9][3], first_matrix[4][6]);
}

解决方案

我们需要分别释放每一行:

void free_matrix(int **matrix, int size_x)
{
    for(int i = 0; i < size_x; i++)
        free(matrix[i]);
    free(matrix);
}

我们只释放了first_matrix的第一行(或者列)。编写这样的另一个函数:

void free_matrix(int **matrix, int rows)
{
    int i;
    for(i=0; i<rows; i++)
    {
        free(matrix[i]);
    }
    free(matrix);
}

我们可能需要将矩阵制作为结构以存储其行数和列数。

释放内存并不能消除它,只是意味着另一个分配可能会抢占相同的内存。无论我们输入什么内容,它都会一直存在,直到其他内容将其覆盖。

另外,我们不会释放分配的所有内容。我们只释放了指针数组和第一行。但是,即使我们正确释放了所有内容,我们仍然会获得相同的效果。

如果要创建"总线错误",则需要指向不属于进程的内存。我们为什么仍要这样做?

我建议使用valgrind来跟踪未释放的内存,而不是尝试使总线出错。它也可以用于其他很多东西。

山姆

之所以会出现内存泄漏,是因为释放了矩阵的第一行和行列表,但没有释放第1到第n行。我们需要循环免费通话。

但是,有两种选择:
分配sizeof(int *)行+行cols * sizeof(int)字节,并将第一个字节用作行指针。这样,我们只有一小块内存可以释放(而且在分配器上也更容易)
使用包含行数的结构。然后,我们可以完全避免使用行列表(节省内存)。唯一的缺点是我们必须使用函数,宏或者一些混乱的符号来表示矩阵。

如果使用第二个选项,则可以在任何C99编译器中使用这样的结构,并且再次只需分配一个内存块(大小为numints * sizeof(int)+ sizeof(int)):

struct matrix {
    int rows;
    int data[0];
}

仅仅因为内存已释放并不意味着我们无法访问它!当然,在释放它之后访问它是一个非常糟糕的主意,但这就是为什么它在示例中起作用。

注意,free(* first_matrix)仅释放first_matrix [0],而不释放其他数组。我们可能想要某种标记来表示最后一个数组(除非我们总是知道释放外部数组时分配了多少内部数组)。就像是:

int** read_matrix(int size_x, int size_y)
{
    int** matrix;
    matrix = calloc(size_x, 1+sizeof(int*)); // alloc one extra ptr
    for(int i = 0;i<size_x;i++) {
        matrix[i] = calloc(size_y, sizeof(int));
    }
    matrix[size_x] = NULL; // set the extra ptr to NULL
    for(int i = 0;i<size_x;i++) {
        for(int j = 0;j<size_y;j++) {
            matrix[i][j] = i*10+j;
        }
    }
    return matrix;
}

然后,当我们释放它们时:

// keep looping until you find the NULL one
for( int i=0; first_matrix[i] != NULL; i++ ) {
    free( first_matrix[i] );
}
free( first_matrix );

我们在这里缺少的概念是,对于每个calloc,都必须有一个免费的。
并且必须将free应用于从calloc传回的指针。

我建议我们创建一个函数(名为delete_matrix)
使用循环释放我们在此处分配的所有指针

for(int i = 0; i <size_x; i ++){
matrix [i] = calloc(size_y,sizeof(int));
}

然后,一旦完成,就释放由此分配的指针。

矩阵= calloc(size_x,sizeof(int *));

我们现在的做法,

免费(* first_matrix);
免费(first_matrix);

不会做你想做的事。