c++ - char转string - string char




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

C ++ 17

C ++ 17 (即将发布的标准)改变了模板basic_string的概要,添加了一个非const的data()重载data()

charT* data() noexcept;

返回:一个指针p,使得[+,size()]中每个i的p + i ==&运算符。

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开始,标准说:

  1. basic_string对象中的类char对象应连续存储。 也就是说,对于任何basic_string对象,标识&*(s.begin() + n) == &*s.begin() + n应该适用于&*(s.begin() + n) == &*s.begin() + n的所有值,使得0 <= n < s.size()
  1. const_reference operator[](size_type pos) const;
    reference operator[](size_type pos);

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

  1. const charT* c_str() const noexcept;
    const charT* data() const noexcept;

    返回:对于[0,size()]每个i ,指针p使得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 p
  delete[] p;
}
catch (...)
{
  if (p) { delete[] p; }
  throw;
}

  • 最大“控制”

精读

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

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


只要看到这个:

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

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


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

您可以使用&mystring[0]来获取char *指针,但有几个问题需要注意:您不一定会得到零终止的字符串,并且您将无法更改字符串的大小。 你特别要小心,不要在字符串末尾添加字符,否则你会得到一个缓冲区溢出(并可能崩溃)。

在C ++ 11之前,并不能保证所有的字符都是同一个连续缓冲区的一部分,但实际上所有已知的std::string实现都是这样工作的; 请参阅“&s [0]”是否指向std :: string中的连续字符?

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


尝试这个

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

鉴于说...

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

仅用于来自&x[0]的非常量指针:

p_x0_rw[n] = c;  // valid for n <= x.size() - 1
                 // i.e. don't overwrite the implementation maintained NUL

在字符串的其他地方写一个NUL 不会改变stringsize() ; 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]
      • 对于空字符串,你保证有一些非NULL指针,可以安全地添加0(hurray!),但不应该取消引用该指针。
  • &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()但是:
      • 对于非常量x这会产生一个非const char*指针; 你可以覆盖字符串内容
  • x.c_str()

    • const char*返回给值(​​即['h','e','l','l','o','\ 0'])的ASCIIZ(NUL-terminated)表示。
    • 尽管很少有实现选择这样做,但C ++ 03标准的措辞允许字符串实现自由地创建一个独立的NUL终止缓冲区 ,从可能不受NUL终止的缓冲区“暴露” x.data()&x[0]
    • x.size() + 1个字符可以安全读取。
    • 即使对于空字符串也是安全的(['\ 0'])。

获取外部法律索引的后果

无论你如何获得一个指针,你都不能访问指针以外的内存,而不是上面描述中保证的字符。 尝试这样做的方式有未定义的行为 ,即使是读取也会出现应用程序崩溃和垃圾结果的真实机会,并且还会出现批量数据,堆栈损坏和/或写入安全漏洞。

这些指针何时失效?

如果您调用一些修改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(而是使用字符串存储数据块(有时甚至不是真正的文本)),重新传递给另一个将其视为“二进制”数据块的函数。 这可以成为确保其他程序员的代码更改继续正确处理数据的关键洞察。
  • 仅限C ++ 03:您的string实现需要做一些额外的内存分配和/或数据复制,以便准备NUL终止缓冲区的可能性很小

作为一个进一步的提示,如果一个函数的参数需要( constchar*但并不坚持获得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*

所以,上面你已经看到了如何获得( constchar* ,以及如何使文本的副本独立于原始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传递以避免冲突

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




const