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

C语言链表字符串分割问题:节点数据损坏及段错误求助

字符串分割链表的段错误与数据损坏问题分析与修复

问题描述

用结构体实现链表按分隔符分割字符串时,第一个字符串可正常输出,但第二个字符串是随机字符,第三个及之后节点触发Segmentation fault(段错误)。代码如下:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct strliststruct{
    char* string;
    unsigned long long length;
    struct strliststruct* prior;
    struct strliststruct* later;
    int exist_prior;
    int exist_later;
}strlist;

strlist init_strlist(){
    strlist ans;
    ans.exist_later=0;
    ans.exist_prior=0;
    ans.length=0;
    return ans;
}

strlist init_strlist_with_string(char* str,char splitter){
    strlist ans=init_strlist(),next;
    unsigned long long i;
    for(i=0;1;i++){
        if(str[i]==splitter){
            next=init_strlist_with_string(&str[i+1],splitter);
            ans.later=&next;
            ans.exist_later=1;
            next.exist_prior=1;
            next.prior=&ans;
        }else if(str[i]!='\0'){continue;}
        ans.string=malloc(sizeof(char)*(i+1));
        ans.string[i]='\0';
        for(unsigned long long j=0;j<i;j++){
            ans.string[j]=str[j];
        }
        break;
    }
    return ans;
}
int main(){
    strlist sl=init_strlist_with_string("I am a human",' ');
    while(1){
        printf("%s\n",sl.string);
        if(sl.exist_later){sl=*sl.later;}else break;
    }
    return 0;
}

核心错误原因

  • 局部变量指针悬空:init_strlist_with_string函数中,next是栈上的局部变量,将&next赋值给ans.later后,函数返回时next的栈内存会被释放,ans.later变成野指针。后续访问*sl.later时,读取的是已经被回收的内存,导致数据错乱或段错误。
  • 栈内存滥用:所有链表节点都是栈上的局部变量,而非堆内存分配。递归调用结束后,栈帧被销毁,节点内存失效,后续访问必然触发非法内存操作。
  • 未初始化关键字段:length字段未被赋值,属于逻辑漏洞,可能影响后续链表操作的正确性。

修复方案与代码

将链表节点改为堆内存分配,调整递归逻辑以正确维护指针关系,同时补全length字段的赋值:

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

typedef struct strliststruct{
    char* string;
    unsigned long long length;
    struct strliststruct* prior;
    struct strliststruct* later;
    int exist_prior;
    int exist_later;
}strlist;

// 初始化单个节点(堆分配)
strlist* init_strlist(){
    strlist* ans = malloc(sizeof(strlist));
    if (!ans) return NULL;
    ans->exist_later = 0;
    ans->exist_prior = 0;
    ans->length = 0;
    ans->string = NULL;
    ans->prior = NULL;
    ans->later = NULL;
    return ans;
}

// 递归分割字符串并创建链表
strlist* init_strlist_with_string(char* str, char splitter){
    strlist* ans = init_strlist();
    if (!ans) return NULL;

    unsigned long long i = 0;
    // 找到分隔符或字符串结束位置
    while (str[i] != splitter && str[i] != '\0') {
        i++;
    }

    // 分配并复制当前段字符串
    ans->string = malloc(sizeof(char) * (i + 1));
    if (!ans->string) {
        free(ans);
        return NULL;
    }
    strncpy(ans->string, str, i);
    ans->string[i] = '\0';
    ans->length = i;

    // 如果不是字符串结尾,递归创建后续节点
    if (str[i] == splitter) {
        ans->later = init_strlist_with_string(&str[i+1], splitter);
        if (ans->later) {
            ans->exist_later = 1;
            ans->later->exist_prior = 1;
            ans->later->prior = ans;
        }
    }

    return ans;
}

// 遍历链表并释放内存
void free_strlist(strlist* head){
    strlist* temp;
    while (head) {
        temp = head;
        head = head->later;
        free(temp->string);
        free(temp);
    }
}

int main(){
    strlist* sl = init_strlist_with_string("I am a human", ' ');
    strlist* current = sl;
    while (current) {
        printf("%s\n", current->string);
        current = current->later;
    }
    free_strlist(sl);
    return 0;
}

修复说明

  1. 堆内存分配节点:所有链表节点通过malloc在堆上分配,避免栈内存回收导致的野指针问题。
  2. 修正指针关系:递归创建的后续节点直接赋值给当前节点的later字段,指针指向堆内存,不会失效。
  3. 补全字段初始化:正确设置length字段,并新增内存释放函数free_strlist,避免内存泄漏。
  4. 简化字符串复制逻辑:用strncpy替代手动循环复制,代码更简洁可靠。

内容的提问来源于stack exchange,提问作者Altus83765

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 06:32:39