C语言链表动态插入字符串异常:所有元素被新元素覆盖问题排查
问题分析与解决方案
嘿,我一眼就揪出问题所在啦!你遇到的所有链表元素都变成最后插入内容的情况,核心原因是你一直在复用同一块栈内存的指针,所有链表节点都指向了同一个地方。
为什么会这样?
你看main函数里的currentline是在while循环内部定义的栈数组,每次循环时,这块内存的地址是固定不变的(栈上的位置不会变)。你调用insert(currentline, lines)的时候,只是把这个数组的地址赋值给了链表节点的val字段。
当循环到最后一次时,currentline里的内容被覆盖成最后一行的输入,而所有链表节点的val都指向这块栈内存,所以打印的时候自然全是最后一行的内容。
另外还有两个隐藏小问题:
- 你没有给
currentline添加字符串终止符'\0',这会导致printf或者字符串处理函数读取到垃圾内容,直到遇到内存中的随机'\0'。 char a的定义有问题:getchar()返回的是int类型(包含字符ASCII值或EOF),如果你的系统中char是无符号类型,EOF会被转成正数,导致无法正确判断循环结束条件。
修复后的代码
我修改了main函数的关键部分,同时修复了这些隐藏问题:
#include "listd.h" #include <stdio.h> #include <string.h> // 用于strdup和字符串操作 #include <stdlib.h> // 用于perror void show(Value v) { printf("%s\n", v); // 用%s更安全,避免字符串含%字符导致printf出错 } int main( void ) { List lines = init(); int a; // 改成int类型,正确存储getchar的返回值(包括EOF) // 先读取字符再判断,避免a初始值未定义的问题 while((a = getchar()) != EOF){ char currentline[256] = {0}; // 初始化为全0,也可以后面手动加'\0' int i = 0; while(a != '\n' && a != EOF){ if(i < 255){ // 防止数组越界,最多存255个字符+1个终止符 currentline[i] = a; i++; } a = getchar(); } currentline[i] = '\0'; // 手动添加字符串终止符,确保是合法C字符串 // 为每行分配独立的堆内存,复制内容 char* line_copy = strdup(currentline); if(line_copy == NULL){ // 检查内存分配是否成功 perror("Failed to allocate memory for line"); return 1; } lines = insert(line_copy, lines); // 插入堆内存的指针,而非栈数组的指针 } iterate(lines, show); // 别忘了释放内存,避免泄漏 List temp_node; while(lines != NULL){ temp_node = lines; lines = lines->next; free(temp_node->val); // 先释放字符串的堆内存 free(temp_node); // 再释放链表节点本身 } return 0; }
关键修改点说明
- 改用int存储getchar返回值:确保能正确识别EOF,避免循环无法终止。
- 添加字符串终止符:让currentline成为合法的C字符串,避免后续操作出现未定义行为。
- 使用strdup分配堆内存:
strdup会自动分配足够的内存并复制字符串内容,每个链表节点的val都指向独立的堆内存,不会被后续循环覆盖。如果你的环境不支持strdup,也可以用malloc(strlen(currentline)+1)+strcpy来替代。 - 添加内存释放逻辑:程序结束前释放链表节点和字符串的内存,养成良好的内存管理习惯。
- 优化show函数的printf调用:用
%s格式化输出,避免字符串中包含特殊字符(比如%)导致的printf解析错误。
内容的提问来源于stack exchange,提问作者Ben
相关产品推荐
相关产品推荐

