释放结构内部的指针(到void *)

时间:2015-05-03 22:12:56

标签: c

C新手在这里,我似乎无法想出这个。所以我开始实现一个链表(只是一些基本的东西,所以我可以把它包围起来),我遇到了麻烦。该程序运行正常,但我无法释放()存储在我的结构中的数据。

这是来源:

#include <stdio.h>
#include <stdlib.h>

struct node {
    struct node* next;
    void* data;
    size_t data_size;
};
typedef struct node node;

node* create_node(void* data, size_t size)
{
    node* new_node = (node*)malloc(sizeof(node));
    new_node->data = (void*)malloc(size);
    new_node->data = data;
    new_node->next = NULL;
    return new_node;
}
void destroy_node(node** node)
{
    if(node != NULL)
    {
        free((*node)->next);
        //this line here causes the error
        free((*node)->data);
        free(*node);
        *node = NULL;
        printf("%s\n", "Node destroyed!");
    }
}

int main(int argc, char const *argv[])
{
    float f = 4.325;
    node *n;

    n = create_node(&f, sizeof(f));
    printf("%f\n", *((float*)n->data));

    if (n->next == NULL)
        printf("%s\n", "No next!");

    destroy_node(&n);
    return 0;
}

我在程序输出中收到此消息:

  

malloc:***对象0x7fff5b4b1cac的错误:释放的指针未分配

我并不完全热衷于如何解决这个问题。

3 个答案:

答案 0 :(得分:4)

这是因为当你这样做时:

new_node-&gt; data = data;

您将之前的行替换malloc放置的值。 您需要的是复制数据,请参阅函数memcpy

答案 1 :(得分:3)

node* create_node(void* data, size_t size)
    ...
    new_node->data = (void*)malloc(size);
    new_node->data = data;

这里,(1)你正在丢失malloc给出的内存,因为第二个赋值会替换存储未知来源指针的地址(2)。

第二个很重要,因为你不能保证data指向的内存实际上是malloced。在destroy_node中释放数据成员时,这会导致问题。 (在给定的示例中,正在释放堆栈中的地址)

要修复它,请用

替换第二个作业
memcpy (new_node->data, data, size);

destroy_node函数中还有一个潜在的 double free ,因为next成员也被释放了。

在链表中,通常一个节点在从列表中取消链接后被释放,因此不应释放下一个节点,因为它仍然可以从被取消链接的节点的前任访问。

答案 2 :(得分:1)

虽然你得到了直接问题的答案,但代码还存在许多其他问题。

struct node {
    struct node* next;
    void* data;

将*放在类型名称旁边是什么意思?无论如何你都使用它不一致,因为在主节点你有节点* n。

    size_t data_size;
};
typedef struct node node;

node* create_node(void* data, size_t size)
{
    node* new_node = (node*)malloc(sizeof(node));

你在为什么投射malloc?它是有害的。你应该使用sizeof(* new_node)。如何检查NULL?

    new_node->data = (void*)malloc(size);

这更加不必要,因为malloc返回void *所以不需要强制转换。

    new_node->data = data;

已经提到的错误。

    new_node->next = NULL;
    return new_node;
}
void destroy_node(node** node)
{
    if(node != NULL)
    {

怎么样:

if (node == NULL)
    return;

突然间,你摆脱了对整个功能的谴责。

    free((*node)->next);
    //this line here causes the error
    free((*node)->data);
    free(*node);
    *node = NULL;
    printf("%s\n", "Node destroyed!");

%s而不仅仅是printf(“Node destroyed!\ n”)是什么?这条消息无论如何都是坏的,因为它甚至不打印上述节点的地址。