ChatGPT解决这个技术问题 Extra ChatGPT

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

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

而不是: char * writable = new char[str.size() + 1];您可以使用 char writable[str.size() + 1];那么你就不用担心删除可写或异常处理了。
除非在编译时知道大小,否则不能使用 str.size() ,如果固定大小值很大,它也可能会溢出堆栈。
char* 结果 = strcpy((char*)malloc(str.length()+1), str.c_str());
@cegprakash strcpymalloc 并不是真正的 C++ 方式。
不,但 char* dest = new char[str.length() + 1]; std::copy(str.begin(), str.end(), dest) 会是更惯用的 C++。 strcpy()malloc() 没有错误或有问题,但在同一代码块中使用 C++ 字符串和 C 库工具与 C++ 等效项似乎不一致。

7
7 revs, 4 users 92%

如果您只想将 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()

只需使用 char *result = strdup(str.c_str());
你可以,但 strdup 不是 ac 或 c++ 标准函数,它来自 posix :)
我通常可能更喜欢的是 std::vector writable(str.begin(), str.end()); writable.push_back('\0');字符 * c = &writable[0];
std::copy 是执行此操作的 c++ 方式,无需获取字符串指针。我尽量避免使用 C 函数。
从 C++17 开始,std::string::data() 现在返回 CharT* 而不是 const CharT*。更新这个答案可能是个好主意:)
1
17 revs, 3 users 98%

鉴于说...

std::string x = "hello";

从 `string` 获取 `char *` 或 `const char*`

如何在 x 保持在范围内且未进一步修改时获得有效的字符指针

C++11 简化了事情;以下所有内容都可以访问相同的内部字符串缓冲区:

const char* p_c_str = x.c_str();
const char* p_data  = x.data();
char* p_writable_data = x.data(); // for non-const x from C++17 
const char* p_x0    = &x[0];

      char* p_x0_rw = &x[0];  // compiles iff x is not const...

所有上述指针都将保存 same value - 缓冲区中第一个字符的地址。即使是空字符串也有一个“缓冲区中的第一个字符”,因为 C++11 保证在显式分配的字符串内容之后始终保留一个额外的 NUL/0 终止符(例如 std::string("this\0that", 9) 将有一个缓冲区保存 "this\0that\0") .

鉴于上述任何指针:

char c = p[n];   // valid for n <= x.size()
                 // i.e. you can safely read the NUL at p[x.size()]

仅适用于非 const 指针 p_writable_data 和来自 &x[0]

p_writable_data[n] = c;
p_x0_rw[n] = c;  // valid for n <= x.size() - 1
                 // i.e. don't overwrite the implementation maintained NUL

在字符串的其他地方写入 NUL 不会更改 stringsize()string 可以包含任意数量的 NUL - std::string 没有对它们进行特殊处理(在 C++03 中相同)。

在 C++03 中,事情要复杂得多(突出显示关键差异):

x.data() 将 const char* 返回到字符串的内部缓冲区,标准不要求以 NUL 结尾(即可能是 ['h', 'e', 'l', 'l', 'o '] 后跟未初始化或垃圾值,意外访问具有未定义的行为)。 x.size() 字符是安全读取的,即 x[0] 到 x[x.size() - 1] 用于空字符串,你可以保证一些非 NULL 指针可以安全地添加 0 (欢呼! ),但您不应该取消引用该指针。

将 const char* 返回到标准不要求以 NUL 结尾的字符串的内部缓冲区(即可能是 ['h', 'e', 'l', 'l', 'o'] 后跟未初始化或垃圾值,意外访问具有未定义的行为)。 x.size() 字符是安全读取的,即 x[0] 到 x[x.size() - 1] 用于空字符串,你可以保证一些非 NULL 指针可以安全地添加 0 (欢呼! ),但您不应该取消引用该指针。

x.size() 字符可以安全读取,即 x[0] 到 x[x.size() - 1]

