链表未定义的行为

时间:2017-07-04 05:45:02

标签: c linked-list undefined-behavior

一个抽象的问题:假设我有一个单链接的节点列表:

      #node 1      #node 2
root->[data|next]->[data|next]->NULL

在C中,声明了root:

struct Node *root = NULL;

其中* root是节点指针'保持'地址“NULL”。

现在,假设我要删除链表中的最后一个节点,以下代码将允许计算机执行此类操作:

//pop: pop removes last/latter node in linked list and sets new last node to NULL
void pop(struct Node *root){
    struct Node *last;
    struct Node *current = root;    //current point to same node as root

    while(current->next != NULL){
        if(current->next == NULL) {break;}    //premature break in traversing of linked list; will stop at last node
        last = current;    //last points to same node as current
        current = current->next;    //move current to next node
    }

    last->next = NULL;    //point second-to-last node to NULL, making it defacto last node in list
    free(current);    //free last node to heap

}//end pop

调用pop并将root传递给函数后,新的链表如下所示:

      #node 1
root->[data|next]->NULL

如果程序再次调用pop,我们应该期望链表看起来像这样:

root->NULL

然而,它没有!在按顺序排列整数元素的链接的情况下,我们将调用pop直到我们观察到奇怪的行为:

List: 1 2 3
Call pop
List: 1 2
Call pop
List: 1
Call pop
List 1980765

以上是由悬空指针引起的未定义行为的示例。现在的问题是:程序如何避免这种行为,并产生一个接近root-> NULL的副作用,从链表中弹出所有节点,直到所述列表为空?

1 个答案:

答案 0 :(得分:1)

<强>首先

这种情况永远不会成真:

if(current->next == NULL) {break;}

如果确实如此,我们就不会达到该行,但会超出while循环。

第二名:

如果您至少执行一次循环体,则指针last保持未初始化状态。因此

last->next = NULL;

将随机内存位置设置为NULL

<强>第三

当您尝试删除最后剩余的元素时,您需要free(root)。但是,您无法将root设置为NULL,因为它是按值传递的。