如何将 std::string 转换为 const char\* 或 char\*

新手上路,请多包涵

如何将 std::string 转换为 char*const char*

原文由 user37875 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.7k
2 个回答

如果您只想将 std::string 传递给需要 const char* 的函数,您可以使用

std::string str;
const char * c = str.c_str();

如果你想得到一个可写的副本,比如 char * ,你可以这样做:

 std::string str;
char * writable = new char[str.size() + 1];
std::copy(str.begin(), str.end(), writable);
writable[str.size()] = '\0'; // don't forget the terminating 0

// don't forget to free the string after finished using it
delete[] writable;

编辑:请注意,上述内容不是异常安全的。如果在 new 调用和 delete --- 调用之间发生任何问题,您将泄漏内存,因为不会自动为您调用 delete 。有两种直接的方法可以解决这个问题。

boost::scoped_array

boost::scoped_array 将在超出范围时为您删除内存:

 std::string str;
boost::scoped_array<char> writable(new char[str.size() + 1]);
std::copy(str.begin(), str.end(), writable.get());
writable[str.size()] = '\0'; // don't forget the terminating 0

// get the char* using writable.get()

// memory is automatically freed if the smart pointer goes
// out of scope

标准::向量

这是标准方式(不需要任何外部库)。您使用 std::vector ,它完全为您管理内存。

 std::string str;
std::vector<char> writable(str.begin(), str.end());
writable.push_back('\0');

// get the char* using &writable[0] or &*writable.begin()

原文由 Johannes Schaub - litb 发布,翻译遵循 CC BY-SA 3.0 许可协议

这在将 --- 的底层 char* 缓冲区传递给期望并写入 std::string char* 缓冲区的 C 调用时特别有用。这样您就可以两全其美!:C++ 的精妙之 std::string 以及它直接与您从 C++ 调用的 C 库一起使用的可用性。

如何使用 现代 C++ std::string 作为 C 风格读/写 char* 或只读空终止 const char*

如何将 std::string 转换为 char*const char*

尽管这是一个非常古老且备受推崇的问题,但我将要介绍的信息还没有很好地涵盖,如果完全涵盖的话,所以这是一个必要的补充, 特别 是关于需要预先分配的部分如果您想将其用作可写缓冲区,则使用 .resize() 方法的底层 C 字符串。

以下所有用法都需要 C++11 或更高版本,但 char* data() 调用除外,它需要 C++17 或更高版本。

要运行和测试下面的所有示例代码等,请查看并运行我的 eRCaGuy_hello_world 存储库中的 string__use_std_string_as_a_c_str_buffer.cpp 文件。

1.使用 std::string 作为读/写 char*

要使用 C++ std::string 作为 C 风格 可写 char* 缓冲区,您必须首先使用 –2f295850ae78bafb57992f4b5c1102 预先分配字符串的内部缓冲区以更改其 .size() .resize() 。请注意,使用 .reserve() 仅增加 .capacity() 是不够的! std::string::operator[] 的 cppreference.com 社区 wiki 页面 正确指出:

如果 pos > size() ,则行为未定义。

resize() 方法改变了大小, 而不是 reserve() 方法,它只改变了 capacity()

前任:

 #include <cstring>  // `strcpy()`
#include <iostream>
#include <string>

constexpr size_t BUFFER_SIZE = 100;

std::string str;
str.resize(BUFFER_SIZE);  // pre-allocate the underlying buffer
// check the size
std::cout << "str.size() = " << str.size() << "\n";

对于下面的所有示例,假设您有这些 C 字符串:

 constexpr char cstr1[] = "abcde ";
constexpr char cstr2[] = "fghijk";

一旦您使用 resize() 预先分配了足够大的底层缓冲区,您就可以通过至少 3 种方式以 char* 的形式访问底层缓冲区:

  1. 技术 1 [使用 C++11 的最佳选择]:数组索引使用 operator[] 获得一个字符,然后使用 & 获得它的地址。 前任:
    char* c_str;
   c_str = &str[0];
   c_str = &str[5];
   // etc.

   // Write these 2 C-strings into a `std::string`'s underlying buffer
   strcpy(&str[0], cstr1);
   strcpy(&str[sizeof(cstr1) - 1], cstr2); // `- 1` to overwrite the first
                                           // null terminator

   // print the string
   std::cout << str << "\n"; // output: `abcde fghijk`

