【问题标题】:std::string.c_str() has different value than std::string?std::string.c_str() 的值与 std::string 不同吗?
【发布时间】:2012-05-08 22:11:17
【问题描述】:

我一直在使用 C++ 字符串并尝试使用 C 函数(例如 strcpy())将 char * 字符串加载到 std::string 中。由于strcpy()char * 作为参数,因此我必须将其转换为如下所示:

std::string destination;
unsigned char *source;
strcpy((char*)destination.c_str(), (char*)source);

代码运行良好,当我在调试器中运行程序时,*source 的值存储在 destination 中,但由于某些奇怪的原因,它不会与语句一起打印出来

std::cout << destination;

我注意到如果我使用

std::cout << destination.c_str();

值打印正确,一切正常。为什么会这样?有没有更好的方法将unsigned char*char* 复制到std::string(字符串流?)这似乎只有在我在复制操作中将字符串指定为foo.c_str() 时才会发生。

编辑:为了回答“你为什么要这样做?”这个问题,我使用strcpy() 作为一个简单的例子。有时它比分配更复杂。例如,必须使用 strncpy() 将仅 X 数量的字符串 A 复制到字符串 B 中,或者将 std::string 传递给 C 库中的函数,该函数将 char * 作为缓冲区的参数。

【问题讨论】:

  • 所以,您忽略了编译器给您的错误并决定将其关闭并将其转换为 (char*)?你想知道为什么你有问题吗?
  • 你为什么不直接使用:destination = source;
  • 所有答案都问隐含的问题,为什么?为什么?
  • c_str() 返回 const 是有原因的。
  • 不要使用 C 转换。它隐藏了错误(比如这个)。

标签: c++ cstring stdstring


【解决方案1】:

这就是你想要的

 std::string destination = source;

你所做的在很多层面上都是错误的......你正在写 std::string 的内部表示......我的意思是......不是很酷的人......它比这更复杂,正在调整大小的数组,只读内存......作品。

【讨论】:

【解决方案2】:

这根本不是一个好主意,原因有两个:

  1. destination.c_str() 是一个 const 指针,丢弃它的 const 并写入它是未定义的行为。
  2. 您没有设置字符串的大小,这意味着它甚至不需要足够大的缓冲区来保存可能导致访问冲突的字符串。

std::string 有一个构造函数,它允许从char* 构造它,所以只需编写:

std::string destination = source

【讨论】:

    【解决方案3】:

    嗯,你正在做的是未定义的行为。您的 c_str() 返回一个 const char * 并且不打算分配给。为什么不使用定义的构造函数或赋值运算符。

    【讨论】:

      【解决方案4】:

      std::string defines an implicit conversionconst char*std::string... 所以使用它。

      您决定放弃一个错误,因为c_str() 返回一个const char*,即它不允许写入其底层缓冲区。您已尽一切努力解决这个问题,但没有奏效(您不应该对此感到惊讶)。

      c_str() 有充分的理由返回 const char*。您不知道该指针是否指向字符串的底层缓冲区。你不知道这个指针是否指向一个足够大的内存块来保存你的新字符串。该库正在使用它的接口来准确地告诉您应该如何使用 c_str() 的返回值,而您完全忽略了这一点。

      【讨论】:

        【解决方案5】:

        不要做你正在做的事情!!!

        我再说一遍!

        不要做你正在做的事!!!

        当你做一些奇怪的事情时它似乎有点工作是字符串类是如何实现的结果。你几乎可以肯定是在记忆中写你不应该写的东西和一堆其他虚假的东西。

        当您需要与写入缓冲区的 C 函数进行交互时,有两种基本方法:

        std::string read_from_sock(int sock) {
            char buffer[1024] = "";
        
            int recv = read(sock, buffer, 1024);
            if (recv > 0) {
              return std::string(buffer, buffer + recv);
            }
            return std::string();
        }
        

        或者你可以试试 peek 方法:

        std::string read_from_sock(int sock) {
        
            int recv = read(sock, 0, 0, MSG_PEEK);
            if (recv > 0) {
              std::vector<char> buf(recv);
              recv = read(sock, &buf[0], recv, 0);
              return std::string(buf.begin(), buf.end());
            }
            return std::string();
        }
        

        当然,这些不是非常强大的版本……但它们说明了这一点。

        【讨论】:

          【解决方案6】:

          首先你应该注意c_str返回的值是const char*,不能修改。实际上它甚至不必指向string的内部缓冲区。

          【讨论】:

            【解决方案7】:

            响应您的编辑:

            只需使用 strncpy() 将 X 数量的字符串 A 复制到字符串 B 中

            如果字符串 A 是一个 char 数组,而字符串 B 是 std::string,并且 strlen(A) >= X,那么你可以这样做:

            B.assign(A, A + X);
            

            将 std::string 传递给 C 库中的函数,该函数采用 char * 作为缓冲区的参数

            如果参数实际上是const char *,则可以使用c_str()。但如果它只是普通的char *,并且您使用的是符合 C++11 的编译器,那么您可以执行以下操作:

            c_function(&B[0]);
            

            但是,您需要确保字符串中有空间用于存储数据(就像您使用普通的 c 字符串一样),您可以通过调用 resize() 函数来做到这一点。如果函数将未指定数量的字符作为以 null 结尾的 c 字符串写入字符串,那么您可能希望在之后截断字符串,如下所示:

            B.resize(B.find('\0'));
            

            您可以在 C++11 编译器而不是 C++03 编译器中安全地执行此操作的原因是,在 C++03 中,标准不保证字符串是连续的,但在 C++11 中, 他们是。如果你想要 C++03 中的保证,那么你可以使用 std::vector&lt;char&gt; 来代替。

            【讨论】:

            • 关于将c_str() 的返回值传递给采用char* 的函数的建议...这是个坏主意。你不知道const char* 指向什么。我看不到任何地方都说它指向字符串使用的内部缓冲区,因此它甚至可能不起作用,并且 API 对您大喊不应该修改此内存。除非你知道函数不会修改指针指向的内容,否则不要这样做。
            • @EdS。 -- 还好我没这么说。
            猜你喜欢
            • 1970-01-01
            • 2021-12-10
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-09-24
            • 2011-09-17
            相关资源
            最近更新 更多