我不完全理解 c 中的列表是如何工作的

I don't understand fully how lists in c work

提问人:g1e2h3 提问时间:3/13/2023 最后编辑:Vlad from Moscowg1e2h3 更新时间:3/13/2023 访问量:55

问:

所以我试图在列表的开头添加一个元素。函数prepend_list位于第 27 行。我试图以两种不同的方式进行它,一种是返回一个列表,另一种是 void 函数。

#include "base.h"
#include "string.h"

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

Node* new_node(int value, Node* next){
    Node* new = xmalloc(sizeof(Node));
    new->value = value;
    new->next = next;
    return new;
}

void free_list(Node* list){
    Node* currentHead = list;
    while(list != NULL){
        currentHead = list;
        list = list->next;
        free(currentHead);
    }
}

Node* prepend_list(int value, Node* list){
    return new_node(value, list);
}

void test(void) {
    Node* n = NULL;
    n = new_node(1, new_node(3, NULL));
    n = prepend_list(2, n);
    for(Node* print = n;print != NULL;print = print->next){
        printi(print->value);
        if(print->next != NULL){
            prints(", ");
        }
    }
    printsln("");
    free_list(n);
}

int main(void) {
    test();
    report_memory_leaks(true);
    return 0;
}

但我不明白为什么我不能这样做

void prepend_list(int value, Node* list){
    list = new_node(value, list);
}

当我尝试这样做时,测试函数中的列表 n 根本没有改变。相反,我得到了内存泄漏。有人能告诉我为什么吗?

C 引用 单链接列表 按值传递 函数定义

评论

0赞 Some programmer dude 3/13/2023
问题是它是函数内部的局部变量。当函数返回时,它的生存期将结束,变量将不复存在。届时,对变量的任何更改都将丢失。list = new_node(value, list);list
0赞 Gerhardh 3/13/2023
欢迎来到 SO。在 C 中,所有参数都按值传递。这意味着,您将获得所提供值的副本。无论您对该副本执行任何操作,都不会影响原始值。如果要使更改在函数外部可见,则必须传递指针,即Node *list => Node **list

答:

1赞 Vlad from Moscow 3/13/2023 #1

该函数处理作为参数传递给函数的表达式值的副本。

你可以想象这个功能

void prepend_list(int value, Node* list){
    list = new_node(value, list);
}

和它的呼唤

Node* n = NULL;
prepend_list(2, n);

以下方式

prepend_list(2, n);
//...
void prepend_list(/* int value, Node* list */){
    int value = 2;
    Node* list = n;
    list = new_node(value, list);
}

如您所见,函数的局部变量列表由传递的指针 n 的值初始化,并且在函数中更改的是局部变量列表。指针 n 保持不变。也就是说,函数按值接受其参数。

有两种方法可以解决问题和更改原始指针。

第一个是从函数返回一个新指针,并将其分配给原始指针,就像在程序中所做的那样。

n = prepend_list(2, n);

第二种是通过指向原始指针的指针间接地通过引用传递原始指针。并且取消引用指向原始指针的指针,该函数可以访问原始指针并可以更改它。例如

prepend_list(2, &n);
//...
void prepend_list(int value, Node ** list){
    *list = new_node(value, *list);
}