2013-06-25 145 views
1

所以我對C很新,但不是編程。我想學習C,所以我決定嘗試實現一個簡單的鏈接列表。C鏈接列表循環參考

下面是代碼:

#include <stdio.h> 

typedef struct node node; 
struct node { 
    char *word; 
    node *next; 
}; 

// Returns a node. 
node node_new(char *word) { 
    node n; 
    n.word = word; 
    n.next = NULL; 
    return n; 
} 

// Traverses the linked list, spitting out the 
// words onto the console. 
void traverse(node *head) { 
    node *cur = head; 

    while (cur != NULL) { 
     printf("I have %s.\n", cur->word); 
     cur = cur->next; 
    } 

    printf("Done.\n"); 

    return; 
} 

// In here I get circular references whenever I pass a second argument. 
void dynamic(int argc, char **argv) { 
    printf("DYNAMIC:\n"); 

    node n = node_new("ROOT"); 
    node *cur = &n; 

    int i; 
    for (i = 0; i < argc; i++) { 
     node next = node_new(argv[i]); 
     cur->next = &next; 
     cur = &next; 
    } 

    traverse(&n); 
} 

void predefined(void) { 
    printf("PREDEFINED:\n"); 

    node n = node_new("ROOT"); 
    node a = node_new("A"); 
    node b = node_new("B"); 
    node c = node_new("C"); 

    n.next = &a; 
    a.next = &b; 
    b.next = &c; 

    traverse(&n); 
} 

int main(int argc, char **argv) { 
    predefined(); 
    dynamic(argc, argv); 
    return 0; 
} 

如果我只是運行它不帶參數( 「./test」)的輸出是:

PREDEFINED: 
I have ROOT. 
I have A. 
I have B. 
I have C. 
Done. 
DYNAMIC: 
I have ROOT. 
I have ./test. 
Done. 

,但如果我把任何參數上,而不是「我有./test」。它給出了命令行上最後一個參數(「./test one two three」給出「我有三個」)的無限循環。一遍又一遍忽略了「one」和「two」,但前面的行是相同)。

我認爲它與動態函數中的錯誤指針管理有關,但我不知道爲什麼它將自己設置爲它自己的「下一個」節點。

+0

我認爲你有堆棧分配vs堆問題? –

+0

當你在堆棧上分配,並使複製節點n = new_node(),它在範圍的末尾釋放n(for循環) –

+0

它釋放n,這正是我想要的。第一次通過for循環,它將「head」的下一個節點設置爲指向n。我想不出我做錯了什麼。 我看不出爲什麼我需要malloc,因爲我沒有做任何動態內存管理。我只是在移動指針。但是我在兩天前從未使用過C,所以我真的不知道。 –

回答

2

的問題是在這裏:

for (i = 0; i < argc; i++) { 
    node next = node_new(argv[i]); 
    cur->next = &next; 
    cur = &next; 
} 

通過分配next這樣,它仍然保留了堆棧,在每次迭代實際上不會更改地址。

for (i = 0; i < argc; i++) { 
    node *next = malloc (sizeof node); 
    next->word = argv[i]; 
    next->next = NULL; 
    cur->next = next; 
    cur = next; 
} 

此外,node_new()不能使用,因爲它沒有任何分配任何持久的新的內存:每次它應該是一個新的對象。

2

問題出在您的for循環中。每次迭代使用堆棧中相同的內存位置來存儲next變量。因此,&next給出的內存位置實際上對於您的整個for循環是一個常量,並且在運行traverse時,該內存位置包含的最後一個值爲next

for循環相當於這個版本,這可能會流下更多的光線:

int i; 
node next; // note this line 
for (i = 0; i < argc; i++) { 
    next = node_new(argv[i]); 
    cur->next = &next; 
    cur = &next; 
} 

你需要在堆上創建新的節點,如果您希望能夠通過周圍的地址,或將他們的地址存儲在其他數據結構中。請閱讀mallocfree