【问题标题】:Adding and removing from double linked list从双链表中添加和删除
【发布时间】:2015-01-11 20:00:19
【问题描述】:

我有这个结构

typedef struct node
{
    struct node *prev;
    void        *data;
    struct node *next;
}NODE;

typedef struct head
{
    unsigned int length;
    struct node  *first;
    struct node *last;
}HEAD;


STATUS addNode(HEAD *head, NODE *newNode, int loc)
{
int i;
STATUS ret = SUCCESS;

NODE *curPtr;

if(head && newNode && loc && (loc <= (head->length)+1))
{
    if(loc == 1)
    {
        newNode->prev = NULL;
        newNode->next = head->first;

        if(head->first)
            head->first = newNode;
    }
    else
    {
        curPtr = head->first;

        for(i=1; i<(loc-1); i++){
            curPtr = curPtr->next;
        }

        newNode->prev = curPtr;
        newNode->next = curPtr->next;

        if(curPtr->next){
            curPtr->next->prev = newNode;
        }
        curPtr->next = newNode;

    }

    head->length++;
}
else
    ret = FAILURE;

return ret;
}



STATUS removeNode(HEAD *head,NODE *nodeToRemove)
{
    STATUS ret = SUCCESS;

    NODE *curPtr;

    if(head && head->first)
    {
        curPtr = nodeToRemove->prev;
        curPtr->next = nodeToRemove->next;
        if(!(curPtr->next)){
            curPtr->next = head->first;
        }
        head->length--;
    }
    else
        ret = FAILURE;

    return ret;
}

我知道我没有在从列表中删除时调用 free(node),这个调用是在其他地方进行的

我的问题是,有时在添加节点中的 newNode-&gt;next = curPtr-&gt;next; 行上它属于分段错误

你能告诉我这可能发生的原因吗?

【问题讨论】:

  • 如果loc == 1,旧的第一节点prev指针指向什么?如果列表为空,为什么不添加节点呢?
  • 至于你的分段错误,如果你想最后添加新节点怎么办? IE。当curPtrNULL
  • 最后,如果您提供的loc 大于列表中的节点数会怎样?
  • 第一个问题 - 应该指向尾部,第二个问题将其添加到尾部,第三个问题在列表中圈几圈,直到你消耗掉这个位置

标签: c doubly-linked-list


【解决方案1】:

好的,让我们从我的第一个 cmets 开始:当您使用 loc == 1 调用 addNode 函数时会发生什么:您初始化了新节点,所以它是 next 指针指向列表的旧头,并且prev 指针指向NULL。这一切都很好,但是你的问题开始了。仅当列表为空时,您才将新节点添加到列表中。您也不要更改以前的头节点prev 指针。

这意味着如果列表为空(即当head-&gt;firstNULL 时),那么您将不会添加节点,并且列表将继续为空。如果列表不为空,那么你有一个双链表,你只能走一条路(从(新)第一个节点到(新)第二个节点,你不能走相反的方向,因为你没有以这种方式设置链接。


现在是我的第二个和第三个 cmets:loc != 1 时的循环。首先,如果loc == 0,它根本不会运行,这意味着它将添加到头部(这是您在loc == 1 时尝试做的事情)。如果列表为空,这将不起作用,因为 curPtr 将是 NULL,当您取消引用该指针时,您将拥有 undefined behavior

其次,假设您已经设法将一些节点添加到列表中,并且您传递了一个大于列表中节点数加一的值作为loc(即,如果您有一个节点,并且您传递了一个值大于2,或者你有五个节点并传递一个大于6的值),那么循环将迭代一次到多次,留下curPtrNULL。您不会在任何地方进行检查,这意味着您迟早会(在循环中或之后)尝试取消引用指向 undefined behaviorNULL 指针。


Undefined behavior 是导致崩溃的最常见原因,例如您遇到的崩溃。下次遇到崩溃时,您应该做的第一件事是使用 调试器 并在其中运行您的程序。调试器将停止在崩溃的位置,让您检查函数调用堆栈,以及向上走调用堆栈。您还可以检查调用堆栈的每个级别的变量值(如果调试器具有该级别的信息)。您还应该尝试在调试器中针对不同场景逐行逐行执行代码,以查看您打算发生的实际情况如果您仍然感到困惑,那么您可以来并发布一个关于它的问题。除了编译器,调试器是程序员的最佳工具。哦,说到编译器,总是在构建时启用尽可能多的警告,因为编译器非常擅长检测可疑并可能导致 UB(未定义行为)的事物。

【讨论】:

    【解决方案2】:

    curptr-&gt;next 可能没有分配给任何不一定指向 NULL 的东西,因此您可能会在运行时遇到分段错误。确保在构建列表时,节点中的所有指针在对其进行任何分配/操作之前都被初始化为 NULL。

    看到这个:C: Why do unassigned pointers point to unpredictable memory and NOT point to NULL?

    还有这个:Why am I getting a segmentation fault?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-11-17
      • 1970-01-01
      • 2012-01-10
      • 2018-09-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多