对于空字符串,您可以保证某些非 NULL 指针可以安全地添加到其中 0 (欢呼!),但您不应该取消引用该指针。

&x[0] 对于空字符串,这具有未定义的行为 (21.3.4) 例如给定 f(const char* p, size_t n) { if (n == 0) return; ...无论如何... } 你不能调用 f(&x[0], x.size());当 x.empty() - 只需使用 f(x.data(), ...)。否则,根据 x.data() 但是:对于非常量 x 这会产生非常量 char* 指针;你可以覆盖字符串内容

对于空字符串,这具有未定义的行为(21.3.4),例如给定 f(const char* p, size_t n) { if (n == 0) return; ...无论如何... } 你不能调用 f(&x[0], x.size());当 x.empty() - 只需使用 f(x.data(), ...)。

例如给定 f(const char* p, size_t n) { if (n == 0) return; ...无论如何... } 你不能调用 f(&x[0], x.size());当 x.empty() - 只需使用 f(x.data(), ...)。

否则,根据 x.data() 但是:对于非常量 x 这会产生非常量 char* 指针;你可以覆盖字符串内容

对于非常量 x 这将产生一个非常量 char* 指针;你可以覆盖字符串内容

x.c_str() 将 const char* 返回为值的 ASCIIZ(NUL 终止)表示(即 ['h', 'e', 'l', 'l', 'o', '\0']) .尽管很少有实现选择这样做,但 C++03 标准的措辞允许字符串实现自由地动态创建不同的 NUL 终止缓冲区,从潜在的非 NUL 终止缓冲区“暴露”x .data() 和 &x[0] x.size() + 1 个字符可以安全阅读。即使对于空字符串 (['\0']) 也能保证安全。

将 const char* 返回为值的 ASCIIZ(NUL 终止)表示(即 ['h', 'e', 'l', 'l', 'o', '\0'])。

尽管很少有实现选择这样做,但 C++03 标准的措辞允许字符串实现自由地动态创建不同的 NUL 终止缓冲区,从潜在的非 NUL 终止缓冲区“暴露”x .data() 和 &x[0]

x.size() + 1 个字符可以安全阅读。

即使对于空字符串 (['\0']) 也能保证安全。

访问外部法律索引的后果

无论您以何种方式获得指针,您都不能从指针访问超出上述描述中保证的字符的内存。这样做的尝试具有未定义的行为,即使对于读取,应用程序崩溃和垃圾结果的可能性也非常大,另外还有大量数据、堆栈损坏和/或写入的安全漏洞。

这些指针什么时候失效?

如果您调用某个修改 string 或保留更多容量的 string 成员函数,则上述任何方法预先返回的任何指针值都会无效。您可以再次使用这些方法来获取另一个指针。 (规则与进入 string 的迭代器相同)。

另请参阅 即使在 x 离开范围或被进一步修改后,如何使字符指针有效 ....

那么,哪个更好用呢?

从 C++11 开始,将 .c_str() 用于 ASCIIZ 数据,将 .data() 用于“二进制”数据(下文将进一步解释)。

在 C++03 中,除非确定 .data() 足够,否则使用 .c_str(),并且更喜欢 .data() 而不是 &x[0],因为它对于空字符串是安全的......

...尝试充分理解程序以在适当的时候使用 data(),否则您可能会犯其他错误...

.c_str() 保证的 ASCII NUL '\0' 字符被许多函数用作标记值,表示相关和安全访问数据的结束。这适用于仅 C++ 的函数(例如 fstream::fstream(const char* filename, ...))和与 C 共享的函数(例如 strchr()printf())。

鉴于 C++03 的 .c_str() 对返回缓冲区的保证是 .data() 的超集,您始终可以安全地使用 .c_str(),但人们有时不这样做,因为:

使用 .data() 与其他阅读源代码的程序员沟通数据不是 ASCIIZ(相反,您使用字符串来存储数据块(有时甚至不是真正的文本)),或者您将其重新传递给另一个将其视为“二进制”数据块的函数。这可能是确保其他程序员的代码更改继续正确处理数据的关键洞察力。

