C 从双链接列表中添加和删除

C 从双链接列表中添加和删除,c,doubly-linked-list,C,Doubly Linked List,我有这个结构 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

我有这个结构

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;
}
typedef结构节点
{
结构节点*prev;
作废*数据;
结构节点*下一步;
}节点;
typedef结构头
{
无符号整数长度;
结构节点*第一;
结构节点*last;
}头部;
状态addNode(HEAD*HEAD,NODE*newNode,int loc)
{
int i;
状态ret=成功;
节点*curPtr;
if(头和新节点和位置和位置长度)+1))
{
如果(loc==1)
{
newNode->prev=NULL;
新建节点->下一个=头部->第一个;
如果(头->第一个)
head->first=newNode;
}
其他的
{
curPtr=头->第一;
对于(i=1;不精确;
}
newNode->prev=curPtr;
newNode->next=curPtr->next;
如果(当前->下一步){
curPtr->next->prev=newNode;
}
curPtr->next=newNode;
}
头部->长度++;
}
其他的
ret=失败;
返回ret;
}
状态removeNode(头*头,节点*节点删除)
{
状态ret=成功;
节点*curPtr;
如果(头和头->第一个)
{
curPtr=nodeToRemove->prev;
curPtr->next=nodeToRemove->next;
如果(!(当前->下一步)){
curPtr->next=head->first;
}
头部->长度--;
}
其他的
ret=失败;
返回ret;
}
我知道我在“从列表中删除”中没有调用空闲(节点),此调用是在其他地方进行的

我的问题是,有时在add节点的
newNode->next=curPtr->next;
行上,它会出现分段错误


您能告诉我可能发生这种情况的原因吗?

可能未将
curptr->next
分配给任何不一定会使其指向NULL的对象,因此您可能会在运行时遇到分段错误。请确保在生成列表时,节点中的所有指针在出现任何错误之前都已初始化为NULL对其进行分配/操作

见此:


这是:

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

这意味着如果列表为空(即当
head->first
NULL
)时,您将不会添加节点,并且列表将继续为空。如果列表不为空,则您有一个双链接列表,您只能单程(从(新)第一个节点到(新)第一个节点)第二个节点,你不能走相反的方向,因为你没有这样设置链接


现在来看我的第二条和第三条评论:当
loc!=1
时循环。首先,如果
loc==0
,它将根本不会运行,这意味着它将添加到头部(这是当
loc==1
时尝试执行的操作)。如果列表为空,这将不起作用,因为
curPtr
随后将为
NULL
,当您取消引用该指针时,您将有

其次,假设您已成功地将一些节点添加到列表中,并将大于节点数加上列表中一个的值作为
loc
(即,如果您有一个节点,并且您传递的值大于
2
,或者您有五个节点,并且传递的值大于
6
),然后循环将从一次迭代到多次,留下
curPtr
NULL
。您不会在任何地方检查该值,这意味着您迟早(在循环中或之后)会尝试取消引用一个
NULL
指针,该指针将导致



是导致崩溃的最常见原因,例如您遇到的崩溃。下一次发生崩溃时,您应该做的第一件事是使用调试器并在其中运行程序。调试器将在崩溃位置停止,让您检查函数调用堆栈以及调用堆栈。您还可以检查值调用堆栈的每个级别上的变量数量(如果调试器具有该级别的信息)。你还应该尝试在不同场景的调试器中逐行逐行地检查代码,看看你打算发生的事情是否真的发生了。如果你仍然困惑不解,那么你可以这样做,并发布一个问题。在编译器旁边,调试器是程序员的最佳工具。哦,说到编译器,总是要构建wi启用尽可能多的警告,因为编译器非常擅长检测可疑的东西,并可能导致UB(未定义行为).

如果
loc==1
,旧的第一个节点
prev
指针指向什么?如果列表为空,为什么不添加节点?至于分段错误,如果您想最后添加新节点呢?即当
curPtr
NULL
时?最后,如果您提供的
loc
较大,会发生什么列表中是否有节点?第一个问题-应指向尾部,第二个问题将其添加到尾部,第三个问题将列表绕几圈,直到您使用该位置