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

C++无库分割字符数组:函数内输出正常实例调用结果异常问题

问题:SplitText实例调用后输出分割结果错误,内部printf却正常

你遇到的问题是:在SplitText的split函数内部打印分割结果时显示正确,但通过实例遍历splitTxt数组输出时结果错误。

核心原因:野指针问题

问题出在subTxt函数里的局部变量subTxt_:

char* subTxt(char* text, int index, int len)
{
    char subTxt_[1000]; // 这是栈上的局部数组
    // ... 赋值逻辑 ...
    return subTxt_; // 返回局部数组的地址
}

subTxt_是栈内存分配的局部变量,当subTxt函数执行完毕后,栈空间会被系统回收并可能被后续操作覆盖。在split函数内部刚调用完subTxt时,栈还没被覆盖,所以此时打印指针指向的内容是正确的;但当split函数执行完毕回到主函数后,原来的栈空间已经被其他数据覆盖,此时splitTxt里的指针就变成了野指针,访问它会导致未定义行为(输出乱码或程序崩溃)。

解决方案

解决思路是避免返回局部栈变量的指针,以下是几种可行的方案:

方案1:使用动态内存分配(malloc)

在subTxt中用malloc分配堆内存,这样内存不会随函数返回被释放,使用完后记得手动释放避免内存泄漏:

typedef struct SplitText
{
    int splitLen;
    char* splitTxt[100];
    char* subTxt(char* text, int index, int len)
    {
        // 分配足够内存(+1用于存储字符串终止符'\0')
        char* subTxt_ = (char*)malloc(len + 1);
        if (subTxt_ == NULL) {
            // 内存分配失败时返回NULL,可根据需求添加错误处理
            return NULL;
        }
        int count = 0;
        for (int i = index; i < index + len; i++) {
            subTxt_[count++] = text[i];
        }
        // 必须添加字符串终止符,否则printf会读取到垃圾数据
        subTxt_[count] = '\0';
        return subTxt_;
    }

    void split(char* text, char sep)
    {
        char separator[3] = { '<', sep, '>' };
        int textLen = strlen(text);
        int splitIndex = 0;
        int splitCount = 0;
        for (int t = 0; t < textLen; t++)
        {
            // 注意:t+2不能超过textLen-1,否则会越界访问
            if (t + 2 >= textLen) break;
            if (text[t] == separator[0] && text[t + 1] == separator[1] && text[t + 2] == separator[2])
            {
                if (splitIndex != 0)
                    splitIndex += 3;
                splitTxt[splitCount] = subTxt(text, splitIndex, t - splitIndex);
                splitIndex = t;
                
                splitCount++;
            }
        }
        splitLen = splitCount;
    }
}SplitText;

使用时记得释放内存:

SplitText st;
st.split("testing<=>split<=>function<=>", '=');
for (int i = 0; i < st.splitLen; i++)
{
    printf("%s\n", st.splitTxt[i]);
    free(st.splitTxt[i]); // 释放每个动态分配的字符串
}
printf("--------\n");

方案2:在结构体中预分配缓冲区

如果确定分割后的字符串长度不会超过固定值,可以把splitTxt改成二维字符数组,避免动态内存分配:

typedef struct SplitText
{
    int splitLen;
    char splitTxt[100][1000]; // 最多100个分割结果,每个最多999字符+终止符
    void subTxt(char* dest, char* text, int index, int len)
    {
        int count = 0;
        // 先清空目标缓冲区
        memset(dest, 0, 1000);
        for (int i = index; i < index + len; i++) {
            dest[count++] = text[i];
        }
    }

    void split(char* text, char sep)
    {
        char separator[3] = { '<', sep, '>' };
        int textLen = strlen(text);
        int splitIndex = 0;
        int splitCount = 0;
        for (int t = 0; t < textLen; t++)
        {
            if (t + 2 >= textLen) break;
            if (text[t] == separator[0] && text[t + 1] == separator[1] && text[t + 2] == separator[2])
            {
                if (splitIndex != 0)
                    splitIndex += 3;
                // 直接把结果写入结构体的缓冲区
                subTxt(splitTxt[splitCount], text, splitIndex, t - splitIndex);
                splitIndex = t;
                
                splitCount++;
            }
        }
        splitLen = splitCount;
    }
}SplitText;

这种方案不需要手动释放内存,但要注意缓冲区大小是否满足需求。

额外注意事项

  • 原代码中split函数的循环存在越界风险:当t接近字符串末尾时,t+2会超出字符串长度,导致访问非法内存,需要添加判断if (t + 2 >= textLen) break;避免越界。
  • 字符串操作必须保证以'\0'结尾,否则printf等字符串函数会读取到内存中的垃圾数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 13:30:52