仅限 C++03:您的字符串实现可能需要进行一些额外的内存分配和/或数据复制以准备 NUL 终止的缓冲区

作为进一步的提示,如果函数的参数需要 (const) char* 但不坚持获取 x.size(),则函数可能需要 ASCIIZ 输入,因此 .c_str() 是一个不错的选择(该函数需要知道文本以某种方式终止的位置,因此如果它不是一个单独的参数,它只能是一个约定,如长度前缀或哨兵或一些固定的预期长度)。

即使在 x 离开范围或进一步修改后如何使字符指针有效

您需要将 string x 的内容复制x 之外的新内存区域。此外部缓冲区可能位于许多地方,例如另一个 string 或字符数组变量,由于处于不同的范围(例如命名空间、全局、静态、堆、共享),它的生命周期可能与 x 不同,也可能不同内存,内存映射文件)。

要将 std::string x 中的文本复制到一个独立的字符数组中:

// USING ANOTHER STRING - AUTO MEMORY MANAGEMENT, EXCEPTION SAFE
std::string old_x = x;
// - old_x will not be affected by subsequent modifications to x...
// - you can use `&old_x[0]` to get a writable char* to old_x's textual content
// - you can use resize() to reduce/expand the string
//   - resizing isn't possible from within a function passed only the char* address

std::string old_x = x.c_str(); // old_x will terminate early if x embeds NUL
// Copies ASCIIZ data but could be less efficient as it needs to scan memory to
// find the NUL terminator indicating string length before allocating that amount
// of memory to copy into, or more efficient if it ends up allocating/copying a
// lot less content.
// Example, x == "ab\0cd" -> old_x == "ab".

// USING A VECTOR OF CHAR - AUTO, EXCEPTION SAFE, HINTS AT BINARY CONTENT, GUARANTEED CONTIGUOUS EVEN IN C++03
std::vector<char> old_x(x.data(), x.data() + x.size());       // without the NUL
std::vector<char> old_x(x.c_str(), x.c_str() + x.size() + 1);  // with the NUL

// USING STACK WHERE MAXIMUM SIZE OF x IS KNOWN TO BE COMPILE-TIME CONSTANT "N"
// (a bit dangerous, as "known" things are sometimes wrong and often become wrong)
char y[N + 1];
strcpy(y, x.c_str());

// USING STACK WHERE UNEXPECTEDLY LONG x IS TRUNCATED (e.g. Hello\0->Hel\0)
char y[N + 1];
strncpy(y, x.c_str(), N);  // copy at most N, zero-padding if shorter
y[N] = '\0';               // ensure NUL terminated

// USING THE STACK TO HANDLE x OF UNKNOWN (BUT SANE) LENGTH
char* y = alloca(x.size() + 1);
strcpy(y, x.c_str());

// USING THE STACK TO HANDLE x OF UNKNOWN LENGTH (NON-STANDARD GCC EXTENSION)
char y[x.size() + 1];
strcpy(y, x.c_str());

// USING new/delete HEAP MEMORY, MANUAL DEALLOC, NO INHERENT EXCEPTION SAFETY
char* y = new char[x.size() + 1];
strcpy(y, x.c_str());
//     or as a one-liner: char* y = strcpy(new char[x.size() + 1], x.c_str());
// use y...
delete[] y; // make sure no break, return, throw or branching bypasses this

// USING new/delete HEAP MEMORY, SMART POINTER DEALLOCATION, EXCEPTION SAFE
// see boost shared_array usage in Johannes Schaub's answer

// USING malloc/free HEAP MEMORY, MANUAL DEALLOC, NO INHERENT EXCEPTION SAFETY
char* y = strdup(x.c_str());
// use y...
free(y);

希望从字符串生成 char* 或 const char* 的其他原因

