如果你只想将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 ,它可以为您完全管理内存。
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"; 如何在x保持在范围内并且不进一步修改时获得有效的字符指针
C ++ 11简化了事情; 以下所有内容都允许访问相同的内部字符串缓冲区:
const char* p_c_str = x.c_str();
const char* p_data = x.data();
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从指针&x[0]
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.data()
const char*返回到字符串的内部缓冲区,标准不要求用 NUL 结束 (即可能是['h', 'e', 'l', 'l', 'o']然后是未初始化的或垃圾值,意外访问具有未定义的行为 )。 x.size()字符可以安全读取,即x[0]到x[x.size() - 1] &x[0]
f(const char* p, size_t n) { if (n == 0) return; ...whatever... }你不能调用f(&x[0], x.size());当x.empty() - 只需使用f(x.data(), ...) 。 x.data()但是: const x这会产生一个非const char*指针; 你可以覆盖字符串内容 x.c_str()
const char*返回到值的 ASCIIZ(NUL 终止)表示(即 ['h','e','l','l','o','\ 0'])。 x.data()和&x[0] x.size() + 1 个字符可以安全阅读。 无论哪种方式获得指针,您都不能从指针进一步访问内存,而不是上面描述中保证的字符。尝试这样做具有未定义的行为 ,即使对于读取,也存在非常真实的应用程序崩溃和垃圾结果的可能性,以及批量数据,堆栈损坏和 / 或写入的安全漏洞。
如果调用某个string成员函数来修改string或保留更多容量,则任何上述方法预先返回的任何指针值都将失效 。您可以再次使用这些方法来获取另一个指针。 (规则与string s 中的迭代器相同)。
另请参见如何在x离开作用域或在下面进一步修改后使字符指针有效 ....
从 C ++ 11 开始,对于 ASCIIZ 数据使用.c_str() ,对于 “二进制” 数据使用.data() (在下面进一步说明)。
在 C ++ 03 中,使用.c_str()除非确定.data()是足够的,并且更喜欢.data() over &x[0]因为它对空字符串是安全的....
... 尝试理解程序足以在适当的时候使用data() ,否则你可能会犯其他错误......
由.c_str()保证的 ASCII NUL'\ 0' 字符被许多函数用作表示相关和安全访问数据结束的.c_str()值。这适用于 C ++ - 只有函数,比如说fstream::fstream(const char* filename, ...)和共享 C 函数,比如strchr()和printf() 。
鉴于 C ++ 03 的.c_str()对返回缓冲区的保证是.data()的超集,你可以随时安全地使用.c_str() ,但人们有时不这样做,因为:
.data()与其他程序员进行通信,读取数据不是 ASCIIZ 的源代码(相反,你使用字符串存储数据块(有时甚至不是真正的文本)),或者你 '将其传递给另一个将其视为 “二进制” 数据块的函数。这可以是确保其他程序员的代码更改继续正确处理数据的重要见解。 string实现可能需要进行一些额外的内存分配和 / 或数据复制才能准备 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);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 ) const char*或char* (可能是出于历史原因 - 客户端使用现有的 API - 或者对于 C 兼容性,您不想返回std::string ,但是想要复制string的数据在某个地方为来电者) string变量离开作用域后返回可能被调用者解除引用的指针std::string实现编译 / 链接的一些具有共享对象的项目(例如 STLport 和 native-native)可以将数据作为 ASCIIZ 传递以避免冲突使用.c_str()方法来表示const char * 。
您可以使用&mystring[0]来获取char *指针,但是有一些问题:您不一定会得到一个零终止字符串,并且您将无法更改字符串的大小。您尤其要注意不要在字符串末尾添加字符,否则会出现缓冲区溢出(以及可能的崩溃)。
在 C ++ 11 之前,无法保证所有字符都是同一个连续缓冲区的一部分,但实际上所有已知的std::string实现都是这样的。看“&s [0]” 是否指向 std :: string 中的连续字符? 。
请注意,许多string成员函数将重新分配内部缓冲区并使您可能已保存的任何指针无效。最好立即使用它们然后丢弃。