【问题标题】:Properly free dynamically allocated struct正确释放动态分配的结构
【发布时间】:2015-06-21 09:51:55
【问题描述】:

我已经阅读了几个针对类似问题给出的答案,但有一件事使我的案例与我所阅读的内容略有不同。我使用链表来存储数据,以供线程选择和处理。一个节点就是一个简单的typedef

struct QueueNode;

typedef struct QueueNode {
    struct QueueNode* next; // pointer to the next node
    void* data;
} QueueNode;

名单

typedef struct LinkedQueue {
    QueueNode* head;   // pointer to the first Node
    QueueNode* tail;   // pointer to the last Node
    long long k;       // the number of nodes in the queue
} LinkedQueue;

两者都由使用malloc 的相应函数初始化。当一个线程需要处理数据时,它调用一个弹出队列头部并返回void* data 指针的函数。

void* pop_data(LinkedQueue* queue) {
    /*
     Pops the head node from a queue, extracts data out of it and
     frees the memory allocated by that node
     */
    assert(queue->head && "Can't pop data from an empty queue");

    void* data = queue->head->data;            // extract data from head
    QueueNode* old_head_pointer = queue->head;
    queue->head = queue->head->next;           // replacing head with a new one
    destroy_node(old_head_pointer);            // destroying the old head

    return data;
};

问题是destroy_node 应该在不破坏void* data 指针的情况下释放为节点分配的内存,因为稍后会使用数据。这是我的情况变得不同。我已经阅读过的所有示例都描述了一个完全释放节点内所有内容的情况,而我需要保存那个指针。

void destroy_node(QueueNode* node) {
    /*
     Frees memory allocated by a node.
     */
    free(node->next);
    free(node);
};

在我的测试中这很好用,但是因为我知道 free() 实际上并没有擦除这块内存,而且由于我的机器有大量内存,所以我仍然可以访问 void* data 指针而无需任何分段不能依赖错误。所以问题基本上是我做对了还是我的担忧真的合理?如果这确实可能导致内存泄漏或其他与内存相关的问题,我该怎么做?

【问题讨论】:

  • 使用您显示的代码,您可以释放新的head 指针。不要免费node->next
  • struct QueueNode 在整个代码中是一个不完整的类型...也许是一个无关紧要的错误,但仍然是一个错误,尤其是当您尝试取消引用 next 成员时。我可以建议在typedef struct 之后直接插入QueueNode 吗?
  • 实际代码中实际上定义为typedef struct QueueNode {...,但我很欣赏这个注释。
  • 一般来说,对结构进行类型定义是个坏主意。对结构进行类型定义只会弄乱代码,弄乱编译器名称空间,并且在维护代码时(可能是几年后)可能会导致误解。
  • @user3629249 你能详细说明一下吗?到目前为止,我看到的每个教程都显示类型定义结构是正常的。

标签: c pointers struct


【解决方案1】:

您做得对,因为您在释放整个节点之前访问了data 指针。做相反的事情将是一个逻辑错误。 不会发生内存泄漏,前提是您在代码稍后的某个位置实际释放了数据。

但是,您不应该释放节点的 next 字段,因为它也会使该节点无效,这可能不是您想要做的。

【讨论】:

  • 我不应该在pop_data函数中为void* data指针动态分配空间并显式复制指针吗?据我所知,data 是一个局部变量,如果它未声明为 static 或动态分配,它会在 return 上被释放。
  • data 确实是一个局部变量。但它的内容可能是malloc 调用的返回值,并且仍然有效。它是返回给调用者的内容的地址,就像您可以毫无问题地返回来自局部变量的整数值一样。
【解决方案2】:

如果要保留指向“数据”的指针,

然后在调用 'destroy_node()' 之前将该指针保存到局部变量中

destroy_node() 函数对 'void *Data' 指向的内存没有任何影响。

正如其他地方提到的,不要释放()'next'指针,因为这实际上释放了链表中的下一个节点('head'刚刚被设置为指向)

这意味着“head”现在指向未分配的内存。

对该未分配内存的任何引用都会导致未定义的行为。

这种未定义的行为可能导致任何事情,包括段错误事件。

所有编译操作都应该在启用大多数/所有警告的情况下执行。

启用警告后,发布的代码将引发 2 个警告。

每个警告说:

ISO C does not allow extra ';' outside of a function

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-10-20
    • 2018-10-21
    • 1970-01-01
    • 2023-03-10
    • 2022-01-13
    • 1970-01-01
    • 2012-11-03
    相关资源
    最近更新 更多