2013-06-25 116 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