如何将 std::string
转换为 char*
或 const char*
?
原文由 user37875 发布,翻译遵循 CC BY-SA 4.0 许可协议
这在将 --- 的底层 char*
缓冲区传递给期望并写入 std::string
char*
缓冲区的 C 调用时特别有用。这样您就可以两全其美!:C++ 的精妙之 std::string
以及它直接与您从 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 文件。
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*
的形式访问底层缓冲区:
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]);
.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`
.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
std::string
作为只读,以空结尾的 const char*
要从 --- 获取 可读 的空终止 const char*
std::string
,请使用 .c_str()
方法。它返回一个 保证为空终止 的 C 风格字符串。请注意, .data()
方法不是一回事,因为它不能保证为空终止!
例子:
std::string str = "hello world";
printf("%s\n", str.c_str());
(关于堆栈溢出的问题)
(我的内容)
(来自 cppreference.com 社区 wiki)
basic_string 的元素是连续存储的,即对于 basic_string s,&*(s.begin () + n) == &*s.begin() + n 对于 [0, s.size( )),或者等价地,可以将指向 s[0] 的指针传递给函数,这些函数期望指向以 null 结尾的 (C++11 起)CharT[] 数组的第一个元素的指针。
返回对指定位置 pos 的字符的引用。不执行边界检查。如果 pos > size(),则行为未定义。
原文由 Gabriel Staples 发布,翻译遵循 CC BY-SA 4.0 许可协议
2 回答1.2k 阅读✓ 已解决
2 回答1.9k 阅读✓ 已解决
1 回答1.9k 阅读✓ 已解决
1 回答1.9k 阅读
1 回答1.1k 阅读
2 回答1.4k 阅读
2 回答2.2k 阅读
如果您只想将
std::string
传递给需要const char*
的函数,您可以使用如果你想得到一个可写的副本,比如
char *
,你可以这样做:编辑:请注意,上述内容不是异常安全的。如果在
new
调用和delete
--- 调用之间发生任何问题,您将泄漏内存,因为不会自动为您调用delete
。有两种直接的方法可以解决这个问题。boost::scoped_array
boost::scoped_array
将在超出范围时为您删除内存:标准::向量
这是标准方式(不需要任何外部库)。您使用
std::vector
,它完全为您管理内存。