2017-07-04 64 views
-2

一个抽象的问题:说我有节点的单链表:链表未定义行为

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

在C,根声明:

struct Node *root = NULL; 

其中*根是节点指针'保存'地址“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 

调用弹出并通过根的功能之后,新的链接列表如下:

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

如果程序调用再次流行,我们应该期待的链表是这样的:

root->NULL 

但是,它不!在整数元素以链表的情况下,我们将调用弹出,直到我们看到奇怪的行为:

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

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

+1

当您逐步执行弹出功能时,调试器会告诉您什么? – Gerhardh

+1

您的代码有几个问题。它会在这里崩溃while(current-> next!= NULL){'如果根是NULL且在这里'last-> next = NULL;'如果列表只有一个节点,因为上一次未初始化。 – Karthick

回答

1

第一:

这种情况可能永远不会是真实的:

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

如果这是真的,我们就不会达到这个线,但掉出while循环。

二:

如果不执行循环体至少一次,指针last不断初始化。因此

last->next = NULL; 

设置一个随机的内存位置NULL

三:

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