Joh*_*itb 1024
如果你只是想传递一个std::string需要const char*你可以使用的功能
std::string str;
const char * c = str.c_str();
Run Code Online (Sandbox Code Playgroud)
如果你想得到一个可写的副本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;
Run Code Online (Sandbox Code Playgroud)
编辑:请注意,上述内容不是安全例外.如果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
Run Code Online (Sandbox Code Playgroud)
这是标准方式(不需要任何外部库).您使用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()
Run Code Online (Sandbox Code Playgroud)
Ton*_*roy 188
鉴于......
std::string x = "hello";
Run Code Online (Sandbox Code Playgroud)
如何获取有效的字符指针,同时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...
Run Code Online (Sandbox Code Playgroud)
所有上述指针都将保持相同的值 - 缓冲区中第一个字符的地址.即使是空字符串也有"缓冲区中的第一个字符",因为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()]
Run Code Online (Sandbox Code Playgroud)
仅适用于非const指针p_writable_data:
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
Run Code Online (Sandbox Code Playgroud)
在字符串的其他地方写一个NUL 不会改变它&x[0]的string; size()允许包含任意数量的NUL - 它们没有给予特殊处理string(在C++ 03中也是如此).
在C++ 03中,事情要复杂得多(突出显示关键差异):
std::string
x.data()到字符串的内部缓冲区,标准不需要以NUL结束(即可能const char*后跟未初始化或垃圾值,其中意外访问具有未定义的行为).
['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()的ASCIIZ(NUL终止)表示(即['h','e','l','l','o','\ 0']).const char*和x.data()&x[0] + 1个字符可以安全阅读.无论哪种方式获得指针,您都不能从指针进一步访问内存,而不是上面描述中保证的字符.尝试这样做具有未定义的行为,即使对于读取,也存在非常真实的应用程序崩溃和垃圾结果的可能性,以及批量数据,堆栈损坏和/或写入的安全漏洞.
如果调用某个x.size()修改string或保留更多容量的成员函数,则任何上述方法预先返回的任何指针值都将失效.您可以再次使用这些方法来获取另一个指针.(规则与strings中的迭代器的规则相同).
另请参见如何使字符指针有效,即使在string叶子范围之后或在下面进一步修改 ....
从C++ 11开始,x用于ASCIIZ数据和.c_str()"二进制"数据(下面进一步说明).
在C++ 03,使用.data(),除非肯定.c_str()是足够的,而喜欢.data()过.data(),因为它是为空字符串安全....
...尝试&x[0]在适当的时候理解程序,或者你可能会犯其他错误......
保证的ASCII NUL'\ 0'字符data()被许多函数用作表示相关和安全访问数据结束的标记值.这适用于C++ -只有类似功能的说.c_str()和类似共享与-C的功能fstream::fstream(const char* filename, ...),和strchr().
鉴于C++ 03 printf()对返回缓冲区的保证是超集.c_str()的,你可以随时安全地使用.data(),但人们有时不这样做,因为:
.c_str()与其他程序员沟通,阅读数据不是ASCIIZ的源代码(相反,你使用字符串来存储数据块(有时甚至不是真正的文本)),或者你将它传递给另一个将它视为"二进制"数据块的函数.这可以是确保其他程序员的代码更改继续正确处理数据的重要见解..data()实现可能需要进行一些额外的内存分配和/或数据复制才能准备NUL终止缓冲区作为进一步的提示,如果一个函数的参数需要(string)const但不坚持获取char*,该函数可能需要一个ASCIIZ输入,所以这x.size()是一个很好的选择(该函数需要知道文本以某种方式终止的位置,所以如果它不是一个单独的参数,它只能是一个约定,如长度前缀或标记或一些固定的预期长度).
.c_str()范围或进一步修改后使字符指针有效您需要将内容复制x string到外部的新内存区域x.这个外部缓冲区可能在很多地方,例如另一个x或字符数组变量,它可能会或可能没有不同的生命周期,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);
Run Code Online (Sandbox Code Playgroud)
std::string x或char*从a生成的其他原因const char*所以,上面你已经看过如何获得一个(string)const,以及如何制作一个独立于原文的文本副本char*,但是你能用它做什么呢?一个随机的例子......
string的文本,如stringprintf("x is '%s'", x.c_str());文本复制到函数调用者指定的缓冲区(例如x)或用于设备I/O的易失性存储器(例如strncpy(callers_buffer, callers_buffer_size, x.c_str()))for (const char* p = x.c_str(); *p; ++p) *p_device = *p;文本追加到已经包含一些ASCIIZ文本的字符数组(例如x) - 注意不要超出缓冲区(在很多情况下你可能需要使用strcat(other_buffer, x.c_str()))strncat或const char*一个函数(可能是出于历史原因 - 客户端使用您现有的API - 或者对于C兼容性,您不想返回一个char*,但确实想要将您std::string的数据复制到调用者的某个地方)
string变量已经离开范围之后可能被调用者解除引用string实现编译/链接的一些具有共享对象的项目(例如STLport和native-native)可以将数据作为ASCIIZ传递以避免冲突Mar*_*som 33
使用.c_str()方法const char *.
您可以使用&mystring[0]获取char *指针,但有几个问题:您不一定会得到一个零终止字符串,并且您将无法更改字符串的大小.您尤其要注意不要在字符串末尾添加字符,否则会出现缓冲区溢出(以及可能的崩溃).
在C++ 11之前,无法保证所有字符都是同一个连续缓冲区的一部分,但实际上所有已知的实现std::string方式都是这样的.看"&s [0]"是否指向std :: string中的连续字符?.
请注意,许多string成员函数将重新分配内部缓冲区并使您可能已保存的任何指针无效.最好立即使用它们然后丢弃.
Pix*_*ist 20
C++ 17(即将推出的标准)更改了模板的概要,basic_string添加了非常量的重载data():
charT* data() noexcept;返回:指针p,使得[0,size()]中的每个i的p + i ==&operator.
CharT const * 从 std::basic_string<CharT>std::string const cstr = { "..." };
char const * p = cstr.data(); // or .c_str()
Run Code Online (Sandbox Code Playgroud)
CharT * 从 std::basic_string<CharT>std::string str = { "..." };
char * p = str.data();
Run Code Online (Sandbox Code Playgroud)
CharT const * 从 std::basic_string<CharT>std::string str = { "..." };
str.c_str();
Run Code Online (Sandbox Code Playgroud)
CharT * 从 std::basic_string<CharT>从C++ 11开始,标准说:
- 对象中的char状
basic_string对象应连续存储.也就是说,任何basic_string对象s,身份&*(s.begin() + n) == &*s.begin() + n应持的所有值n这样0 <= n < s.size().
const_reference operator[](size_type pos) const;
reference operator[](size_type pos);返回:
*(begin() + pos)ifpos < size(),否则引用CharT具有值的类型的对象CharT(); 参考值不得修改.
const charT* c_str() const noexcept;const charT* data() const noexcept;返回:指针p,
p + i == &operator[](i)对于每个iin[0,size()].
有可分割的方法来获取非const字符指针.
std::string foo{"text"};
auto p = &*foo.begin();
Run Code Online (Sandbox Code Playgroud)
临
缺点
'\0'不得改变/不一定是非常规内存的一部分.std::vector<CharT>std::string foo{"text"};
std::vector<char> fcv(foo.data(), foo.data()+foo.size()+1u);
auto p = fcv.data();
Run Code Online (Sandbox Code Playgroud)
临
缺点
std::array<CharT, N>if N是编译时间常量(并且足够小)std::string foo{"text"};
std::array<char, 5u> fca;
std::copy(foo.data(), foo.data()+foo.size()+1u, fca.begin());
Run Code Online (Sandbox Code Playgroud)
临
缺点
std::string foo{ "text" };
auto p = std::make_unique<char[]>(foo.size()+1u);
std::copy(foo.data(), foo.data() + foo.size() + 1u, &p[0]);
Run Code Online (Sandbox Code Playgroud)
临
缺点
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;
}
Run Code Online (Sandbox Code Playgroud)
临
精读
我正在使用一个带有很多函数的API作为输入a 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_; }
};
Run Code Online (Sandbox Code Playgroud)
你可以用它作为:
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
Run Code Online (Sandbox Code Playgroud)
我已经调用了这个类,DeepString因为它正在创建DeepString一个现有字符串的深层唯一副本(不可复制).
看看这个:
string str1("stackoverflow");
const char * str2 = str1.c_str();
Run Code Online (Sandbox Code Playgroud)
但请注意,这将返回const char *.对于a char *,用于strcpy将其复制到另一个char数组中.
char* result = strcpy((char*)malloc(str.length()+1), str.c_str());
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
890894 次 |
| 最近记录: |