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

使用strtok读取字符串时出现Error reading character of String错误求助

解决strtok导致的0xCCCCCCCC内存访问错误

老哥,你遇到的0xCCCCCCCC地址错误和"Error reading characters of string"提示,本质是访问了未初始化或已失效的内存。结合你贴的核心代码,我帮你拆解几个关键问题和对应的修复方案:

1. 最可能的元凶:strtok修改了只读字符串

strtok的第一个参数会被它直接修改(把分隔符替换成\0),如果你的str是字符串字面量(比如char* str = "hello,world";),那它存在程序的只读内存区,修改这种内存会触发未定义行为,直接导致后续的nv指向无效地址(比如0xCCCCCCCC)。

修复方案:
把传入的字符串复制到一块可写的内存里再传给strtok:

// 先复制原字符串到可写内存
char* writableStr = new char[strlen(str) + 1];
strcpy(writableStr, str);
// 用writableStr代替原str调用strtok
nv = strtok(writableStr, sep);

⚠️ 注意:如果你的tot数组里存的是writableStr的片段,那writableStr不能在函数内部释放,否则tot里的所有指针都会失效;或者你可以把每个子串单独复制一份(比如用strdup),这样就能安全释放writableStr了。

2. 循环逻辑不完整+越界风险

你的代码里nv = strtok(...没写完,正确的后续调用应该是nv = strtok(NULL, sep);——strtok第一次调用传目标字符串,后续调用传NULL才能继续分割剩下的内容。

另外,你没有检查i是否超过sizeRet,如果分割出的子串数量比sizeRet大,会导致tot[i]越界写入,破坏内存结构,也可能让nv变成无效值。

修复方案:
完善循环逻辑并加上边界检查:

int i = 0;
char * nv = strtok(writableStr, sep);
while (nv != NULL && i < sizeRet) {
    tot[i] = nv; // 或者复制子串:tot[i] = strdup(nv);
    i++;
    nv = strtok(NULL, sep); // 这里要传NULL
}

3. 未初始化的指针隐患

你分配的tot数组里的指针默认是未初始化的,如果分割出的子串数量少于sizeRet,后续访问tot里未赋值的元素就会指向0xCCCCCCCC(VS调试模式下未初始化内存的标记)。

修复方案:
初始化tot里的所有指针为NULL:

char ** tot = new char *[sizeRet];
// 初始化每个指针为NULL
for (int j = 0; j < sizeRet; j++) {
    tot[j] = NULL;
}

4. 内存泄漏问题(顺带解决)

你分配的sep数组没有释放,长期运行会导致内存泄漏,虽然不是直接导致当前错误,但也得修复:

// 在函数结束前释放sep
delete[] sep;

完整修正后的示例代码

char** splitStr(char* str, char separator, int sizeRet) {
    // 先处理非法输入
    if (str == NULL || sizeRet <= 0) {
        return NULL;
    }

    // 复制原字符串到可写内存
    char* writableStr = new char[strlen(str) + 1];
    if (writableStr == NULL) {
        return NULL;
    }
    strcpy(writableStr, str);

    // 初始化结果数组,所有指针设为NULL
    char ** tot = new char *[sizeRet];
    for (int j = 0; j < sizeRet; j++) {
        tot[j] = NULL;
    }

    char * sep = new char[2];
    sep[0] = separator;
    sep[1] = '\0';

    char * nv = strtok(writableStr, sep);
    int i = 0;
    while (nv != NULL && i < sizeRet) {
        // 这里选择复制子串,避免依赖writableStr的生命周期
        tot[i] = strdup(nv);
        i++;
        nv = strtok(NULL, sep);
    }

    // 释放临时内存
    delete[] sep;
    delete[] writableStr;

    return tot;
}

调用后的内存释放

因为上面的代码用了strdup复制子串,调用完后要记得释放内存:

char** result = splitStr("a,b,c,d", ',', 4);
// 使用result...
// 释放内存
for (int j = 0; j < 4; j++) {
    if (result[j] != NULL) {
        free(result[j]); // strdup分配的内存用free释放
    }
}
delete[] result;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 06:55:42