C语言CSV的SQL处理:未复制TCHAR*参数导致结果失真问题
问题根源分析与修复
你的代码出现字符串失真的核心原因是未定义行为导致的内存越界与错误的内存分配,而非必须复制输入参数本身,以下是具体分析:
1. 致命的循环条件错误
SplitStr中的while循环条件while (i < MAXSTR - strlen1)完全不符合逻辑:
strlen1是输入字符串的实际长度,MAXSTR - strlen1计算的是字符串末尾到MAXSTR缓冲区剩余的空间,而非字符串的有效范围。- 当i超过
strlen1后,&str[i]会访问字符串末尾之外的未知内存,触发未定义行为:可能覆盖原字符串中未处理的部分(比如你保存的where指向的内容),或者破坏SplitStr返回的指针数组split的结构。
正确的循环条件应该是遍历整个有效字符串:
while (i < strlen1) {
2. 内存分配大小错误
分配分割结果的内存时,你使用了sizeof(TCHAR*):
res[c] = malloc(MAXSTR * sizeof(TCHAR*));
但res[c]是指向TCHAR数组的指针,应该分配的是MAXSTR个TCHAR的空间,正确写法是:
res[c] = malloc(MAXSTR * sizeof(TCHAR));
错误的分配大小会导致缓冲区溢出,当复制字符串时破坏相邻内存区域,这也是where内容失真的重要原因。
3. 为什么复制参数能"临时解决"问题
当你用_tcsdup复制输入字符串后:
- 复制后的字符串是独立的内存块,越界访问只会破坏这个临时块,不会影响原字符串中的
where部分内容。 - 但这只是掩盖了核心错误,并未真正解决问题,后续仍可能出现其他内存异常。
修正后的SplitStr代码
#define SplitCount 20 TCHAR** SplitStr(TCHAR* pstr, TCHAR *psplitby) { if (pstr == NULL || psplitby == NULL) return NULL; TCHAR** res = malloc(SplitCount * sizeof(TCHAR*)); if (res == NULL) // 新增:检查malloc是否成功 return NULL; int i = 0, j = 0, c = 0; // 可选:如果输入字符串是只读的(比如字面量),复制是必要的;否则可直接使用原指针 TCHAR* splitby = psplitby; int len = _tcslen(splitby); TCHAR* str = pstr; int strlen1 = _tcslen(str); while (i < strlen1) { // 修正循环条件 if (i + len <= strlen1 && _tcsncmp(splitby, &str[i], len) == 0) // 修正边界判断,避免越界 { res[c] = malloc(MAXSTR * sizeof(TCHAR)); // 修正内存分配大小 if (res[c] == NULL) break; // 复制后添加字符串结束符,避免乱码 _tcsncpy_s(res[c], MAXSTR, &str[j], i - j); res[c][i - j] = _T('\0'); i += len; j = i; c++; } i++; } // 处理最后一段 res[c] = malloc(MAXSTR * sizeof(TCHAR)); if (res[c] != NULL) { _tcsncpy_s(res[c], MAXSTR, &str[j], strlen1 - j); res[c][strlen1 - j] = _T('\0'); // 添加结束符 c++; } res[c] = _tcsdup(_T("END")); return res; }
额外补充:
- 调用
_tcsncpy_s后需要手动添加\0结束符,否则字符串可能包含垃圾数据。 - 新增
res的malloc成功检查,避免空指针访问。 - 修正
i + len < strlen1为i + len <= strlen1,避免漏掉字符串末尾刚好匹配分隔符的情况。
内容的提问来源于stack exchange,提问作者Mostafa Asghari
相关产品推荐
相关产品推荐

