向链表添加字符串时所有历史节点值被新输入覆盖的问题求助
向链表添加字符串时所有历史节点值被新输入覆盖的问题求助
嘿,我一眼就看出问题所在啦!你遇到的这个情况,本质是所有链表节点都指向了同一块内存空间,导致新输入的内容会覆盖之前的所有节点数据。
问题根源
你用了一个全局的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
相关产品推荐
相关产品推荐

