You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

向链表添加字符串时所有历史节点值被新输入覆盖的问题求助

向链表添加字符串时所有历史节点值被新输入覆盖的问题求助

嘿,我一眼就看出问题所在啦!你遇到的这个情况,本质是所有链表节点都指向了同一块内存空间,导致新输入的内容会覆盖之前的所有节点数据。

问题根源

你用了一个全局的Name数组来存储输入的名字,每次调用scanf都会把新名字写入这个数组的内存地址里。而你的链表节点中visitor指针,直接赋值成了Name的地址(也就是append函数里的visitor参数,其实就是Name的指针)。这就意味着,不管你添加多少个节点,所有节点的visitor都指向同一块内存——也就是Name数组的地址。所以最后所有节点显示的,自然都是最后一次输入的内容。

解决办法

给每个链表节点的visitor分配独立的内存空间,用来存储对应的字符串,这样每个节点的数据就不会互相干扰了。有两种常见的实现方式:

方式1:用strdup函数(简单快捷)

strdup会自动帮你分配内存并复制字符串,直接修改append函数里的赋值语句就行:

// 原来的代码
// new_node->visitor = visitor;
// 修改为
new_node->visitor = strdup(visitor);

方式2:手动分配内存+复制字符串(更灵活,适合理解底层逻辑)

如果不想用strdup,可以手动用malloc分配内存,再用strcpy复制字符串:

// 计算字符串长度,分配足够的内存(+1是为了存储字符串结束符'\0')
new_node->visitor = (char*)malloc(strlen(visitor) + 1);
// 检查内存分配是否成功(好习惯)
if (new_node->visitor == NULL) {
    printf("内存分配失败!");
    free(new_node); // 释放已经分配的节点内存
    return;
}
// 把输入的字符串复制到新分配的内存里
strcpy(new_node->visitor, visitor);

额外提醒:记得释放内存

因为我们手动分配了内存,程序结束前一定要记得释放,避免内存泄漏。可以写一个专门的函数来释放链表:

void freeTicketList(struct ticket *head) {
    struct ticket *tempNode;
    while (head != NULL) {
        tempNode = head;
        head = head->nextPtr;
        // 先释放字符串的内存
        free(tempNode->visitor);
        // 再释放节点本身的内存
        free(tempNode);
    }
}

然后在main函数的return 0;之前调用这个函数:

freeTicketList(head);

修改后的完整代码示例

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

#define MAX 40

struct ticket
{
    char *visitor;
    struct ticket *nextPtr;
};

// insert a new value into ticket data list
void append(struct ticket **head_ref, char *visitor)
{
    // allocate node
    struct ticket *new_node = (struct ticket *)malloc(sizeof(struct ticket));
    struct ticket *last = *head_ref;

    // 给字符串分配独立内存并复制内容
    new_node->visitor = strdup(visitor);
    // 如果用手动分配的方式,替换上面这行:
    // new_node->visitor = (char*)malloc(strlen(visitor) + 1);
    // if (new_node->visitor == NULL) {
    //     printf("内存分配失败!");
    //     free(new_node);
    //     return;
    // }
    // strcpy(new_node->visitor, visitor);

    // This new node is the last node
    new_node->nextPtr = NULL;

    // If the Linked List is empty, then make the new node as head
    if (*head_ref == NULL)
    {
        *head_ref = new_node;
        return;
    }

    // Else traverse till the last node */
    while (last->nextPtr != NULL)
    {
        last = last->nextPtr;
    }

    // Change the next of last node
    last->nextPtr = new_node;
    return;
}

// This function prints contents of linked list starting from head
void printList(struct ticket *node)
{
    while (node != NULL)
    {
        printf("\n%s", node->visitor);
        node = node->nextPtr;
    }
}

// 释放链表内存的函数
void freeTicketList(struct ticket *head) {
    struct ticket *tempNode;
    while (head != NULL) {
        tempNode = head;
        head = head->nextPtr;
        free(tempNode->visitor);
        free(tempNode);
    }
}

char Name[31] = {'\0'};

int main(void)
{
    /* Start with the empty list */
    struct ticket *head = NULL;
    int i = 0;

    printf("Name: "); // instruction
    scanf("%[^\n]%*c", Name);
    append(&head, Name);
    printList(head);

    printf("\nName: "); // instruction
    scanf("%[^\n]%*c", Name);
    append(&head, Name);
    printList(head);

    // 释放链表内存
    freeTicketList(head);
    return 0;
}

这样修改后,你再输入名字就会得到你期望的结果啦!

备注:内容来源于stack exchange,提问作者Gary

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.23 07:08:16