【问题标题】:int matrix with pointers in C - memory allocation confusion带有 C 中指针的 int 矩阵 - 内存分配混乱
【发布时间】:2010-09-11 11:07:18
【问题描述】:

我在生成 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]);
}

【问题讨论】:

    标签: c pointers memory-management matrix


    【解决方案1】:

    您需要单独释放每一行:

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

    【讨论】:

    • 不能在C的for循环中声明变量。
    【解决方案2】:

    您只释放了 first_matrix 的第一行(或列)。像这样写另一个函数:

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

    您可能希望将矩阵制作成一个结构来存储它的行数和列数。

    【讨论】:

      【解决方案3】:

      释放内存并不会让它消失,它只是意味着另一个分配可能会占用相同的内存块。无论你放入什么,它都会一直存在,直到有其他东西覆盖它。

      另外,你并没有释放你分配的所有东西。您只释放指针数组和第一行。但是即使你正确地释放了所有东西,你仍然会有同样的效果。

      如果您想创建“总线错误”,您需要指向不属于您的进程的内存。你为什么要这样做?

      【讨论】:

      • 我只是想这样做以表明内存是空闲的,但现在我知道问题出在我的想法中,由于我在 OS X 上并且想要一种方法来运行 valgrind看看我是否真的释放了它
      【解决方案4】:

      我建议使用 valgrind 来追踪未释放的内存,而不是试图让总线错误发生。它也适用于很多其他的东西。

      山姆

      【讨论】:

      • 我在 OS X 上,所以我不能运行 valgrind,否则我会:/你知道任何在 mac 上工作的替代方案吗?
      【解决方案5】:

      您会出现内存泄漏,因为您要释放矩阵的第一行和行列表,但没有释放第 1 到第 n 行。你需要循环调用free。

      不过,有几种选择: - 分配 sizeof(int*)rows + rowscols*sizeof(int) 字节并使用第一个字节作为行指针。这样,你只有一块内存可以释放(而且在分配器上也更容易) - 使用包含行数的结构。然后你可以完全避免行列表(节省内存)。唯一的缺点是您必须使用函数、宏或一些杂乱的符号来处理矩阵。

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

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

      【讨论】:

        【解决方案6】:

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

        请注意,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 );
        

        【讨论】:

        • 似乎循环直到 matrix[i] != NULL 工作,即使我没有将最后一个指针设置为 NULL,这是巧合/其他不好的吗?
        • 如果你分配了一个额外的指针并且没有设置它,它可能默认为 NULL,这取决于操作系统(Windows 将分配的内存归零,Unix 不会) .如果不是,你将跑出分配数组的末尾并继续释放东西,直到你碰巧碰到一个 NULL 指针或(更有可能)崩溃。
        • calloc 总是将内存设置为空。
        【解决方案7】:

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

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

        for(int i = 0;i

        然后,一旦完成,释放 this 分配的指针。

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

        你现在的做法,

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

        不会做你想让它做的事情。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-12-11
          • 1970-01-01
          • 2018-08-11
          • 2016-02-21
          • 2016-01-25
          相关资源
          最近更新 更多