我对C字符串和宽C字符串有点困惑。为了这个问题,假设我使用的是Microsoft Visual Studio 2010 Professional。如果我的任何信息不正确,请告诉我。
我有一个带有const wchar_t *成员的结构,用于存储名称。
struct A
{
const wchar_t* name;
};
当我为对象'a'分配名称时:
int main()
{
A a;
const wchar_t* w_name = L"Tom";
a.name = w_name;
return 0;
}
这只是将w_name指向的内存地址复制到a.name中。现在,w_name和a.name都是宽字符指针,指向内存中的相同地址。
如果我是对的,那么我想知道如何应对这种情况。我正在使用tinyxml2从XML属性读取C字符串。
tinyxml2::XMLElement* pElement;
// ...
const char* name = pElement->Attribute("name");
收到我的C字符串后,我将其转换为宽字符串,如下所示:
size_t newsize = strlen(name) + 1;
wchar_t * wcName = new wchar_t[newsize];
size_t convertedChars = 0;
mbstowcs_s(&convertedChars, wcName, newsize, name, _TRUNCATE);
a.name = wcName;
delete[] wcName;
如果到目前为止我是正确的,那么行:
a.name = wcName;
只是将数组wcName的第一个字符的内存地址复制到a.name中。但是,我在分配这个指针后直接删除了wcName,这会使它指向垃圾。
如何将C字符串转换为宽字符C字符串,然后将其分配给a.name?
答案 0 :(得分:3)
最简单的方法可能是让你name
变量管理内存。反过来,这可以通过将其声明为
std::wstring name;
这些人没有独立内容和对象变异的概念,即你不能真正制作单个字符const
并使整个对象const
阻止它被分配到。
答案 1 :(得分:1)
可以在使用std::wstring
时执行此操作,而不依赖于额外的临时转换缓冲区分配和销毁。除非您过分关注堆碎片或在有限的系统(即Windows Phone)上,否则不是非常重要。它只需要在正面进行一些设置。让标准库为您管理内存(稍微轻推)。
class A
{
...
std::wstring a;
};
// Convert the string (I'm assuming it is UTF8) to wide char
int wlen = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, NULL);
if (wlen > 0)
{
// reserve space. std::wstring gives us the terminator slot
// for free, so don't include that. MB2WC above returns the
// length *including* the terminator.
a.resize(wlen-1);
MultiByteToWideChar(CP_UTF8, 0, name, -1, &a[0], wlen);
}
else
{ // no conversion available/possible.
a.clear();
}
在一个完整的附注中,你可以构建TinyXML以使用标准库和std::string
而不是char *
,这对你来说并没有多大帮助,但是稍后可能会为您节省吨以后的strlen()
来电。
答案 2 :(得分:0)
正如您正确提到的那样a.name
只是一个指针,它不会假设任何已分配的字符串存储空间。您必须使用new
或静态/作用域数组手动管理它。
要摆脱这些无聊的事情,只需使用一个可用的字符串类:来自ATL的CStringW
(易于使用,但特定于MS)或来自STL的std::wstring
(C ++标准,但不是那么容易要转换自char*
):
#include <atlstr.h>
// Conversion ANSI -> Wide is automatic
const CStringW name(pElement->Attribute("name"));
不幸的是,std::wstring
使用char*
并不容易。
请在此处查看转化功能:How to convert std::string to LPCWSTR in C++ (Unicode)