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


当前回答

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

其他回答

从c++ std字符串转换到c风格字符串现在真的很容易。

为此,我们有string::copy函数,它可以轻松地将std字符串转换为C风格字符串。参考

字符串::连续复制函数形参

Char字符串指针 字符串大小,b复制多少个字符 位置,从字符复制开始的位置

另一件重要的事,

此函数不会在操作结束时附加空字符。所以,我们需要手动放置它。

代码考试在下面

// char string
char chText[20];

// c++ string
string text =  "I am a Programmer";

// conversion from c++ string to char string
// this function does not append a null character at the end of operation
text.copy(chText, text.size(), 0);

// we need to put it manually
chText[text.size()] = '\0';

// below statement prints "I am a Programmer"
cout << chText << endl;

反之亦然,从C样式字符串转换到c++ std字符串要容易得多

有三种方法可以将C样式字符串转换为c++ std字符串

第一个是使用构造函数,

char chText[20] = "I am a Programmer";
// using constructor
string text(chText);

第二个是使用string::assign方法

// char string
char chText[20] = "I am a Programmer";

// c++ string
string text;

// convertion from char string to c++ string
// using assign function
text.assign(chText);

第三个是赋值操作符(=),其中字符串类使用操作符重载

// char string
char chText[20] = "I am a Programmer";

// c++ string
// convertion from char string to c++ string using assignment operator overloading
string text = chText;

第三个也可以写成如下-

// char string
char chText[20] = "I am a Programmer";

// c++ string
string text;


// convertion from char string to c++ string
text = chText;

鉴于说…

std::string x = "hello";

从string对象中获取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不会改变字符串的大小();string对象允许包含任意数量的NULs——std::string对它们没有特殊处理(c++ 03中相同)。

在c++ 03中,事情要复杂得多(重点区别突出显示):

x.data() returns const char* to the string's internal buffer which wasn't required by the Standard to conclude with a NUL (i.e. might be ['h', 'e', 'l', 'l', 'o'] followed by uninitialised or garbage values, with accidental accesses thereto having undefined behaviour). x.size() characters are safe to read, i.e. x[0] through x[x.size() - 1] for empty strings, you're guaranteed some non-NULL pointer to which 0 can be safely added (hurray!), but you shouldn't dereference that pointer. &x[0] for empty strings this has undefined behaviour (21.3.4) e.g. given f(const char* p, size_t n) { if (n == 0) return; ...whatever... } you mustn't call f(&x[0], x.size()); when x.empty() - just use f(x.data(), ...). otherwise, as per x.data() but: for non-const x this yields a non-const char* pointer; you can overwrite string content x.c_str() returns const char* to an ASCIIZ (NUL-terminated) representation of the value (i.e. ['h', 'e', 'l', 'l', 'o', '\0']). although few if any implementations chose to do so, the C++03 Standard was worded to allow the string implementation the freedom to create a distinct NUL-terminated buffer on the fly, from the potentially non-NUL terminated buffer "exposed" by x.data() and &x[0] x.size() + 1 characters are safe to read. guaranteed safe even for empty strings (['\0']).

访问外部法律索引的后果

无论以何种方式获取指针,都不能访问指针以外的内存,不能访问上述描述中保证存在的字符。尝试这样做会有未定义的行为,即使对于读,也有非常真实的应用程序崩溃和垃圾结果的机会,而且对于写,还会有大量数据、堆栈损坏和/或安全漏洞。

这些指针什么时候失效?

如果调用某个字符串成员函数来修改字符串或保留进一步的容量,则上述任何方法之前返回的任何指针值都将无效。您可以再次使用这些方法来获取另一个指针。(规则与迭代器到字符串的规则相同)。

请参见如何在x离开作用域或在....下面进一步修改后仍使字符指针有效

那么,用哪个更好呢?

从c++ 11开始,使用.c_str()表示ASCIIZ数据,使用.data()表示“二进制”数据(下文将进一步解释)。

在c++ 03中,使用.c_str(),除非确定.data()是足够的,并且优先使用.data()而不是&x[0],因为它对空字符串....是安全的

...尝试充分理解程序,以便在适当的时候使用data(),否则您可能会犯其他错误……

由.c_str()保证的ASCII NUL '\0'字符被许多函数用作标记值,表示相关且可安全访问的数据的结束。这既适用于c++函数,如fstream::fstream(const char* filename,…),也适用于与C语言共享的函数,如strchr()和printf()。

鉴于c++ 03的.c_str()对返回缓冲区的保证是.data()的超集,您总是可以安全地使用.c_str(),但人们有时不会这样做,因为:

using .data() communicates to other programmers reading the source code that the data is not ASCIIZ (rather, you're using the string to store a block of data (which sometimes isn't even really textual)), or that you're passing it to another function that treats it as a block of "binary" data. This can be a crucial insight in ensuring that other programmers' code changes continue to handle the data properly. C++03 only: there's a slight chance that your string implementation will need to do some extra memory allocation and/or data copying in order to prepare the NUL terminated buffer

作为进一步的提示,如果函数的形参需要(const) char*,但不坚持获取x.s size(),则该函数可能需要一个ascii输入,因此.c_str()是一个很好的选择(函数需要知道文本以某种方式在何处结束,因此如果它不是一个单独的形参,则只能是一个约定,如长度前缀或哨兵或一些固定的预期长度)。

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

你需要将字符串x的内容复制到x外部的一个新的内存区域。这个外部缓冲区可能在很多地方,比如另一个字符串或字符数组变量,由于在不同的作用域(例如命名空间,全局,静态,堆,共享内存,内存映射文件),它可能有或没有与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);

想要从字符串生成char*或const char*的其他原因

那么,上面你已经看到了如何获取(const) char*,以及如何独立于原始字符串复制文本,但是你可以用它做什么呢?一些随机的例子……

give "C" code access to the C++ string's text, as in printf("x is '%s'", x.c_str()); copy x's text to a buffer specified by your function's caller (e.g. strncpy(callers_buffer, callers_buffer_size, x.c_str())), or volatile memory used for device I/O (e.g. for (const char* p = x.c_str(); *p; ++p) *p_device = *p;) append x's text to an character array already containing some ASCIIZ text (e.g. strcat(other_buffer, x.c_str())) - be careful not to overrun the buffer (in many situations you may need to use strncat) return a const char* or char* from a function (perhaps for historical reasons - client's using your existing API - or for C compatibility you don't want to return a std::string, but do want to copy your string's data somewhere for the caller) be careful not to return a pointer that may be dereferenced by the caller after a local string variable to which that pointer pointed has left scope some projects with shared objects compiled/linked for different std::string implementations (e.g. STLport and compiler-native) may pass data as ASCIIZ to avoid conflicts

我正在使用一个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 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不可复制)。

比方说, 字符串str =“堆栈”;

1)将字符串转换为char*

  char* s_rw=&str[0]; 

上面的字符*(即。, s_rw)是可读可写的,并且指向基 需要转换为char*的字符串的地址

2)将字符串转换为const char*

   const char* s_r=&str[0];

上面的const char*(即s_r)是可读的但不可写的,并且指向 字符串的基址。

如果你只是想将std::string传递给一个需要const char *的函数,你可以使用.c_str():

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

如果你需要一个非const char *,调用.data():

std::string str;
char * c = str.data();

.data()是在c++ 17中添加的。在此之前,你可以使用&str[0]。

注意,如果std::string是const, .data()将返回const char *,就像.c_str()一样。

如果字符串被销毁或重新分配内存,指针将失效。

指针指向一个以空结束的字符串,终止符不计入str.size()。不允许将非空字符分配给结束符。