2016-04-24 47 views
0

我試圖實現自己的鏈表,並且一直在學習關於動態內存分配和指針等的代碼。當我嘗試添加一些東西到我的鏈表時,我得到一個段錯誤,並且在使用調試器時,我意識到這是因爲最初我的鏈表的頭指針沒有指向空,然後我的添加函數沒有將頭識別爲空。但我有一個初始化函數,它將鏈表的頭指針設置爲NULL,但由於某種原因,一旦我退出初始化函數並加入add函數,頭部不再指向NULL。鏈接列表頭沒有跨越函數調用更新

這裏是我的代碼:

list.h

typedef struct node{ 
    int value; 
    struct node *next; 
} Node; 

typedef struct list{ 
    Node *head; 
} List; 

list.c

void initialize(List *l){ 
    if(l != NULL){ 
     l = malloc(sizeof(List)); 
     l->head = NULL; 
    } 
} 

void add(List *l, int a){ 
    //Code 
} 

int main(){ 
    List l; 
    initialize(&l) 
    add(&l, 2); 
} 

當我步入add函數,並打印出* L,我看到頭部不指向0x0。我一直在撓頭,爲什麼它不是。我認爲這是與價值傳遞有關,但我不認爲這是事實。我在這裏做錯了什麼?

+0

建議執行搜索stackoverflow.com的。這個問題已經回答了很多次。 – user3629249

+0

由於這更多的是關於針對我的案例的指針的概念性問題,所以我不認爲搜索問人家問題的人會幫助我。 –

+0

無論您對指針使用有什麼誤解,發佈代碼的問題根源與許多關於stackoverflow上鍊接列表的問題都是一樣的。 – user3629249

回答

2

是的,傳遞值是你的罪魁禍首。您正在按值傳遞一個指針。

假設l在您的main()位於地址0xABCD。然後你main()被編譯到

int main(void) { 
    List l; 
    initialize(0xABCD); 
    add(0xABCD, 2); 
} 

和你initialize()調用如下(假設malloc()成功,並在地址0xCDEF分配內存:

void initialize(List *l) { 
    if(l != 0x0) { 
     l = 0xCDEF; // malloc() 
     l->head = 0x0; 
    } 
} 

l = 0xCDEF不會傳播到main(),因爲l傳遞按價值

你想要做的是

void initialize(List **l) { 
    if(l != NULL) { 
     *l = malloc(sizeof(List)); // note dereferencing the passed-by-value pointer 
     (*l)->head = NULL; 
    } 
} 

int main(void) { 
    List * l; 
    initialize(&l); 
    add(l, 2); 
} 

它將指針指向指向列表的指針(實際上是指向你的main()中的指針的地址。它允許initialize()中的代碼更改main()中的l變量。

或者,你可以使用

List * list_init() { 
    List * retval = malloc(sizeof(List)); 
    if(retval == NULL) { // you should check malloc return value 
     // abort(), print warning or just 
     return NULL; 
    } 
    retval->head = NULL; 
    return retval; 
} 

int main(void) { 
    List * l = list_init(); 
    if(l == NULL) { 
     // handle the error 
    } 
    add(l, 2); 
} 
+0

請注意,ADT初始化函數更常見有一個'List * initialize();'原型,做一個等價的'return l;'來返回'malloc''指針。 –

+0

啊是的。我現在明白了。除了使用雙指針之外,沒有其他方法可以做到嗎? –

+0

我沒有被初始化的原型收縮,但是讓我們說我是這個函數,並且這個函數只用一個指針作爲參數?我只是想了解複製,解除引用等。 –

0

你的代碼編譯了這一行l->malloc(sizeof(list));看起來很奇怪。

創建只有一個參數的結構是不是真的有用,一個簡單的typedef應該做的工作:生活在在堆棧上typedef Node* List

+0

這並不奇怪。這就是你在鏈表中分配節點的方式。 –

+0

這個問題已經被編輯過了'l-> malloc(sizeof(list));'不會編譯,'l = malloc(sizeof(List));' –

1

您在主申報表()。你傳遞一個指向這個List的指針initailize()。然後你在堆上創建一個新的列表。當你從initialize()返回的時候,你仍然在使用棧中的列表。堆上的列表泄漏,您無法訪問它。所以你永遠不會初始化你傳遞的List作爲add()的指針。你可以忘記初始化(),只需要有

l.head = NULL;

改爲。