关于C++:如何将STD::string转换为 const char *或char *?

How to convert a std::string to const char* or char*?

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


如果只想将std::string传递给需要const char*的函数,可以使用

1
2
std::string str;
const char * c = str.c_str();

如果你想得到一个可写的副本,比如char *,你可以用这个来实现:

1
2
3
4
5
6
7
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::作用域数组

当超出范围时,boost::scoped_array将为您删除内存:

1
2
3
4
5
6
7
8
9
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::载体

这是标准方法(不需要任何外部库)。您使用std::vector,它完全为您管理内存。

1
2
3
4
5
std::string str;
std::vector<char> writable(str.begin(), str.end());
writable.push_back('\0');

// get the char* using &writable[0] or &*writable.begin()


给定的说………………… </P >好。

1
std::string x ="hello";

(一)"越来越"或"char * const char *"从"字符串"

(一)技术对山羊是字符指针的有效输入范围随xremains和是不是进一步的改进 </P >好。

C + + 11 simplifies下面所有的东西;给访问同样的内部缓冲区的字符串: </P >好。

1
2
3
4
5
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个额外的现在。/ 0字符后的《终结者explicitly指定字符串的内容(例如std::string("this\0that", 9)将缓冲区控股"this\0that\0")。 </P >好。

在给定的任何部分: </P >好。

1
2
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 >好。

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

A现在。在写作《字符串是不变化的stringsize()string的是allowed对人员和包含的任何数,它们是给定的,没有特别的治疗std::string村(同一个C++ 03)。 </P >好。

C++ 03,事情更复杂的是considerably(关键的差异highlighted): </P >好。

  • x.data() </P >好。

    • 剧情const char*到字符串的内部缓冲区,这我不需要到农村,和一个标准的conclude(即现在。其次可能会问['h', 'e', 'l', 'l', 'o']村未初始化存储或垃圾值,与accidental accesses thereto具有undefined行为)。
      • x.size()读人物是安全的",即x[x.size() - 1]x[0]
      • 为空字符串,y-o-u-r-e保证和控制的一些非空指针,车辆可以做safely添加0(hurray!)不,但你是指针的引用。
  • &x[0] </P >好。

    • 这就为空字符串(undefined行为21.3.4)
      • 例如,给定的f(const char* p, size_t n) { if (n == 0) return; ...whatever... }你不要的f(&x[0], x.size());呼叫时使用f(x.data(), ...)x.empty()哦。
    • 此外,作为一x.data()但:
      • constyields x这一非constchar*指针;你可以overwrite字符串的内容
  • x.c_str() </P >好。

    • 剧情const char*安(到现在。asciiz端基)表示的值(即"H"、"E"、"L"、"L"、"O"、"0"])。
    • 尽管少,如果选择了做任何implementations SO,《C++ 03标准是worded to allow the字符串执行"create a成不同的自由到现在。-封端的缓冲区的运行,从潜在的非现在。端缓冲区的"暴露"和&x[0]x.data()
    • x.size()+ 1的特点是"安全"的读。
    • 安全保证和控制,甚至为空字符串("0")。

访问的法律后果外指数

whichever路你得到一个指针,你必须不访问存储器,从指针的存在进一步保证和控制的礼物比人物的描述上。attempts做这么有undefined行为,和一个非常好的实时应用程序crashes和垃圾的结果,即使在读取数据,和additionally批发业务,把腐败和/或安全vulnerabilities writes指南。 </P >好。 这些指针何时失效?

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

另请参阅如何获取即使在x离开作用域或在下面进一步修改后仍有效的字符指针…好的。那么,哪个更好用呢?

从C++ 11,使用ECDCX1,4为ASCIZ数据,EDCOX1,5为"二进制"数据(下面进一步解释)。好的。

在C++ 03中,使用EDCOX1 OR 4 }除非EDCOX1〔5〕是足够的,并且在EDCOX1×9的条件下更倾向于EDCOX1×5,因为它对于空字符串是安全的。好的。

…尽量理解程序,在适当的时候使用data(),否则可能会犯其他错误…好的。

.c_str()保证的ascii nul''0'字符被许多函数用作表示相关和安全访问数据结束的哨兵值。这适用于两个C++函数,例如EDCOX1,12,和共享-C函数,如EDCOX1,13,EDCX1,14。好的。

