c circular double linked-list delete_node - iterate traverses deleted node on first pass after delete

北慕城南 提交于 2019-12-02 06:43:52

You're not modifying the caller's pointer when requesting the very node it points to as the delete request. The following, a cut down version of some of your code, demonstrates one way to do this:

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

typedef struct record rec;
struct record
{
    int data;
    rec *prev, *next;
};

void delete_node (rec ** pp, int num)
{
    if (!*pp)
        return;

    // find the num'th node
    while (num-- && *pp)
        pp = &(*pp)->next;

    // setup victim
    rec *victim = *pp;

    // non-self-reference node means just rewire
    if (victim && (victim != victim->next))
    {
        victim->prev->next = victim->next;
        victim->next->prev = victim->prev;
        *pp = victim->next;
    }
    else
    {   // deleted node was self-referenced. last node
        *pp = NULL;
    }
    free(victim);
}

void iterfwd(const rec* list)
{
    const rec *p = list;
    printf("list: %p\n", list);
    if (p)
    {
        for (; p; p = (p->next != list ? p->next : NULL))
            printf("prev: %p, self:%p, next:%p, data = %d\n", p->prev, p, p->next, p->data);
    }
    puts("");
}

void insert(rec **pp, int data)
{
    // setup new node
    rec *newp = malloc(sizeof(*newp));
    newp->data = data;

    if (!*pp)
    {
        newp->next = newp->prev = newp;
        *pp = newp;
    }
    else
    {   // insert between prev and head.
        newp->next = *pp;
        (*pp)->prev->next = newp;
        newp->prev = (*pp)->prev;
        (*pp)->prev = newp;
    }
}

int main()
{
    rec *list = NULL;
    int i;

    for (i=1; i<=5; ++i)
        insert(&list, i);
    iterfwd(list);

    // delete fourth node (0-based)
    delete_node(&list, 3);
    iterfwd(list);

    // delete first node (0-based)
    delete_node(&list, 0);
    iterfwd(list);

    // delete first node (0-based)
    delete_node(&list, 0);
    iterfwd(list);

    // delete first node (0-based)
    delete_node(&list, 0);
    iterfwd(list);

    // delete first node (0-based)
    delete_node(&list, 0);
    iterfwd(list);

    return 0;
}

Output (obviously system dependent)

Note how the passed-in pointer (pass by address) is modified when requesting the 0-element is removed.

list: 0x100103af0
prev: 0x100103b70, self:0x100103af0, next:0x100103b10, data = 1
prev: 0x100103af0, self:0x100103b10, next:0x100103b30, data = 2
prev: 0x100103b10, self:0x100103b30, next:0x100103b50, data = 3
prev: 0x100103b30, self:0x100103b50, next:0x100103b70, data = 4
prev: 0x100103b50, self:0x100103b70, next:0x100103af0, data = 5

list: 0x100103af0
prev: 0x100103b70, self:0x100103af0, next:0x100103b10, data = 1
prev: 0x100103af0, self:0x100103b10, next:0x100103b30, data = 2
prev: 0x100103b10, self:0x100103b30, next:0x100103b70, data = 3
prev: 0x100103b30, self:0x100103b70, next:0x100103af0, data = 5

list: 0x100103b10
prev: 0x100103b70, self:0x100103b10, next:0x100103b30, data = 2
prev: 0x100103b10, self:0x100103b30, next:0x100103b70, data = 3
prev: 0x100103b30, self:0x100103b70, next:0x100103b10, data = 5

list: 0x100103b30
prev: 0x100103b70, self:0x100103b30, next:0x100103b70, data = 3
prev: 0x100103b30, self:0x100103b70, next:0x100103b30, data = 5

list: 0x100103b70
prev: 0x100103b70, self:0x100103b70, next:0x100103b70, data = 5

list: 0x0
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!