std::string 到 unsigned char[] 和 unsigned char* 有什么不同?

What's the different about std::string to unsigned char[] and unsigned char*?

本文关键字:char unsigned 什么 string std      更新时间:2023-10-16

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

unsigned char c[16];
std::string message = ReadFile(); // get string from file
strcpy((char*)c,message.c_str());
并将字符串转换为unsigned char*
unsigned char* c;
std::string message = ReadFile(); // get string from file
c = (unsigned char*)message.c_str();
我不明白他们有什么不同。它们是一样的吗?

基础知识

unsigned char c[16]: c是一个包含16个unsigned char的数组。

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

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


第一个代码示例

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

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


第二个代码示例

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

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


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

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

  • 避免第二个版本;如果你有一个接受C-string的函数,只需将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()返回的指针失效。[/p>
  • 如果你真的需要一个字符串内容的副本,只要在你做任何改变之前把它赋值给另一个字符串:

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

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

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

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

首先转换为c风格数组有什么原因吗?