因此,在上面您已经了解了如何获取 (const) char*,以及如何制作独立于原始 string 的文本副本,但是您可以做什么它?一些随机的例子......

让“C”代码访问 C++ 字符串的文本,如 printf("x is '%s'", x.c_str());

将 x 的文本复制到函数调用者指定的缓冲区(例如 strncpy(callers_buffer, callers_buffer_size, x.c_str()))或用于设备 I/O 的易失性内存(例如 for (const char* p = x.c_str() ; *p; ++p) *p_device = *p;)

将 x 的文本附加到已经包含一些 ASCIIZ 文本的字符数组(例如 strcat(other_buffer, x.c_str())) - 注意不要超出缓冲区(在许多情况下,您可能需要使用 strncat)

从函数返回 const char* 或 char*(可能出于历史原因 - 客户端使用您现有的 API - 或者为了 C 兼容性,您不想返回 std::string,但确实想将字符串的数据复制到某处调用者)注意不要返回一个指针,在该指针指向的本地字符串变量离开范围后,调用者可能会取消引用该指针,该指针已离开范围,某些项目具有为不同的 std::string 实现(例如 STLport 和编译器)编译/链接的共享对象-native) 可以将数据作为 ASCIIZ 传递以避免冲突

注意不要在指针指向的本地字符串变量离开范围后返回可能被调用者取消引用的指针

一些为不同的 std::string 实现(例如 STLport 和编译器原生)编译/链接共享对象的项目可能会将数据作为 ASCIIZ 传递以避免冲突


好东西。需要 char*(非 const)的另一个原因是使用 MPI 广播进行操作。如果您不必来回复制,它看起来会更好。我会亲自为字符串提供一个 char* const getter。常量指针,但可编辑的字符串。尽管它可能与从 const char* 到字符串的隐式转换混淆了......
C
Community

const char * 使用 .c_str() 方法。

您可以使用 &mystring[0] 获取 char * 指针,但有几个问题:您不一定会得到一个以零结尾的字符串,并且您将无法更改字符串的大小。尤其要注意不要在字符串末尾添加字符,否则会导致缓冲区溢出(并可能崩溃)。

在 C++11 之前,不能保证所有字符都是同一个连续缓冲区的一部分,但实际上 std::string 的所有已知实现都以这种方式工作;见Does “&s[0]” point to contiguous characters in a std::string?

请注意,许多 string 成员函数将重新分配内部缓冲区并使您可能保存的任何指针无效。最好立即使用它们然后丢弃。


你应该注意 data() 返回 const char * :) 你的意思是 &str[0],它返回一个连续的,但不是必要的空终止字符串。
@litb,啊!这就是我试图快速回答的结果。我过去使用过您的解决方案,不知道为什么它不是首先想到的。我已经编辑了我的答案。
从技术上讲,std::string 存储仅在 C++0x 中是连续的。
@MSalters,谢谢-我不知道。不过,我很难找到一个不是这种情况的实现。
char* 结果 = strcpy(malloc(str.length()+1), str.c_str());
P
Pixelchemist

C++17

C++17(即将推出的标准)更改了模板 basic_string 的概要,添加了 data() 的非 const 重载:

charT* data() noexcept;返回: 一个指针 p,使得 p + i == &operator 对于 [0,size()] 中的每个 i。

CharT const * 来自 std::basic_string

std::string const cstr = { "..." };
char const * p = cstr.data(); // or .c_str()

CharT * 来自 std::basic_string

std::string str = { "..." };
char * p = str.data();

C++11

CharT const * 来自 std::basic_string

std::string str = { "..." };
str.c_str();

CharT * 来自 std::basic_string

从 C++11 开始,标准说:

