2017-07-04 40 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,因爲它是按值傳遞的。