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

C语言链表动态插入字符串异常:所有元素被新元素覆盖问题排查

问题分析与解决方案

嘿,我一眼就揪出问题所在啦!你遇到的所有链表元素都变成最后插入内容的情况,核心原因是你一直在复用同一块栈内存的指针,所有链表节点都指向了同一个地方。

为什么会这样?

你看main函数里的currentline是在while循环内部定义的栈数组,每次循环时,这块内存的地址是固定不变的(栈上的位置不会变)。你调用insert(currentline, lines)的时候,只是把这个数组的地址赋值给了链表节点的val字段。

当循环到最后一次时,currentline里的内容被覆盖成最后一行的输入,而所有链表节点的val都指向这块栈内存,所以打印的时候自然全是最后一行的内容。

另外还有两个隐藏小问题:

  1. 你没有给currentline添加字符串终止符'\0',这会导致printf或者字符串处理函数读取到垃圾内容,直到遇到内存中的随机'\0'。
  2. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:40:14