basic_string 对象中的类字符对象应连续存储。也就是说,对于任何 basic_string 对象 s,标识 &*(s.begin() + n) == &*s.begin() + n 应适用于所有 n 值,使得 0 <= n < s.size ()。 const_reference operator[](size_type pos) const;参考运算符[](size_type pos);返回: *(begin() + pos) 如果 pos < size(),否则引用 CharT 类型的对象,其值为 CharT();不得修改参考值。 const charT* c_str() const noexcept; const charT* data() const noexcept;返回: 一个指针 p 使得 p + i == &operator[](i) 对于 [0,size()] 中的每个 i。

有多种可能的方法来获取非常量字符指针。

1.使用C++11的连续存储

std::string foo{"text"};
auto p = &*foo.begin();

简单而简短

快速(不涉及复制的唯一方法)

缺点

最终的 '\0' 不会被更改/不一定是非常量内存的一部分。

2. 使用 std::vector

std::string foo{"text"};
std::vector<char> fcv(foo.data(), foo.data()+foo.size()+1u);
auto p = fcv.data();

简单的

自动内存处理

动态的

缺点

需要字符串复制

3. 如果 N 是编译时间常数(并且足够小),则使用 std::array

std::string foo{"text"};
std::array<char, 5u> fca;
std::copy(foo.data(), foo.data()+foo.size()+1u, fca.begin());

简单的

堆栈内存处理

缺点

静止的

需要字符串复制

4. 带自动存储删除的原始内存分配

std::string foo{ "text" };
auto p = std::make_unique<char[]>(foo.size()+1u);
std::copy(foo.data(), foo.data() + foo.size() + 1u, &p[0]);

内存占用小

自动删除

简单的

缺点

需要字符串复制

静态(动态使用需要更多代码)

特征少于向量或数组

5. 手动处理的原始内存分配

std::string foo{ "text" };
char * p = nullptr;
try
{
  p = new char[foo.size() + 1u];
  std::copy(foo.data(), foo.data() + foo.size() + 1u, p);
  // handle stuff with p
  delete[] p;
}
catch (...)
{
  if (p) { delete[] p; }
  throw;
}

最大“控制”

骗局

需要字符串复制

最大责任/对错误的敏感性

复杂的


A
Arsen Khachaturyan

看看这个:

string str1("stackoverflow");
const char * str2 = str1.c_str();

但是请注意,这将返回一个 const char *

对于 char *,使用 strcpy 将其复制到另一个 char 数组中。


嗨,您发布的内容已经在 5 岁问题的其他答案中多次提及,并提供了更多详细信息。回答较早的问题很好,但前提是您添加了新信息。否则,这只是噪音。
就个人而言,我很欣赏这种简单性。
P
Peter Mortensen

我正在使用一个包含许多函数的 API,这些函数将 char* 作为输入。

我创建了一个小类来面对这种问题,并且我已经实现了 RAII 成语。

class DeepString
{
        DeepString(const DeepString& other);
        DeepString& operator=(const DeepString& other);
        char* internal_; 
    
    public:
        explicit DeepString( const string& toCopy): 
            internal_(new char[toCopy.size()+1]) 
        {
            strcpy(internal_,toCopy.c_str());
        }
        ~DeepString() { delete[] internal_; }
        char* str() const { return internal_; }
        const char* c_str()  const { return internal_; }
};

您可以将其用作:

void aFunctionAPI(char* input);

//  other stuff

aFunctionAPI("Foo"); //this call is not safe. if the function modified the 
                     //literal string the program will crash
std::string myFoo("Foo");
aFunctionAPI(myFoo.c_str()); //this is not compiling
aFunctionAPI(const_cast<char*>(myFoo.c_str())); //this is not safe std::string 
                                                //implement reference counting and 
                                                //it may change the value of other
                                                //strings as well.
DeepString myDeepFoo(myFoo);
aFunctionAPI(myFoo.str()); //this is fine

我之所以调用类 DeepString,是因为它正在创建现有字符串的深度且唯一的副本(DeepString 不可复制)。


