链接列表头没有跨越函数调用更新

问题描述:

我试图实现自己的链表,并且一直在学习关于动态内存分配和指针等的代码。当我尝试添加一些东西到我的链表时,我得到一个段错误,并且在使用调试器时,我意识到这是因为最初我的链表的头指针没有指向空,然后我的添加函数没有将头识别为空。但我有一个初始化函数,它将链表的头指针设置为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

是的,传递值是你的罪魁祸首。您正在按值传递一个指针。

假设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

我没有被初始化的原型收缩,但是让我们说我是这个函数,并且这个函数只用一个指针作为参数?我只是想了解复制,解除引用等。 –

你的代码编译了这一行l->malloc(sizeof(list));看起来很奇怪。

创建只有一个参数的结构是不是真的有用,一个简单的typedef应该做的工作:生活在在堆栈上typedef Node* List

+0

这并不奇怪。这就是你在链表中分配节点的方式。 –

+0

这个问题已经被编辑过了'l-> malloc(sizeof(list));'不会编译,'l = malloc(sizeof(List));' –

您在主申报表()。你传递一个指向这个List的指针initailize()。然后你在堆上创建一个新的列表。当你从initialize()返回的时候,你仍然在使用栈中的列表。堆上的列表泄漏,您无法访问它。所以你永远不会初始化你传递的List作为add()的指针。你可以忘记初始化(),只需要有

l.head = NULL;

改为。