调用WriteConsoleW后释放宽字符串内存致崩溃,是否需释放?
控制台宽字符串释放崩溃问题分析
崩溃原因
程序崩溃的核心原因是内存分配与释放函数不匹配:
- 你的
CHARtoWCHAR函数使用Windows API的LocalAlloc(LPTR)分配宽字符串内存 - 但在
console_print中却用C标准库的free()释放这块内存 - C标准库的内存管理函数(
malloc/free等)和Windows本地堆函数(LocalAlloc/LocalFree等)属于不同的堆管理体系,混用会直接导致堆结构损坏,触发程序崩溃。
另外,WriteConsoleW不会自动释放传入的缓冲区,你必须自行负责内存的释放工作,但必须保证分配和释放函数的匹配性。
解决方案
将释放ws的代码从free(ws);替换为Windows API的LocalFree(ws);,同时可以补充一些健壮性检查:
修正后的console_print函数
void console_print(const char *fmt, ...) { va_list args; va_start(args, fmt); char *buf = smprintf(fmt, args); va_end(args); if (buf == NULL) { return; } DWORD cCharsWritten; // 用于接收实际写入的字符数 HANDLE std_out = GetStdHandle(STD_OUTPUT_HANDLE); LPWSTR ws = CHARtoWCHAR(buf, CP_ACP); if (ws != NULL) { // 检查宽字符串分配是否成功 WriteConsoleW(std_out, ws, wcslen(ws), &cCharsWritten, NULL); LocalFree(ws); // 使用LocalFree匹配LocalAlloc的分配 } free(buf); }
额外注意事项
- 始终检查
CHARtoWCHAR的返回值:如果LocalAlloc分配失败,会返回NULL,此时调用wcslen或WriteConsoleW会引发新的错误 WriteConsoleW的第四个参数如果传NULL,虽然函数可以正常执行,但无法获取实际写入控制台的字符数;传入有效的DWORD变量可以帮助调试或处理写入异常的情况
原函数代码参考
CHARtoWCHAR函数
LPWSTR CHARtoWCHAR(LPSTR str, UINT codePage) { size_t len = strlen(str) + 1; int size_needed = MultiByteToWideChar(codePage, 0, str, len, NULL, 0); LPWSTR wstr = (LPWSTR) LocalAlloc(LPTR, sizeof(WCHAR) * size_needed); if (wstr != NULL) { // 补充分配成功检查 MultiByteToWideChar(codePage, 0, str, len, wstr, size_needed); } return wstr; }
smprintf函数
// Creates a buffer and fills it with a string formatted with the specified // format and arguments. Caller must free the buffer after usage. char *smprintf(const char *fmt, ...) { va_list args; // 1. Measure the required size of buffer. va_start(args, fmt); int len = vsnprintf(NULL, 0, fmt, args); va_end(args); // 2. Create the buffer. char *buf = malloc(++len); if (buf == NULL) { return NULL; } // 3. Fill the buffer. va_start(args, fmt); vsnprintf(buf, len, fmt, args); va_end(args); return buf; // Do not forget to use: free(x). }
内容的提问来源于stack exchange,提问作者user17471643
相关产品推荐
相关产品推荐