我会避免这种命名约定。 std 使用的 c_str() 是“C-string”而不是“const string”的缩写,并且 str() 始终返回 std::basic_string,而不是 char*(例如 std::stringstream::str()
c
cegprakash
char* result = strcpy((char*)malloc(str.length()+1), str.c_str());

看起来很花哨但真的很难理解......简单是最好的IMO
strcpy()、malloc()、length() 和 c_str() 是基本函数,没有什么难的。只是分配内存和复制。
是的,这些功能是基本的,但你已经扭曲和弯曲它们看起来像一碗意大利面或一个班轮科学怪人的怪物:)
是的,这些功能是基本的,但是......你还记得你是什么时候开始接触编程语言的吗?还有一些需要解释的行,它确实会帮助新手了解例如为什么与 this answer 不同或更好:)
@cegprakash:只要有 malloc(),也必须有 free()。否则代码会泄漏内存,您的答案中的解决方案也是如此。分配内存而不至少暗示所需的释放对于此类问题是不好的做法。
S
SHAH MD IMRAN HOSSAIN

现在从 c++ std 字符串转换为 C 样式字符串真的很容易。

为此,我们有 string::copy 函数,可以轻松地将 std 字符串转换为 C 样式字符串。 reference

string::copy 函数参数串行

char 字符串指针 字符串大小,要复制多少个字符 b 位置,从哪里开始复制字符

还有一点很重要,

此函数不会在操作结束时附加空字符。所以,我们需要手动放置。

代码考试如下 -

// char string
char chText[20];

// c++ string
string text =  "I am a Programmer";

// conversion from c++ string to char string
// this function does not append a null character at the end of operation
text.copy(chText, text.size(), 0);

// we need to put it manually
chText[text.size()] = '\0';

// below statement prints "I am a Programmer"
cout << chText << endl;

反之亦然,从 C 样式字符串转换为 C++ 标准字符串要容易得多

我们可以通过三种方式将 C 样式字符串转换为 C++ 标准字符串

第一个是使用构造函数,

char chText[20] = "I am a Programmer";
// using constructor
string text(chText);

第二个是使用 string::assign 方法

// char string
char chText[20] = "I am a Programmer";

// c++ string
string text;

// convertion from char string to c++ string
// using assign function
text.assign(chText);

第三个是赋值运算符(=),其中字符串类使用运算符重载

// char string
char chText[20] = "I am a Programmer";

// c++ string
// convertion from char string to c++ string using assignment operator overloading
string text = chText;

第三个也可以像下面这样写 -

// char string
char chText[20] = "I am a Programmer";

// c++ string
string text;


// convertion from char string to c++ string
text = chText;

V
Vineeth Peddi

假设,字符串 str="stack";

1)将字符串转换为字符*

  char* s_rw=&str[0]; 

上面的char*(即s_rw)是可读可写的,指向需要转换成char*的字符串的基地址

2) 将字符串转换为 const char*

   const char* s_r=&str[0];

上面的const char*(即s_r)可读不可写,指向字符串的基地址。


G
Gabriel Staples

这在将 std::string 的底层 char* 缓冲区传递给期望并写入 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 作为读/写字符*

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

