2008-11-02 128 views
2
void addNewNode (struct node *head, int n) 
{ 
    struct node* temp = (struct node*) malloc(sizeof(struct node)); 
    temp -> data = n; 
    temp -> link = head; 
    head = temp; 
} 

上面給出的代碼是用於在鏈接列表的頭部添加新節點的功能的普遍錯誤版本。 一般正確的版本一樣,將新節點添加到鏈接列表的新方法

void addNewNode (struct node **head, int n); 
void addNewNode (struct node * &head, int n); 

我制定了另一個,但簡單的功能其目的工作得很好。

struct node* addNewNode (struct node *head, int n) 
{ 
    struct node* temp = (struct node*) malloc(sizeof(struct node)); 
    temp -> data = n; 
    temp -> link = head; 
    return temp; 
} 

但我還沒有看到這個被使用或代碼和教程討論,因此我很想知道,如果這種方法有一定的缺陷。

回答

17

這個缺陷是你依靠調用者執行更新頭指針到列表的最後一步。

如果調用者忽略這樣做,編譯器不會抱怨,並且出於所有意圖和目的,列表看起來沒有改變(並且您已經泄漏了節點的內存)。

0

我在任何提到的正確代碼中看不到任何問題。 要改變或不改變頭部是一個設計問題 - 以及如何返回修改列表。 良好的接口在std :: list <>中實現,作爲使用OOP的例子,這種方法沒有潛在的問題。頭指針是隱藏的,你可以隨意修改它,由於調用者不明確存儲頭,它對列表的引用永遠是正確的。

看起來醜陋的一件事(當你使用C++而不是C時)是一個malloc,最好使用'new'。

2

您的方法與addNode是列表中的方法不兼容,這是OO語言中更常用的方法。

我個人認爲

list.add(element) 

是一個巨大的很多比 「集合」 圖書館不能錯的

list = add(list, element) 

幾十個更直觀的...

+0

有沒有這樣的事情,在C中的對象。 – 2008-11-03 01:35:27

4

這是怎麼鏈接列出大多數功能語言的工作。例如,在ML你可能會做這樣的事情:

val ls = [1, 2, 3, 4] 
val newList = 0 :: ls 

::語法實際上是一個函數,它接受兩個參數(0ls),並返回一個具有0作爲第一要素的新列表。 ML中的列表實際上定義爲列表節點,因此::實際上與您提出的addNewNode功能非常相似。

換句話說:恭喜,你已經在C中創建了一個不可變的鏈表實現!理解這對於函數式語言來說是相當重要的第一步,所以知道這真是一件好事。

1

Afaik,這就是glib中的列表如何工作的方式,我確定gtk人不是第一個使用這種方式的人,所以我不會稱之爲一種新方法。我個人更喜歡有一個基本結構,它包含節點數量,第一個和最後一個指針。

1

這並不新鮮。正如quinmars所指出的,超過10年來,glib已經這樣做了。這是一個好主意,所以恭喜你搞清楚了。

儘管您的代碼有一個挑剔:不要在C中投入malloc()的返回值,也不要在使用sizeof時重複類型名稱。您的分配線應如下所示:

struct node* temp = malloc(sizeof *temp); 

請參閱?更短,更緊,更容易閱讀,更難以搞砸。更好! :)