使用strtok读取字符串时出现Error reading character of String错误求助
老哥,你遇到的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

