如何将std :: string转换为const char *或char *?
如何将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()] = ' '; // don't forget the terminating 0
// don't forget to free the string after finished using it
delete[] writable;
编辑 :请注意,上述情况并非例外。 如果new
呼叫和delete
呼叫之间有任何内容抛出,则会泄漏内存,因为没有任何内容会自动为您调用delete
。 有两种直接的方法可以解决这个问题。
提高:: 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()] = ' '; // 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 ::矢量
这是标准方式(不需要任何外部库)。 你使用std::vector
,它为你完全管理内存。
std::string str;
std::vector<char> writable(str.begin(), str.end());
writable.push_back(' ');
// get the char* using &writable[0] or &*writable.begin()
鉴于说...
std::string x = "hello";
从字符串中获取`char *`或`const char *`
如何获得一个有效的字符指针,而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 that", 9)
将会有一个缓存"this that "
)。
鉴于以上任何一点:
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
允许包含任意数量的NULs - 它们没有被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(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*
返回给值(即['h','e','l','l','o',' 0'])的ASCIIZ(NUL-terminated)表示。 x.data()
和&x[0]
x.size()
+ 1个字符可以安全读取。 获取外部法律索引的后果
无论你如何获得一个指针,你都不能访问指针以外的内存,而不是上面描述中保证的字符。 尝试这样做的方式有未定义的行为,即使是读取也会出现应用程序崩溃和垃圾结果的真实机会,并且还会出现批量数据,堆栈损坏和/或写入安全漏洞。
这些指针何时失效?
如果调用一些string
修改该成员函数string
或储备进一步的能力,任何指针值通过任何上述方法都无效预先返回。 您可以再次使用这些方法来获取另一个指针。 (规则与迭代器到string
s相同)。
另请参见如何获取字符指针,即使在x
离开作用域后仍然有效,或者在下面进一步修改....
那么,哪个更好用?
从C ++ 11开始,对ASCIIZ数据使用.c_str()
,对“二进制”数据使用.data()
(下面进一步解释)。
在C ++ 03中,除非确定.data()
足够,否则使用.c_str()
,并且通过&x[0]
偏好.data()
,因为它对于空字符串是安全的。
...尝试了解程序足以在适当时使用data()
,否则您可能会犯其他错误...
由.c_str()
保证的ASCII NUL' 0'字符被许多函数用作表示相关和安全访问数据结束的.c_str()
值。 这适用于像fstream::fstream(const char* filename, ...)
这样的仅用于C ++的函数fstream::fstream(const char* filename, ...)
以及用strchr()
和printf()
等C函数共享。
鉴于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 cd" -> 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 ->Hel )
char y[N + 1];
strncpy(y, x.c_str(), N); // copy at most N, zero-padding if shorter
y[N] = ' '; // 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和编译器本地)编译/链接的共享对象的某些项目可能会将数据作为ASCIIZ传递以避免冲突 对const char *
使用.c_str()
方法。
您可以使用&mystring[0]
来获取char *
指针,但有几个问题需要注意:您不一定会得到零终止的字符串,并且您将无法更改字符串的大小。 你特别要小心,不要在字符串末尾添加字符,否则你会得到一个缓冲区溢出(并可能崩溃)。
在C ++ 11之前,并不能保证所有的字符都是同一个连续缓冲区的一部分,但实际上所有已知的std::string
实现都是这样工作的; 请参阅“&s [0]”是否指向std :: string中的连续字符?
请注意,许多string
成员函数将重新分配内部缓冲区并使您可能已保存的任何指针无效。 最好立即使用它们,然后丢弃。