给定C++ 03的EDCOX1,4的关于返回的缓冲区的保证是EDOCX1×5的超级集合,您总是可以安全地使用EDCOX1×4,但是人们有时不这样做是因为:好的。

  • 使用.data()与其他读取源代码的程序员通信,数据不是asciiz(相反,您使用字符串来存储数据块(有时甚至不是真正的文本数据块),或者将其传递给另一个将其视为"二进制"数据块的函数。这对于确保其他程序员的代码更改继续正确地处理数据是至关重要的。
  • C++ 03:只有一个机会,您的EDCOX1×0实现需要进行额外的内存分配和/或数据复制,以准备NUL终止的缓冲区。

作为进一步的提示,如果函数的参数需要(constchar*但不坚持获取x.size()的话,那么函数可能需要asciiz输入,因此.c_str()是一个很好的选择(函数需要知道文本以某种方式终止在哪里,因此如果它不是一个单独的参数,那么它只能是一个约定,如ngth前缀或sentinel或某些固定的预期长度)。好的。如何获取即使在x离开作用域或进一步修改后仍有效的字符指针

您需要将stringx的内容复制到x之外的新内存区域。这个外部缓冲区可以在许多地方,例如另一个string或字符数组变量,由于处于不同的作用域(如名称空间、全局、静态、堆、共享内存、内存映射文件),它可能或可能没有与x不同的生存期。好的。

要将文本从std::string x复制到独立的字符数组中,请执行以下操作:好的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// 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之外,但是您可以如何处理它?一点点随机的例子…好的。

  • 将"C"代码访问到C++ EDCOX1×2的文本,如EDCOX1×7
  • 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和compiler native)可能将数据作为asciiz传递,以避免冲突。

好啊。


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

您可以使用&mystring[0]来获取char *指针,但有两个gotcha:您不一定会得到以零结尾的字符串,并且您将无法更改字符串的大小。尤其要注意不要在字符串末尾添加字符,否则会导致缓冲区溢出(以及可能的崩溃)。

没有保证所有的字符都是同一个连续缓冲区的一部分,直到C++ 11,但是实际上,所有已知的std::string的实现都是这样工作的;参见"&;S(0)"指向STD::String中的连续字符吗?.

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


C++ 17

C++ 17(即将到来的标准)改变模板EDCOX1的大纲(21):添加EconCx1的非const过载(22):

charT* data() noexcept;

Returns: A pointer p such that p + i == &operator for each i in [0,size()].

来自std::basic_stringCharT const *

1
2
std::string const cstr = {"..." };
char const * p = cstr.data(); // or .c_str()

来自std::basic_stringCharT *

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

C++ 11来自std::basic_stringCharT const *

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

来自std::basic_stringCharT *

从C++ 11开始,该标准称:

  • The char-like objects in a basic_string object shall be stored contiguously. That is, for any basic_string object s, the identity &*(s.begin() + n) == &*s.begin() + n shall hold for all values of n such that 0 <= n < s.size().
  • const_reference operator[](size_type pos) const;
    reference operator[](size_type pos);

    Returns: *(begin() + pos) if pos < size(), otherwise a reference to an object of type CharT with value CharT(); the referenced value shall not be modified.

  • const charT* c_str() const noexcept;
    const charT* data() const noexcept;

    Returns: A pointer p such that p + i == &operator[](i) for each i in [0,size()].

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

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

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

    赞成

    • 简单和简短
    • 快速(仅限不涉及副本的方法)

    欺骗

    • 最终的'\0'不需要改变/不一定是非常量存储器的一部分。

    2。使用std::vector

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

    赞成

    • 简单的
    • 自动内存处理
    • 动态的

    欺骗

    • 需要字符串副本

    三。如果N是编译时间常数(并且足够小),则使用std::array

    1
    2
    3
    std::string foo{"text"};
    std::array<char, 5u> fca;
    std::copy(foo.data(), foo.data()+foo.size()+1u, fca.begin());

    赞成

    • 简单的
    • 堆栈内存处理

    欺骗

    • 静态的
    • 需要字符串副本

    4。自动删除存储的原始内存分配

    1
    2
    3
    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。手动处理的原始内存分配

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    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;
    }

    赞成

    • 最大"控制"

    反对的论点

    • 需要字符串副本
    • 最大责任/错误敏感性
    • 复合物

    我正在使用一个API,它有许多函数get作为输入a char*

    我创建了一个小类来面对这种问题,我已经实现了raii习语。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    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_; }
    };

    您可以将其用作:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    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

    我之所以称为DeepString类,是因为它正在创建一个现有字符串的深度和唯一副本(DeepString不可复制)。


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


    看看这个:

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

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


    试试这个

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