LPCWSTR数组初始化异常:仅首个成员生效的问题排查
我正在编写调用Win32函数RmRegisterResources的代码,该函数接收LPCWSTR[]类型的文件路径列表作为参数。尝试组装LPCWSTR数组时,始终只有第一个成员初始化成功。
我的实现代码如下:
void Test(std::vector<LPCWSTR> input) { size_t vecsize = input.size(); LPCWSTR* resourcelist = new LPCWSTR[vecsize]; for (size_t i = 0; i < input.size(); i++) { LPCWSTR single = input.at(i); size_t strsize = wcslen(single); resourcelist[i] = new WCHAR[strsize]; wcscpy_s((WCHAR*)resourcelist[i], strsize, single); } /* The rest of the code... */ }
现象
循环第一次迭代时,第一个字符串复制正常;第二次迭代时wcscpy_s未报错,但无法找到复制后的字符串。最终调用RmRegisterResources时仅第一个复制的字符串生效。
补充说明
我不是开发人员,是一名好奇的系统管理员,正在学习C++。已经连续两天搜索解决方案。根据微软文档,建议一次性传入多个文件名,因为操作成本较高。
编辑1:关于vector input.data()的问题
尝试使用input.data()直接作为参数传给RmRegisterResources时,编译器报错,提示无法将const wchar_t**转换为LPCWSTR*(类型不匹配)。
编辑2:常量数组正常工作
如果用常量值创建数组可以正常调用,示例代码:
LPCWSTR string[2] = { L"Thisisastring", L"Thisisalso" };
但使用LocalAlloc或new关键字分配内存时会出现上述问题。
1. 核心问题:内存分配未考虑字符串终止符
wcslen(single)返回的是字符串的有效宽字符数,不包含末尾的\0终止符。你用new WCHAR[strsize]分配的内存刚好容下有效字符,但wcscpy_s会自动添加\0终止符,导致内存越界,破坏后续数组元素的内存,从而出现异常。
2. 修正后的代码
分配内存时给终止符预留1个字符的空间:
void Test(std::vector<LPCWSTR> input) { size_t vecsize = input.size(); LPCWSTR* resourcelist = new LPCWSTR[vecsize]; for (size_t i = 0; i < input.size(); i++) { LPCWSTR single = input.at(i); size_t strsize = wcslen(single) + 1; // 加1容纳宽字符终止符\0 resourcelist[i] = new WCHAR[strsize]; wcscpy_s((WCHAR*)resourcelist[i], strsize, single); } // 调用RmRegisterResources... // 记得释放内存,避免泄漏 for (size_t i = 0; i < vecsize; i++) { delete[] resourcelist[i]; } delete[] resourcelist; }
3. 更简洁的替代方案(无需复制内存)
如果input中的LPCWSTR指向的字符串在调用RmRegisterResources期间不会被释放或修改,你可以直接复用这些指针,不需要重新分配内存:
void Test(std::vector<LPCWSTR> input) { if (input.empty()) return; // 直接用vector的data()获取数组指针 LPCWSTR* resourcelist = input.data(); // 调用RmRegisterResources,传入resourcelist和input.size()即可 // ... }
如果之前用input.data()报错,大概率是因为你的input实际类型是std::vector<std::wstring>而非std::vector<LPCWSTR>。这种情况下,可以先把std::wstring的c_str()收集到临时的vector<LPCWSTR>中:
void Test(std::vector<std::wstring> input) { std::vector<LPCWSTR> str_ptrs; str_ptrs.reserve(input.size()); for (const auto& str : input) { str_ptrs.push_back(str.c_str()); } // 调用RmRegisterResources RmRegisterResources(... , str_ptrs.size(), str_ptrs.data(), ...); }
内容的提问来源于stack exchange,提问作者FranciscoNabas

