c - 为什么在使用函数时无法正确添加到链表?

标签 c linked-list

我正在尝试创建一个链表。当我在创建对象的同一函数中添加到列表时,它起作用了。

定义:

typedef struct student {
    int num;
    char* name;
} student;

typedef struct container {
    student* data;
    struct container* next;
} container ;

我使用的所有对象都是这样初始化的:

student stu1;
stu1.num = 6;
stu1.name = "grefagf";

front = createContainer(&stu1);
back = front;

student stu2;
stu2.num = 3;
stu2.name = "dsghjyreawre";

student stu3;
stu3.num = 4;
stu3.name = "dsghhjrant";

student stu4;
stu4.num = 213;
stu4.name = "fdsafgrw";

当我将这些元素添加到主函数中的列表时,如下所示:

container* tmp;

tmp = createContainer(&stu2);
back->next = tmp;
back = tmp;

tmp = createContainer(&stu3);
back->next = tmp;
back = tmp;

tmp = createContainer(&stu4);
back->next = tmp;
back = tmp;

它正常工作,输出如下:

1:  6       grefagf
2:  3       dsghjyreawre
3:  4       dsghhjrant
4:  213     fdsafgrw

当我使用我制作的另一个函数打印它时。

但如果我创建一个名为 add() 的函数并传递 stu2、stu3...,如下所示:

int add(student to_add) {

    container* tmp;
    tmp = createContainer(&to_add);
    printf("added: (%d, %s)\n", tmp->data->num, tmp->data->name);

    back->next = tmp;
    back = tmp;

    return 1;
}

然后在主函数中执行此操作:

add(stu2);
add(stu3);
add(stu4);

它输出这个:

1:  6       grefagf
2:  41096808        fdsafgrw
3:  41096808        fdsafgrw
4:  41096808        fdsafgrw

如果您需要,这里是源代码:

非函数示例:https://pastebin.com/ZLqTzp4t

#include <stdio.h>
#include <stdlib.h>

typedef struct student {
    int num;
    char* name;
} student;

typedef struct container {
    student* data;
    struct container* next;
} container ;

container* back;
container* front;

container* createContainer(student* data) {

    container* tmp = malloc(sizeof(container));

    tmp->data = data;
    tmp->next = NULL;

    return tmp;
}

void printList(container* front) {

    container* tmp = front;

    int i;
    i=0;
    while (tmp != NULL) {
        i++;
        printf("%d:\t%d\t\t%s\n", i, tmp->data->num, tmp->data->name);
        tmp = tmp->next;
    }
}

int main(void) {

    student stu1;
    stu1.num = 6;
    stu1.name = "grefagf";

    front = createContainer(&stu1);
    back = front;

    student stu2;
    stu2.num = 3;
    stu2.name = "dsghjyreawre";

    student stu3;
    stu3.num = 4;
    stu3.name = "dsghhjrant";

    student stu4;
    stu4.num = 213;
    stu4.name = "fdsafgrw";

    container* tmp;

    tmp = createContainer(&stu2);
    back->next = tmp;
    back = tmp;

    tmp = createContainer(&stu3);
    back->next = tmp;
    back = tmp;

    tmp = createContainer(&stu4);
    back->next = tmp;
    back = tmp;

    printf("front\n");
    printList(front);
    printf("\ntop\n");
    printList(back);

    return EXIT_SUCCESS;
}

函数示例:https://pastebin.com/TyQY4j5k

#include <stdio.h>
#include <stdlib.h>

typedef struct student {
    int num;
    char* name;
} student;

typedef struct container {
    student* data;
    struct container* next;
} container ;

container* back;
container* front;

container* createContainer(student* data) {

    container* tmp = malloc(sizeof(container));

    tmp->data = data;
    tmp->next = NULL;

    return tmp;
}

int add(student to_add) {

    container* tmp;
    tmp = createContainer(&to_add);
    printf("added: (%d, %s)\n", tmp->data->num, tmp->data->name);

    back->next = tmp;
    back = tmp;

    return 1;
}

void printList(container* front) {

    container* tmp = front;

    int i;
    i=0;
    while (tmp != NULL) {
        i++;
        printf("%d:\t%d\t\t%s\n", i, tmp->data->num, tmp->data->name);
        tmp = tmp->next;
    }
}

int main(void) {

    student stu1;
    stu1.num = 6;
    stu1.name = "grefagf";

    front = createContainer(&stu1);
    back = front;

    student stu2;
    stu2.num = 3;
    stu2.name = "dsghjyreawre";

    student stu3;
    stu3.num = 4;
    stu3.name = "dsghhjrant";

    student stu4;
    stu4.num = 213;
    stu4.name = "fdsafgrw";

    add(stu2);
    add(stu3);
    add(stu4);

    printf("front\n");
    printList(front);
    printf("\ntop\n");
    printList(back);

    return EXIT_SUCCESS;
}

最佳答案

这是带有 add 功能的代码的或多或少的最小版本。它以 60 行运行,而原始版本为 83 行。

#include <stdio.h>
#include <stdlib.h>

typedef struct student
{
    int num;
    char *name;
} student;

typedef struct container
{
    student *data;
    struct container *next;
} container;

static container *back;
static container *front;

static container *createContainer(student *data)
{
    container *tmp = malloc(sizeof(container));
    tmp->data = data;
    tmp->next = NULL;
    return tmp;
}

static void add(student to_add)
{
    container *tmp = createContainer(&to_add);
    printf("added: (%d, %s)\n", tmp->data->num, tmp->data->name);
    back->next = tmp;
    back = tmp;
}

static void printList(container *item)
{
    for (int i = 0; item != NULL; item = item->next)
        printf("%d:\t%d\t\t%s\n", ++i, item->data->num, item->data->name);
}

int main(void)
{
    student stu1 = { 6, "grefagf" };
    student stu2 = { 3, "dsghjyreawre" };
    student stu3 = { 4, "dsghhjrant" };
    student stu4 = { 213, "fdsafgrw" };

    front = createContainer(&stu1);
    back = front;
    add(stu2);
    add(stu3);
    add(stu4);

    printf("front\n");
    printList(front);
    printf("\nback\n");
    printList(back);

    return EXIT_SUCCESS;
}

在我的 Mac 上,它产生了:

added: (3, dsghjyreawre)
added: (4, dsghhjrant)
added: (213, fdsafgrw)
front
1:  6       grefagf
2:  0       
3:  0       
4:  0       

back
1:  0   

问题是您将局部变量的地址传递给 createContainer() 函数,但该变量超出范围,因此您的容器指向垃圾。由于这是调用未定义的行为,因此您的机器上的结果可能不同,但两者都是正确的。崩溃也是可能的——这是 UB 的优点之一。

您需要通过以下两种方式之一修改它。 createContainer() 复制它所传递的内容,或者您​​安排通过 add() 将指针传递给 main() 中的变量> 到 createContainer()。此代码执行第二个 — 但从长远来看,它可能不是更好的解决方案。但是,对于复制传递的内容的通用解决方案,需要处理(很多)更多的内存管理。

#include <stdio.h>
#include <stdlib.h>

typedef struct student
{
    int num;
    char *name;
} student;

typedef struct container
{
    student *data;
    struct container *next;
} container;

static container *back;
static container *front;

static container *createContainer(student *data)
{
    container *tmp = malloc(sizeof(container));
    tmp->data = data;
    tmp->next = NULL;
    return tmp;
}

static void add(student *to_add)
{
    container *tmp = createContainer(to_add);
    printf("added: (%d, %s)\n", tmp->data->num, tmp->data->name);
    back->next = tmp;
    back = tmp;
}

static void printList(container *item)
{
    for (int i = 0; item != NULL; item = item->next)
        printf("%d:\t%d\t\t%s\n", ++i, item->data->num, item->data->name);
}

int main(void)
{
    student stu1 = { 6, "grefagf" };
    student stu2 = { 3, "dsghjyreawre" };
    student stu3 = { 4, "dsghhjrant" };
    student stu4 = { 213, "fdsafgrw" };

    front = createContainer(&stu1);
    back = front;
    add(&stu2);
    add(&stu3);
    add(&stu4);

    printf("front\n");
    printList(front);
    printf("\nback\n");
    printList(back);

    return EXIT_SUCCESS;
}

这里有5个字符与上一个版本不同。 add()的函数定义中有一个*createContainer() 的调用中没有 &;在 main() 中对 add() 的每个调用中都有一个 &。结果是:

added: (3, dsghjyreawre)
added: (4, dsghhjrant)
added: (213, fdsafgrw)
front
1:  6       grefagf
2:  3       dsghjyreawre
3:  4       dsghhjrant
4:  213     fdsafgrw

back
1:  213     fdsafgrw

此代码会泄漏内存,因为它不会尝试清理列表。暂时可以。请注意,您最终需要进行清理。

关于c - 为什么在使用函数时无法正确添加到链表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48735436/

相关文章:

c - 如何在 c 中创建超过 10 亿位的整数数据类型

python - 如何读取从通信端口写入的数据?

java - 在 Java 中将节点添加到列表的开头?

c - 在c中的结构中初始化灵活的结构指针数组

c - 学生结构体的链表实现

c - C 中函数将指向局部静态/全局变量的指针作为左值返回

c - 将整个 char 指针清零

c - 当我删除第一个节点时,它会生成无限循环错误

C:同一个文件一个读指针,一个更新指针

c - 空函数C递归