如果你有一个指向 std::string 的指针怎么办?如果您有一个指向 std::string 的 ptr,则必须首先使用 *pstr 取消引用它,然后才能使用 &(*pstr)[0] operator[] 作为数组对其进行索引 --- ,所以上面的语法变得有点尴尬。这是一个完整的例子:

    std::string str2;
   std::string* pstr = &str2;
   pstr->resize(BUFFER_SIZE);
   c_str = &(*pstr)[0]; // <=== dereference the ptr 1st before indexing into it
   // Or, to make the order of precedence
   // (https://en.cppreference.com/w/cpp/language/operator_precedence) really
   // obvious, you can optionally add extra parenthesis like this:
   c_str = &((*pstr)[0]);

  1. 技术 2 [使用 C++17 的最佳选择]:使用 .data() 方法直接获得 char* 前任:
    char* c_str;
   c_str = str.data();
   c_str = str.data() + 5;
   // etc.

   // Write these 2 C-strings into the `std::string`'s underlying buffer
   strcpy(str.data(), cstr1);
   strcpy(str.data() + (sizeof(cstr1) - 1), cstr2); // `- 1` to overwrite the
                                                    // first null terminator

   // print the string
   std::cout << str << "\n"; // output: `abcde fghijk`

  1. 技巧3【在C++11中很好,但是很尴尬】:使用 .begin() 方法获取到第一个char的迭代器,然后使用迭代器的 operator*() 解引用方法得到迭代器的 char value_type ,然后取其地址得到一个 char* 前任:
    char* c_str;
   c_str = &(*str.begin());
   c_str = &(*str.begin()) + 5;
   // etc.

   // Write these 2 C-strings into the `std::string`'s underlying buffer
   strcpy(&(*str.begin()), cstr1);
   strcpy(&(*str.begin()) + (sizeof(cstr1) - 1), cstr2); // `- 1` to overwrite
                                                         // the first null
                                                         // terminator

   // print the string
   std::cout << str << "\n"; // output: `abcde fghijk`

需要注意的重要一点是,当您调用 str.resize(100) 时,它会为基础字符串保留至少 100 个字节,将字符串的 size() 设置为 100 ,并将这些字符中的所有 100 初始化为 char() –AKA: 的默认 值初始化char见我的问题)零零终止符, '\0' 。因此,每当您调用 str.size() 时,它都会返回 100 即使字符串中只有 "hello" 后跟 95 个空终止符或零。要获取字符串中的 长度 或非空终止符 的数量,您必须使用 C 函数 strlen() ,如下所示:

 std::cout << strlen(str.c_str()) << "\n"; // prints `12` in the examples above

// instead of:
std::cout << str.size() << "\n"; // prints `100` in the examples above

2. 访问一个 std::string 作为只读,以空结尾的 const char*

要从 --- 获取 可读 的空终止 const char* std::string ,请使用 .c_str() 方法。它返回一个 保证为空终止 的 C 风格字符串。请注意, .data() 方法不是一回事,因为它不能保证为空终止!

例子:

 std::string str = "hello world";
printf("%s\n", str.c_str());

参考

  1. (关于堆栈溢出的问题)

    1. 如何将 std::string 转换为 const char* 或 char*: 如何将 std::string 转换为 const char* 或 char*
    2. 直接写入 std::string 的 char* 缓冲区: 直接写入 std::string 的 char* 缓冲区
    3. Is there a way to get std:string’s buffer: Is there a way to get std:string’s buffer
  2. (我的内容)

    1. [我的测试代码] string__use_std_string_as_a_c_str_buffer.cpp
    2. [我的 Q] 请参阅此处我的问题底部的“相邻相关”部分: 什么是对 `char()`、`uint8_t()`、`int64_t()`、整数`T()` 等的调用, 作为 C++ 中的函数?
    3. \\*\*\*\*+ [我对在 std::string 中预分配缓冲区的评论]: [直接写入 std::string 的 char 缓冲区](https://stackoverflow.com/questions/39200665/directly-write-into-char-buffer-of-stdstring#comment127844941_39200666)
    4. \*\*\*\*\*+ [我对如何在 std::string 中预分配存储,用作 char* 缓冲区的评论] 有没有办法获得 std:string 的缓冲区
  3. (来自 cppreference.com 社区 wiki)

    1. https://en.cppreference.com/w/cpp/string/basic_string

    basic_string 的元素是连续存储的,即对于 basic_string s,&*(s.begin () + n) == &*s.begin() + n 对于 [0, s.size( )),或者等价地,可以将指向 s[0] 的指针传递给函数,这些函数期望指向以 null 结尾的 (C++11 起)CharT[] 数组的第一个元素的指针。

    1. https://en.cppreference.com/w/cpp/string/basic_string/operator_at

    返回对指定位置 pos 的字符的引用。不执行边界检查。如果 pos > size(),则行为未定义。

    1. https://en.cppreference.com/w/cpp/string/basic_string/resize

    2. https://en.cppreference.com/w/cpp/string/basic_string/reserve

    3. https://en.cppreference.com/w/cpp/string/basic_string/data

    4. https://en.cppreference.com/w/cpp/string/basic_string/c_str

    5. https://en.cppreference.com/w/cpp/string/basic_string/clear

原文由 Gabriel Staples 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