如果 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 [使用 C++11 的最佳选择]:使用 operator[] 进行数组索引以获取 char,然后使用 & 获取其地址。例如:char* c_str; c_str = &str[0]; c_str = &str[5]; // 等等 // 将这 2 个 C 字符串写入 `std::string` 的底层缓冲区 strcpy(&str[0], cstr1); strcpy(&str[sizeof(cstr1) - 1], cstr2); // `- 1` 覆盖第一个 // null 终止符 // 打印字符串 std::cout << str << "\n"; // 输出:`abcde fghijk` 如果你有一个指向 std::string 的指针怎么办?如果您有指向 std::string 的 ptr,则必须先用 *pstr 取消引用它,然后才能将其作为数组索引,其中 operator[] 为 &(*pstr)[0],因此上述语法变为有点尴尬。这是一个完整的例子:std::string str2; std::string* pstr = &str2; pstr->resize(BUFFER_SIZE); c_str = &(*pstr)[0]; // <=== 在索引到它之前取消引用第一个 ptr // 或者,使优先顺序 // (https://en.cppreference.com/w/cpp/language/operator_precedence) 真的 // 明显,您可以选择像这样添加额外的括号: c_str = &((*pstr)[0]);技术 2 [使用 C++17 的最佳选择]:使用 .data() 方法直接获取 char*。例如:char* c_str; c_str = str.data(); c_str = str.data() + 5; // 等等 // 将这 2 个 C 字符串写入 `std::string` 的底层缓冲区 strcpy(str.data(), cstr1); strcpy(str.data() + (sizeof(cstr1) - 1), cstr2); // `- 1` 覆盖 // 第一个空终止符 // 打印字符串 std::cout << str << "\n"; // 输出:`abcde fghijk` 技巧3 [在C++11中很好,但很尴尬]:使用 .begin() 方法获取第一个字符的迭代器,然后使用迭代器的 operator*() 解引用方法获取迭代器的char value_type,然后取其地址获取char*。例如:char* c_str; c_str = &(*str.begin()); c_str = &(*str.begin()) + 5; // 等等 // 将这 2 个 C 字符串写入 `std::string` 的底层缓冲区 strcpy(&(*str.begin()), cstr1); strcpy(&(*str.begin()) + (sizeof(cstr1) - 1), cstr2); // `- 1` 覆盖 // 第一个 null // 终止符 // 打印字符串 std::cout << str << "\n"; // 输出:`abcde fghijk`

需要注意的重要一点是,当您调用 str.resize(100) 时,它会为基础字符串保留至少 100 个字节,将字符串的 size() 设置为 100,并将所有这些字符的 100 初始化为 { 6}--AKA:char (see my question here) 的默认 值初始化 值,即二进制零空终止符 '\0'。因此,无论何时调用 str.size(),它都会返回 100,即使字符串中仅包含 "hello" 后跟 95 个空终止符或零。要获得 length 或字符串中 non-null-terminators 的数量,您必须使用 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* 访问

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

例子:

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

参考

(关于堆栈溢出的问题)如何将 std::string 转换为 const char* 或 char*:如何将 std::string 转换为 const char* 或 char* 直接写入 std::string 的 char* 缓冲区:直接写入 std::string 的 char* 缓冲区有没有办法获取 std:string 的缓冲区:有没有办法获取 std:string 的缓冲区(我的内容)[我的测试代码] string__use_std_string_as_a_c_str_buffer.cpp [我的 Q] 见“此处我的问题底部的“相邻相关”部分:什么是调用 `char()` 作为 C++ 中的函数? *****+ [我对在 std::string 中预分配缓冲区的评论]:直接写入 std::string 的 char* 缓冲区 *****+ [我对如何预分配存储的评论在 std::string 中,用作 char* 缓冲区] 有没有办法获取 std:string 的缓冲区(来自 cppreference.com 社区 wiki)https://en.cppreference.com/w/cpp/string /basic_string:一个basic_string的元素是连续存储的,即对于一个basic_string s,&*(s.begin()+n)==&*s.begin()+n对于[0,s中的任意n .size()),或者等效地,指向 s[0] 的指针可以传递给函数,这些函数需要指向以空字符结尾的 (C++11 起)CharT[] 数组的第一个元素的指针。 https://en.cppreference.com/w/cpp/string/basic_string/operator_at 返回对指定位置 pos 的字符的引用。不执行边界检查。如果 pos > size(),则行为未定义。 https://en.cppreference.com/w/cpp/string/basic_string/resize https://en.cppreference.com/w/cpp/string/basic_string/reserve https://en.cppreference.com/w/ cpp/string/basic_string/data https://en.cppreference.com/w/cpp/string/basic_string/c_str https://en.cppreference.com/w/cpp/string/basic_string/clear


a
anish

尝试这个

std::string s(reinterpret_cast<const char *>(Data), Size);