std::string 与 unsigned char[] 和 unsigned char* 有啥不同?

Posted

技术标签:

【中文标题】std::string 与 unsigned char[] 和 unsigned char* 有啥不同?【英文标题】:What's the different about std::string to unsigned char[] and unsigned char*?std::string 与 unsigned char[] 和 unsigned char* 有什么不同? 【发布时间】:2015-09-23 08:42:18 【问题描述】:

我从文件中得到一个字符串,并将该字符串转换为 unsinged char[]。 这是我的代码:

unsigned char c[16];
std::string message = ReadFile(); // get string from file
strcpy((char*)c,message.c_str());

并将字符串转换为无符号字符*

unsigned char* c;
std::string message = ReadFile(); // get string from file
c = (unsigned char*)message.c_str();

我不明白他们有什么不同。他们是一样的吗?

【问题讨论】:

string 是一个 c++ 对象,而 char[] 是一个 c 样式数组。在 C++ 中使用 char[] 是自找麻烦,而实际上有更好的解决方案。 【参考方案1】:

基础知识

unsigned char c[16]c 是一个由 16 个 unsigned char 组成的数组。

unsigned char* cc 是指向unsigned char 的指针(可能指向unsigned char 的连续序列(长度未知)的开头)

std::string ss 是一个字符串对象,它在内部保存一个连续的字符序列,其长度可以动态变化。字符串对象还保存了字符串的当前长度。


第一个代码示例

在这里,您创建了一个 16 字符的缓冲区,然后创建了一个 std::string 对象,并用 ReadFile 调用的结果填充该对象。

然后,您请求 std::string 对象的 C 字符串(以空结尾)表示,并使用 strcpy 将其复制到 16 字符缓冲区中。不幸的是,您没有检查大小,因此您可能会超出缓冲区的末尾并陷入未定义的行为。 不要这样做。您现在有两个数据副本; std::string 中的一个,以及 16 字符数组中的(部分)副本。


第二个代码示例

在第二个示例中,您再次将ReadFile 调用的结果分配给std::string,并再次调用c_str() 成员函数以请求以空值结尾的C 字符串表示。这一次,您只需cast 结果指针,使其类型为unsigned char*,并将其分配给您已声明的指针。您只有一份数据副本,并且没有缓冲区溢出。

但是,如果字符串的内容发生变化,指针c可能会失效。


指南

如果可能,请直接使用std::string。避免传递char* 或使用char 的数组,因为std::string 会跟踪大小,根据需要调整大小,并为您处理内存分配。

不要做第一个版本。这是不安全的,因为您不检查边界。

避免使用第二个版本;如果你有一个接受 C 字符串的函数,只需将s.c_str() 的结果直接作为参数给它:

void my_func(const char * str);

// ...

std::string s = "Hello";
my_func(s.c_str()); // This is fine!

[注意:这假定您的程序是单线程的,并且字符串s 具有本地范围,即对于my_funcmy_func 可以调用的任何内容的直接操作是不可见的。对s 的任何修改都可能使s.c_str() 返回的指针无效。]

如果您确实需要一个字符串内容的副本,只需在进行任何更改之前将其分配给另一个字符串:

std::string s1 = "Hello";
std::string s2 = s1; // copy the string
s1 = "Goodbye";
my_func(s2.c_str()); // still "Hello".

【讨论】:

你的回答很有用。非常感谢。【参考方案2】:

不,它们不一样。首先:将message 的内容复制到c。在第二个 - 您只需分配指针,将 c_str 返回到 c。因此,当消息被更改或销毁时,c 中将有垃圾。

【讨论】:

【参考方案3】:

在第一个示例中,字符串的内容被复制到数组中(尽管对于文件缓冲区而言,16 是一个相当短的长度)。现在您有两个不同的容器来保存相同的数据。

在第二个示例中,您读入字符串,然后将其容器的地址传递给指针。所以指针将指向与字符串相同的数据。但是,您无法将 const char * 转换为非 const 类型,因此您的示例可能无法编译。

您有什么理由首先转换为 c 样式的数组吗?

【讨论】:

以上是关于std::string 与 unsigned char[] 和 unsigned char* 有啥不同?的主要内容,如果未能解决你的问题,请参考以下文章

将非null终止的unsigned char数组复制到std :: string

复制 std::string::insert(int pos, char ch)

Swig:将 std::vector<unsigned char> 传递给从 c++ 生成的 c# 函数

为 ISO 8859-1 实现 basic_string<unsigned char>

std::wstring std::string w2m m2w

如何将 unsigned char 值表示为十六进制字符串?