如何释放更复杂的嵌套结构

时间:2019-01-11 16:00:44

标签: c struct nested segmentation-fault free

评论中的解决方案。

typedef struct Vertex {
    int i;
    int color;
} vertex;

typedef struct Edge {
    vertex v1;
    vertex v2;
} edge;

typedef struct Node {
    void *p;
    struct Node *next;
} node;

基本上,这是(节点的)链接列表。 在我的程序中,我知道节点数组是否包含边或顶点。

我不确定如何正确释放边缘列表,我尝试了以下操作:

static void freeEdgeList(node *list) {
    if (list == NULL) return;
    node *ptr = list;
    node *tmp;
    do {
        tmp = ptr->next;
        free(&((*((edge *)(ptr->p))).v1));
        free(&((*((edge *)(ptr->p))).v2));
        free(ptr->p);
        free(ptr);
    } while ((ptr = tmp) != NULL);
}

因为我的结构Edge不存储指针,是否足以释放边缘结构而不释放存储在Edge中的顶点? 我有点困惑。

编辑:

static int addEdge(edge *e, node **list) {
    if ((*list) == NULL) {
        (*list) = malloc(sizeof(node));
        if ((*list) == NULL) return -1;
        (*list)->p = malloc(sizeof(edge));
        if ((*list)->p == NULL) return -1;
        memcpy(&((*list)->p), &e, sizeof(edge));
        (*list)->next = NULL;
    } else {
        node *tmp = (*list);
        while (tmp->next != NULL) {
            tmp = tmp->next;
        }
        tmp->next = malloc(sizeof(node));
        if (tmp->next == NULL) return -1;
        tmp = tmp->next;
        tmp->p = malloc(sizeof(edge));
        if (tmp->p == NULL) return -1;
        tmp->next = NULL;
        memcpy(&(tmp->p), &e, sizeof(edge));
    }
    return 0;
}

这是将边缘添加到列表的功能(最初传入的列表为NULL)。 似乎正确添加了边缘,因为我可以将列表输出到控制台了。 但是,如果我尝试释放:

static void freeEdgeList(node *list) {
    while (list) {
        node *tmp = list;
        list = list->next;
        free(tmp->p);
        free(tmp);
    }
}

我遇到了其他错误(段错误,指针无效)

5 个答案:

答案 0 :(得分:2)

您只能将free和家人返回的确切信息传递给malloc。由于您大概调用了malloc来分配node,所以您只需要释放node

vertexedge都不包含作为指针的字段,因此没有其他可释放的内容。您所需要做的就是:

static void freeEdgeList(node *list) {
    while (list) {
        node *tmp = list;
        list = list->next;
        free(tmp->p);
        free(tmp);
    }
}

编辑:

在添加边的代码中,您错误地这样做:

memcpy(&((*list)->p), &e, sizeof(edge));
...
memcpy(&(tmp->p), &e, sizeof(edge));

由于eedge *,所以这样做是将指针值 e复制到字段p而不是其内容。指着。这导致edge指向的p对象具有无效值。相反,您想要:

memcpy((*list)->p, e, sizeof(edge));
...
memcpy(tmp->p, e, sizeof(edge));

这将复制edge指向的e中包含的值。

答案 1 :(得分:1)

规则是,如果您不分配它,那么您就不会释放它。如您所说,结构Edge不包含任何动态内存分配或指针,因此您不会自己释放它们。内存分配为Edge的一部分,并在释放时释放。

因此,请从free()v1中删除v2,仅使用free(ptr->p)

答案 2 :(得分:0)

是的,这是正确的。由于您不是malloc() vertex(它们不是指针,而是在Edge结构内部分配的变量),因此对于Edge结构,简单的free()足够

答案 3 :(得分:0)

编辑:似乎我还不太明白。

感谢您的帮助,非常感谢!这对我来说很清楚。

while (list) {
    node *tmp = list;
    list = list->next;
    free(&(tmp->p));
    free(tmp);
}

此解决方案有效,我需要将指针的地址传递给free,而不是指针本身,我不太清楚为什么。

答案 4 :(得分:0)

正如其他人所提到的,freeEdgeList需要修复[因此请遵循他们的回答]。

addEdge中,您的memcpy呼叫不正确。您正在/从指针的地址复制数据,而不是指针指向的内容。

您要:memcpy((*list)->p, e, sizeof(edge))memcpy(tmp->p, e, sizeof(edge))

此外,在addEdge中,如果*list == NULL,则不要将其设置为第一个/新元素。

此外,代码可以简化一点。例如,在各处使用*list有点麻烦。

这是经过修复的版本,其中修复了memcpy*list的错误:

static int
addEdge(edge *e, node **list)
{
    node *head = *list;
    node *cur;
    node *prev;
    int ret = -1;

    // find the end of the list
    prev = NULL;
    for (cur = head;  cur != NULL;  cur = cur->next)
        prev = cur;

    do {
        // allocate new node
        cur = malloc(sizeof(node));
        if (cur == NULL)
            break;
        cur->next = NULL;

        // add pointer to new edge
        cur->p = malloc(sizeof(edge));
        if (cur->p == NULL) {
            free(cur);
            break;
        }

        // copy in the edge data
        memcpy(cur->p,e,sizeof(edge);

        // link in new node
        if (prev != NULL)
            prev->next = cur;
        else
            head = cur;

        // adjust list pointer
        *list = head;

        ret = 0;
    } while (0);

    return ret;
}