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
相关产品推荐
相关产品推荐

