600字范文,内容丰富有趣,生活中的好帮手!
600字范文 > 如何将std :: string转换为const char *或char *?

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

时间:2021-11-20 00:45:34

相关推荐

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

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

#1楼

看看这个:

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

但是请注意,这将返回const char *。对于char *,请使用strcpy将其复制到另一个char数组中。

#2楼

char* result = strcpy((char*)malloc(str.length()+1), str.c_str());

#3楼

C ++ 17

C ++ 17(即将发布的标准)更改了模板basic_string的提要,增加了data()的非const重载:

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()

CharT *来自std::basic_string<CharT>

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

C ++ 11

CharT const *来自std::basic_string<CharT>

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

CharT *来自std::basic_string<CharT>

从C ++ 11开始,该标准规定:

basic_string对象中的类似于char的对象应连续存储。 也就是说,对于任何basic_string对象s,对于所有n值,标识&*(s.begin() + n) == &*s.begin() + n都应成立,以使0 <= n < s.size()

const_reference operator[](size_type pos) const;

reference operator[](size_type pos);

返回:*(begin() + pos)如果pos < size(),否则以值CharT()引用CharT的对象; 参考值不得修改。

const charT* c_str() const noexcept;

const charT* data() const noexcept;

返回:指针p,使得[0,size()]每个i具有p + i == &operator[](i)

有几种可能的方法来获取非const字符指针。

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

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

专业版

简单而简短 快速(仅包含副本的方法)

缺点

最终的'\\0'不会被更改,也不一定是非常量存储器的一部分。

2.使用std::vector<CharT>

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

专业版

简单 自动内存处理 动态

缺点

需要字符串复制

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

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 pdelete[] p;}catch (...){if (p) { delete[] p; }throw;}

专业版

最大的“控制”

骗局

需要字符串复制 对错误的最大责任/敏感性 复杂

#4楼

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

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

在C ++ 11之前,无法保证所有字符都将是同一连续缓冲区的一部分,但实际上,所有已知的std::string实现都以这种方式工作; 请参见“&s [0]”是否指向std :: string中的连续字符? 。

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

#5楼

如果只想将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 itdelete[] 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::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()

#6楼

给出说...

std::string x = "hello";

从“字符串”中获取“ 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...

以上所有指针将具有相同的值-缓冲区中第一个字符的地址。 即使是空字符串也具有“缓冲区中的第一个字符”,因为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]对于空字符串,可以确保可以安全地向其添加0的一些非NULL指针(欢呼!),但是您不应该取消引用该指针。

&x[0]

对于空字符串,它具有未定义的行为(21.3.4) 例如,给定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()但: 对于非constx这将产生一个非constchar*指针; 您可以覆盖字符串内容

x.c_str()

const char*返回到值的ASCIIZ(NUL终止)表示形式(即['h','e','l','l','o','\\ 0'])。 尽管很少有实现选择这样做,但是C ++ 03 Standard的措辞是允许字符串实现自由地从x.data()公开的可能非NUL终止的缓冲区中动态创建独特的NUL终止的缓冲区x.data()&x[0]x.size()+ 1个字符可以安全阅读。 即使对于空字符串(['\\ 0'])也保证安全。

访问外部法律索引的后果

无论采用哪种方式获取指针,都不能比上述说明中保证的字符距离指针更远。 尝试执行此操作具有不确定的行为,即使是读取操作,也很有可能发生应用程序崩溃和垃圾结果,此外还可能批发数据,堆栈损坏和/或写入的安全漏洞。

这些指针什么时候失效?

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

另请参见即使在x离开范围或在下面进一步修改后,如何使字符指针仍然有效。

那么,哪个更好用?

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

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

...试图了解程序足以在适当的时候使用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(而是您使用字符串存储数据块(有时甚至不是真正的文本)),或者将其传递给另一个将其视为“二进制”数据块的函数。 这对于确保其他程序员的代码更改继续正确处理数据至关重要。 仅限于C ++ 03:您的string实现很有可能需要做一些额外的内存分配和/或数据复制,以准备NUL终止的缓冲区

进一步提示,如果函数的参数需要(constchar*但不坚持获取x.size(),则该函数可能需要ASCIIZ输入,因此.c_str()是一个不错的选择(函数需要知道文本在何处终止,因此,如果它不是一个单独的参数,则只能是一个约定,例如长度前缀或前哨或某个固定的预期长度。

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

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

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

// USING ANOTHER STRING - AUTO MEMORY MANAGEMENT, EXCEPTION SAFEstd::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* addressstd::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++03std::vector<char> old_x(x.data(), x.data() + x.size()); // without the NULstd::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 shortery[N] = '\0';// ensure NUL terminated// USING THE STACK TO HANDLE x OF UNKNOWN (BUT SANE) LENGTHchar* 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 SAFETYchar* 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 SAFETYchar* y = strdup(x.c_str());// use y...free(y);

想要从string生成char*const char*其他原因

因此,在上面,您已经了解了如何获取(constchar*以及如何独立于原始string来复制文本,但是您可以如何处理呢? 随机散落的例子...

授予“ C”代码访问C ++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编译器)可以将数据作为ASCIIZ传递以避免冲突

#7楼

尝试这个

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

#8楼

我正在使用具有许多功能的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 stuffaFunctionAPI("Foo"); //this call is not safe. if the function modified the //literal string the program will crashstd::string myFoo("Foo");aFunctionAPI(myFoo.c_str()); //this is not compilingaFunctionAPI(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是不可复制的)。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。