如何将std::string
转换为char*
或const char*
?
如果你只是想把一个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
会在超出范围时为你删除内存。
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
](http://en.cppreference.com/w/cpp/container/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()
鉴于说...
std::string x = "hello";
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...
所有上述指针将持有相同的值--缓冲区中第一个字符的地址。 即使是空字符串也有一个"缓冲区中的第一个字符",因为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并不*改变string
'的size()
;string
'允许包含任何数量的NUL--std::string
对它们没有特殊处理(在C++03中也一样)。
在C++03中,事情要复杂得多(关键的区别强调了)。
x.size()
字符可以安全读取,即x[0]
到x[x.size() - 1]
。&x[0]
。f(const char* p, size_t n) { if (n == 0) return; ...ever...}
你不能调用f(&x[0], x.size());
当x.empty()
时 - 只需使用f(x.data(), ...)
。const
的x
,产生一个非const
的char*
指针;你可以覆盖字符串内容const char*
到ASCIIZ(NUL结尾的)表示的值(即['h', 'e', 'l', 'l', 'o' , '0'])。x.data()
和&x[0]
产生。x.size()
+1的字符可以安全读取。string
成员函数来修改string
或保留更多的容量,任何事先由上述任何方法返回的指针值都会被无效。 你可以再次使用这些方法来获得另一个指针。 (规则与进入string'的迭代器相同)。 参见*如何在
x`离开范围或被进一步修改后获得一个有效的字符指针下面....。
那么,哪种方法好用呢?从C++11开始,使用.c_str()
来处理ASCIIZ数据,使用.data()
来处理"二进制"数据(下面进一步解释)。
在C++03中,使用.c_str()
,除非确定.data()
是足够的,并且喜欢.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(相反,你使用字符串来存储一个数据块(有时甚至不是真正的文本)),或者你将其传递给另一个函数,将其视为一个二进制数据块。 这对于确保其他程序员在修改代码时能继续正确处理数据来说,是一个至关重要的洞察力。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);
string'中生成
char'或`const char'的其他原因所以,上面你已经看到了如何获得一个(const
)char*
,以及如何制作一个独立于原始string
的文本副本,但你能用它做什么? 一个随机的零星例子...
string
'的文本,如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
)。string
变量离开范围后,调用者可能会取消引用该指针。std::string
实现(例如STLport和编译器本地),可能会将数据传递为ASCIIZ以避免冲突。对 "const char *"使用.c_str()
方法。
你可以使用&mystring[0]
来获得一个char *
指针,但有几个问题:你不一定会得到一个零结尾的字符串,而且你不能改变字符串的大小。你尤其要注意不要在字符串的末尾添加字符,否则你会得到一个缓冲区超限(并可能崩溃)。
在C++11之前,不能保证所有的字符都属于同一个连续的缓冲区,但实际上所有已知的std::string
的实现都是这样工作的;见[Does "&s[0]" point to contiguous characters in a std::string?](https://stackoverflow.com/questions/1986966/does-s0-point-to-contiguous-characters-in-a-stdstring)。
请注意,许多string
成员函数会重新分配内部缓冲区,并使你可能保存的任何指针无效。最好立即使用它们,然后丢弃。