如何从std::string获取持久char*指针 调用free时不出现堆损坏
问题根因
你出现堆损坏的核心原因是字符串内存分配长度未包含C风格字符串必备的末尾空终止符\0:
- C标准库的
strlen()函数返回的是字符串的有效字符长度,不计算末尾隐含的\0占位 - 你调用
malloc(strlen(xxx)*sizeof(char))时仅分配了有效字符的空间,后续strcpy会额外写入1字节的\0到已分配内存的边界外,直接触发堆溢出损坏
你在释放前能正常打印字符串是因为\0虽然写越界了,但刚好落在堆的未使用保护区里,没有立刻触发异常,直到释放时CRT检查堆完整性才会报损坏错误。
修复方案
方案1:直接修正现有分配逻辑
给每处malloc的长度加1,预留空终止符的位置即可:
ResultItemAttributeClass theAttribute; char* tmpObtainedValueName = (char*)obtainedValue.Name(); // 长度+1预留\0位置 theAttribute.AttributeName = (char*)malloc((strlen(tmpObtainedValueName) + 1) * sizeof(char)); strcpy(theAttribute.AttributeName, tmpObtainedValueName); string tmpObtainedValueType0 = obtainedValue.aDesc->TypeName(); char* tmpObtainedValueType = (char*) tmpObtainedValueType0.c_str(); theAttribute.AttributeType = (char*)malloc((strlen(tmpObtainedValueType) + 1) * sizeof(char)); strcpy(theAttribute.AttributeType, tmpObtainedValueType); string tmpAttributeValue0= obtainedValue.asStr(); char* tmpAttributeValue = (char*) tmpAttributeValue0.c_str(); theAttribute.AttributeValue = (char*)malloc((strlen(tmpAttributeValue) + 1) * sizeof(char)); strcpy(theAttribute.AttributeValue, tmpAttributeValue);
方案2:封装通用安全实现(推荐)
如果要避免重复写分配逻辑,还可以封装专用的std::string转持久化char*函数,同时兼容跨DLL场景:
// 通用转换函数,自动处理内存分配和空终止符 char* StringToPersistentCharPtr(const std::string& src) { size_t strLen = src.size(); char* buf = (char*)malloc(strLen + 1); if (buf != nullptr) { memcpy(buf, src.c_str(), strLen); buf[strLen] = '\0'; } return buf; } // 调用时大幅简化代码 theAttribute.AttributeName = StringToPersistentCharPtr(obtainedValue.Name()); theAttribute.AttributeType = StringToPersistentCharPtr(obtainedValue.aDesc->TypeName()); theAttribute.AttributeValue = StringToPersistentCharPtr(obtainedValue.asStr());
额外注意事项
如果修复分配长度后仍然出现内存异常,请确认DLL和调用方使用的CRT运行库版本完全一致(同用动态CRT/同用静态CRT),如果分配操作在DLL的CRT堆执行、释放在调用方的CRT堆执行,也会触发内存错误。
内容的提问来源于stack exchange,提问作者Ivan P.
相关产品推荐
相关产品推荐

