我对 C 中的结构链表有疑问

I'm having an issue with linked list of structures in C

我必须创建一个结构书的链接列表,我的问题是当我创建一个新节点并在其中输入一本新书的属性时,我以前节点中的所有以前的书都将它们的名称更改为那个我输入的最后一个,尽管出版年份仍然是原始的。谁能解释一下这是如何工作的,以及我必须做些什么才能使其正常工作?

这是我的代码

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

#define N 255

struct Book {
    char *title;
    int year;
};

struct Node {
    struct Book book;
    struct Node *next;
};

struct Book createBook(char *title, int year) {
    struct Book book = {title, year};
    return book;
}

void print(struct Node *head) {
    struct Node *curr_node = head;

    while (curr_node != NULL) {
        printf("%s(%d)\n", curr_node->book.title, curr_node->book.year);
        curr_node = curr_node->next;
    }
}

void add(struct Node **head, struct Book book) {
    struct Node *new_node;
    struct Book *new_book;
    new_node = (struct Node*) malloc(sizeof( struct Node ));

    new_book = &new_node->book;

    new_book->title = book.title;
    new_book->year = book.year;

    new_node->next = (*head);
    *head = new_node;
}

void pop(struct Node **head) {
    struct Node *next_node = NULL;

    if (*head == NULL) {
        printf("List is empty!");
        return;
    }

    next_node = (*head)->next;
    free(*head);
    *head = next_node;
}

void reverse(struct Node **head) {
    struct Node *prev_node = NULL;
    struct Node *curr_node = *head;
    struct Node *next_node = NULL;

    while (curr_node != NULL) {
        next_node = curr_node->next;
        curr_node->next = prev_node;
        prev_node = curr_node;
        curr_node = next_node;
    }

    *head = prev_node;
}

void clear(struct Node **head) {

    struct Node *curr_node = *head;
    struct Node *temp_node = NULL;

    while (curr_node != NULL) {
        temp_node = curr_node->next;
        free(curr_node);
        curr_node = temp_node;
    }

    *head = NULL;
}

int main() {

    struct Node *head = NULL;

    short process = 1; // 1 for True 0 for False
    int option = 0;
    char title[N];
    int year = 0;

    while (process) {

        printf("List of actions:\n");
        printf("1:\tAdd element\n");
        printf("2:\tRemove element\n");
        printf("3:\tReverse list\n");
        printf("4:\tPrint list\n");
        printf("5:\tClear list\n");
        printf("0:\tExit\n");

        scanf("%d", &option);

        switch (option) {

            case 1:
                printf("Enter book\'s title: ");
                scanf("%s", title);
                printf("Enter book\'s year of publishing: ");
                scanf("%d", &year);
                add(&head, createBook(title, year));
                printf("\n");
                break;
            case 2:
                pop(&head);
                break;
            case 3:
                reverse(&head);
                break;
            case 4:
                print(head);
                break;
            case 5:
                clear(&head);
                break;
            case 0:
                process = 0;
                break;
            default:
                printf("\n");
                printf("**************************\n");
                printf("Enter numbers from 1 to 5!\n");
                printf("**************************\n");
                printf("\n");
                continue;
        }
    }
    return 0;
}

您总是将指针传递给在 main

中声明的同一个本地数组 title
 char title[N];

到函数createBook

add(&head, createBook(title, year));

所以所有节点的数据成员title

struct Book {
    char *title;
    int year;
};

指向在 main 中声明的同一个局部数组 title 由于在函数

中进行了初始化
struct Book book = {title, year};

即在main中声明的局部数组title用作函数createBook的参数表达式被隐式转换为指向其第一个元素的指针。并且所有函数调用都处理数组第一个元素的相同地址。

您需要为每个节点动态分配引用数组的副本title

另一种方法是将结构 Book 的数据成员 title 声明为具有字符数组类型而不是指针类型。

谢谢,现在一切正常!

我在 main 函数的 while 循环中就在 switch 语句之前为我的 char 指针分配了内存:

char *title = (char *) calloc(N, sizeof(char));

所以现在的工作代码如下所示:

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

#define N 255

struct Book {
    char *title;
    int year;
};

struct Node {
    struct Book book;
    struct Node *next;
};

struct Book createBook(char *title, int year) {
    struct Book book = {title, year};
    return book;
}

void print(struct Node *head) {
    struct Node *curr_node = head;

    while (curr_node != NULL) {
        printf("%s(%d)\n", curr_node->book.title, curr_node->book.year);
        curr_node = curr_node->next;
    }
}

void add(struct Node **head, struct Book book) {
    struct Node *new_node;
    struct Book *new_book;
    new_node = (struct Node*) malloc(sizeof( struct Node ));

    new_book = &new_node->book;

    new_book->title = book.title;
    new_book->year = book.year;

    new_node->next = (*head);
    *head = new_node;
}

void pop(struct Node **head) {
    struct Node *next_node = NULL;

    if (*head == NULL) {
        printf("List is empty!");
        return;
    }

    next_node = (*head)->next;
    free(*head);
    *head = next_node;
}

void reverse(struct Node **head) {
    struct Node *prev_node = NULL;
    struct Node *curr_node = *head;
    struct Node *next_node = NULL;

    while (curr_node != NULL) {
        next_node = curr_node->next;
        curr_node->next = prev_node;
        prev_node = curr_node;
        curr_node = next_node;
    }

    *head = prev_node;
}

void clear(struct Node **head) {

    struct Node *curr_node = *head;
    struct Node *temp_node = NULL;

    while (curr_node != NULL) {
        temp_node = curr_node->next;
        free(curr_node);
        curr_node = temp_node;
    }

    *head = NULL;
}

int main() {

    struct Node *head = NULL;

    short process = 1; // 1 for True 0 for False
    int option = 0;

    int year = 0;

    while (process) {

        printf("List of actions:\n");
        printf("1:\tAdd element\n");
        printf("2:\tRemove element\n");
        printf("3:\tReverse list\n");
        printf("4:\tPrint list\n");
        printf("5:\tClear list\n");
        printf("0:\tExit\n");

        scanf("%d", &option);
        char *title = (char *) calloc(N, sizeof(char));
        switch (option) {

            case 1:

                printf("Enter book\'s title: ");
                scanf("%s", title);
                printf("Enter book\'s year of publishing: ");
                scanf("%d", &year);
                add(&head, createBook(title, year));
                printf("\n");
                break;
            case 2:
                pop(&head);
                break;
            case 3:
                reverse(&head);
                break;
            case 4:
                print(head);
                break;
            case 5:
                clear(&head);
                break;
            case 0:
                process = 0;
                break;
            default:
                printf("\n");
                printf("**************************\n");
                printf("Enter numbers from 1 to 5!\n");
                printf("**************************\n");
                printf("\n");
                continue;
        }
    }
    return 0;
}