【问题标题】:sorry should not display抱歉不应该显示
【发布时间】:2017-12-11 03:39:56
【问题描述】:

抱歉代码无法显示

【问题讨论】:

  • . 和箭头-> 操作符绑定得非常紧密,它们周围不应该有空格。
  • 要回答你的标题问题,对于每个malloc(),以大致与分配相反的顺序写一个免费的。释放单元格行。释放保存行的指针数组。释放结构。考虑是否可以减少分配的数量,但仍然为每个分配写一个免费的。
  • @JonathanLeffler 出于好奇,以“大致相反的顺序”释放有什么改进?
  • @JacekCz.:free(NULL) 没有问题标准接受它。 如果 ptr 是空指针,则不执行任何操作。
  • @JacekCz:进一步研究,free(maze);maze = malloc(…) 失败时的错误恢复是毫无意义的——无害,但毫无意义。释放空指针是安全的——它被定义为无操作。

标签: c


【解决方案1】:

给定一个分配器函数,释放器会自行写入 - 您按照与分配指针大致相反的顺序释放指针。

因此,鉴于分配器是(仅从问题重新格式化 - 功能不变):

Maze *malloc_maze(int num_rows, int num_cols)
{
    Maze *maze = malloc(sizeof(*maze));
    if (maze == NULL)
    {
        free(maze);
        return NULL;
    }
    maze->cells = malloc(sizeof(maze->cells) * (num_cols));

    if (maze->cells == NULL)
    {
        free(maze);
        return NULL;
    }
    for (int i = 0; i < num_cols; i++)
    {
        maze->cells[i] = malloc(sizeof(*(maze->cells)) * (num_rows));
    }
    maze->num_rows = num_rows;
    maze->num_cols = num_cols;
    return maze;
}

释放器应该是:

void free_maze(Maze *maze)
{
    for (int i = 0; i < num_cols; i++)
        free(maze->cells[i]);
    free(maze->cells);
    free(maze);
}

这可确保代码在释放内存后不会尝试访问内存。


但是,对分配器的仔细分析表明存在一些(小)问题。例如,通常您将索引对视为maze-&gt;cells[row][col],但内存分配要求将其用作maze-&gt;cells[col][row]。两者都可以工作,但行列顺序在 C 中更常见。此外,第二个和第三个 malloc() 调用中的大小不正确。幸运的是,第二个以sizeof(char **) 而不是sizeof(char *) 为单位分配,但它们的大小相同,所以“没关系”。第三个分配sizeof(char *)单位,而不是sizeof(char),因此分配的内存比内存多得多(通常sizeof(char *)是4或8个字节,但sizeof(char)定义为1)。

因此,您最好使用它,它保留maze-&gt;cells[col][row] 访问符号:

Maze *malloc_maze(int num_rows, int num_cols)
{
    Maze *maze = malloc(sizeof(*maze));
    if (maze == NULL)
        return NULL;
    maze->cells = malloc(sizeof(maze->cells[0]) * num_cols);
    if (maze->cells == NULL)
    {
        free(maze);
        return NULL;
    }
    for (int i = 0; i < num_cols; i++)
    {
        maze->cells[i] = malloc(sizeof(maze->cells[0][0]) * num_rows);
        if (maze->cells[i] == 0)
        {
            for (int j = 0; j < i; j++)
                 free(maze->cells[j]);
            free(maze->cells);
            free(maze);
            return NULL;
        }
    }
    maze->num_rows = num_rows;
    maze->num_cols = num_cols;
    return maze;
}

这会在分配失败时清理部分分配的内存。它不会改变释放代码(除非你想添加一个空检查,但如果分配失败,你不应该调用释放代码)。

【讨论】:

  • @coderredoc:是的;见答案的修正。它实际上是“安全的”;分配了(超过)足够的内存。但是尺寸错了,两次。
  • 谢谢,您的解释很有帮助。我对在堆上使用内存还很陌生,所以完整的解释对帮助完成代码的最后部分大有帮助。
【解决方案2】:

注意:我相信在 OP 的情况下,代码会自动处理对齐。我仍在努力调整它以使用Maze 成员的任何数据类型。如果sizeof(char*) 超过sizeof(T),则对齐将被破坏,其中Tcell[0][0] 的类型。

您可以在一个malloc 调用中为整个迷宫分配内存。这将允许您在一个free 调用中释放内存。它提高了性能,因为:

  • 它需要一个 malloc(和 free)调用
  • 分配的内存是连续的(缓存友好)

Maze *malloc_maze(int num_rows, int num_cols)
{
    const size_t mem_size = sizeof(Maze)
                        + num_cols*sizeof(((Maze*)0)->cells[0]) /* indirection array */
                        + sizeof((((Maze*)0)->cells[0][0]))*num_cols*num_rows; /* matrix */

    void *block = malloc(mem_size);
    if(block == NULL)
        return NULL;

    Maze *maze = block;
    maze->cells = (void*)(maze + 1);
    block = &maze->cells[0] + num_cols;
    for(int i = 0; i < num_cols; i++)
    {
        maze->cells[i] = block; 
        block = &maze->cells[i][0] + num_rows;
    }
    
    maze->num_rows = num_rows;
    maze->num_cols = num_cols;
    return maze;
}
void free_maze(Maze *maze)
{
    free(maze);   
}

【讨论】:

  • "你可以在一次 malloc 调用中为整个迷宫分配内存。" 如果代码考虑了maze-&gt;cellsmaze-&gt;cells[i] 的对齐要求,这是正确的,但它没有。这会导致未定义的行为 (UB)。
  • 我不明白需要什么对齐要求。
  • 您对对齐要求的理解是什么?
  • 我完全不知道你在说什么。我所知道的是我需要一个主要维度大小的间接数组,其中每个元素都指向一个数据数组。
  • @chux 我现在从SO answer 得到了一个大概的想法。你能引用一个我可以详细理解的好资源吗?我会尽快学习并更新答案。
猜你喜欢
  • 2015-06-24
  • 2017-12-12
  • 2012-10-06
  • 2023-02-20
  • 1970-01-01
  • 2014-03-10
  • 1970-01-01
  • 2023-04-07
  • 2012-01-11
相关资源
最近更新 更多