簡體   English   中英

如何釋放更復雜的嵌套結構

[英]How to free more complex nested structs

評論中的解決方案。

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不存儲指針,是否足以釋放邊緣結構而不釋放存儲在邊緣中的頂點? 我有點困惑。

編輯:

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);
    }
}

我得到不同的錯誤(segfault,無效的指針)

您只能准確地free malloc和family返回的內容。 由於您大概調用了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而不是它指向的字段。 這導致由p指向的edge對象具有無效值。 相反,您想要:

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

這將復制e指向的edge中包含的值。

規則是,如果不分配它,則不會釋放它。 如您所說,結構Edge不包含任何動態內存分配或指針,因此您不會自己釋放它們。 內存被分配為Edge一部分,並在釋放時釋放。

因此,從v1v2刪除free() ,僅使用free(ptr->p)

是的,這是正確的。 由於您不是在malloc() 繪制 vertex (它們不是指針,而是在Edge結構內部分配的變量free() ,因此,針對Edge結構的簡單free()就足夠了

編輯:似乎我還不太明白。

感謝您的幫助,非常感謝! 這對我來說很清楚。

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

這種解決方案有效,我需要將指針的地址傳遞給free,而不是指針本身,盡管我不太清楚為什么。

正如其他人提到的, freeEdgeList需要修復[因此請遵循他們的回答]。

addEdge ,您的memcpy調用不正確。 您正在向/從指針的地址復制,而不是指針指向的地址

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

另外,在addEdge ,如果*list == NULL ,則不要將其設置為first / new元素。

而且,代碼可以簡化一些。 例如,在任何地方使用*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;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM