为什么我在使用函数时无法正确添加链接列表?

时间:2018-02-11 19:17:42

标签: 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;
}

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

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;
}

3 个答案:

答案 0 :(得分:3)

以下是使用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()可以复制传递的内容,或者安排将指针传递给main()add()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(); &中对add()的每次调用都有一个main()。结果是:

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

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

答案 1 :(得分:1)

add函数还应该使用它添加“student”的链表(或“容器”)。

因此,您不应该在其中创建“temp”容器,而是使用传入的容器并添加到容器中传递的容器的后面。

编辑:刚刚意识到你的背部和前部都是全球性的。这可能不是一个好主意,因为这样你只能为整个程序提供一个链表。

现在重读......

编辑2:啊,这是一个很好的。您正在传递学生(制作学生的副本)和然后在add函数中获取其地址,该函数是堆栈中变量的地址。弹出堆栈,因此堆栈中的变量地址没有意义。相反,add应该接收一个指向学生的指针,你应该传入stu2,stu3等的地址。

编辑3:太晚了:(

答案 2 :(得分:1)

好的,我试过它正在运行。只能通过地址学生结构获取添加功能 如下

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

并更改添加功能如下

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;
}