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

- 30,738
- 21
- 105
- 131

- 13,904
- 9
- 37
- 43
-
2Instead of: char * writable = new char[str.size() + 1]; You can use char writable[str.size() + 1]; Then you don't need to worry about deleting writable or exception handling. – Jun 21 '10 at 09:34
-
12You can't use str.size() unless the size is known at compile time, also it might overflow your stack if the fixed size value is huge. – paulm Oct 05 '12 at 15:32
-
1char* result = strcpy((char*)malloc(str.length()+1), str.c_str()); – cegprakash Jul 12 '14 at 12:10
-
9@cegprakash `strcpy` and `malloc` aren't really the C++ way. – boycy Sep 25 '14 at 09:29
-
@boycy: you mean they are imaginary? – cegprakash Sep 26 '14 at 00:45
-
8No, but `char* dest = new char[str.length() + 1]; std::copy(str.begin(), str.end(), dest)` would be more idiomatic C++. `strcpy()` and `malloc()` aren't wrong or problematic, but it seems inconsistent to use a C++ string and C library facilities with C++ equivalents in the same block of code. – boycy Sep 27 '14 at 08:38
-
`stringName.c_str()` so long as it's a `std::string`, `std::wstring`, or something like a `winrt::hstring`. – kayleeFrye_onDeck Jan 30 '19 at 02:14
11 Answers
If you just want to pass a std::string
to a function that needs const char *
, you can use .c_str()
:
std::string str;
const char * c = str.c_str();
And if you need a non-const char *
, call .data()
:
std::string str;
char * c = str.data();
.data()
was added in C++17. Before that, you can use &str[0]
.
Note that if the std::string
is const
, .data()
will return const char *
instead, like .c_str()
.
The pointer becomes invalid if the string is destroyed or reallocates memory.
The pointer points to a null-terminated string, and the terminator doesn't count against str.size()
. You're not allowed to assign a non-null character to the terminator.

- 78,603
- 9
- 131
- 207

- 496,577
- 130
- 894
- 1,212
-
53
-
75you could, but strdup is not a c or c++ standard function, it's from posix :) – Johannes Schaub - litb Dec 07 '08 at 20:39
-
16what i would probably prefer generally is std::vector
writable(str.begin(), str.end()); writable.push_back('\0'); char * c = &writable[0]; – Johannes Schaub - litb Dec 07 '08 at 20:42 -
6You could also construct the vector with: vector
writable(str.c_str(), str.size() + 1); – efotinis Dec 07 '08 at 21:08 -
4Definitely use std::vector. Allocating the array of char is not exception safe. – Martin York Dec 08 '08 at 04:07
-
I agree: litb, you should add your "vector" solution to your main answer, as it is (exception-) safer than the raw new/delete solution. – paercebal Dec 09 '08 at 23:13
-
1I'm curious why you're bending over backwards to use std::copy(). Wouldn't using strcpy( the_destination, str.c_str()) - or strlcpy() if you have it - work as well and be more immediately obvious what's going on? strcpy() will work with any of scoped_array, vector, or a raw memory allocation. – Michael Burr Dec 10 '08 at 00:33
-
19std::copy is the c++ way of doing this, without the need of getting at the string pointer. I try to avoid using C functions as much as i can. – Johannes Schaub - litb Dec 10 '08 at 03:29
-
2@efotinis: Which vector constructor is `vector
writable(str.c_str(), str.size() + 1);` using? – user200783 Nov 11 '10 at 10:13 -
1@Paul Baker: That's an imaginary ctor I've come up with :) I've mixed it up with std::string's ctor (or maybe it was a non-standard extension of VC6... *shudder*). Anyway, my preferred solution is the one mentioned in litb's comment above (with begin/end iters). – efotinis Nov 13 '10 at 09:06
-
2BTW, if you use something like strdup(), you must call free() later (as opposed to delete []). – njamesp May 17 '12 at 23:05
-
4I'd suggest it is equally the "C++ way" to simply mutate std::string in-place as its public interface exposes `char &operator[]`: this is specified and guaranteed behaviour. – dmw Jan 28 '13 at 10:10
-
1
-
2
-
3You should add a comment "DON'T DO THIS" next to the `new char[..]` statement. I suspect that many people just copy/paste the code sample without reading the accompanying text. – StackedCrooked Mar 15 '14 at 00:06
-
1As a C++ neophyte, why wouldn't I just use std::strcpy(dest, str.c_str())? – Finster Apr 18 '14 at 21:20
-
3@Finster that's totally fine and perhaps I would have used it in real code aswell when in hurry :) I just like to use `std::copy` when I have time to make nice code. Let's not forget there's a difference (albeit an unlikely one with real strings - but who knows what he's going to store). The `std::copy` will copy embedded null bytes aswell, till the end of the `std::string`. – Johannes Schaub - litb Apr 18 '14 at 22:26
-
1Why not copy the string and pass ©[0] for a writable char* of a fixed size? – Nick May 07 '14 at 10:15
-
-
2Instead of `std::copy(str.begin(), str.end(), writable); writable[str.size()] = '\0';`, why not just use `std::copy(str.begin(),str.end() + 1,writable);`? – rsethc Sep 02 '14 at 12:07
-
2@rsethc because in C++03 that was not valid. I am not sure what the exact rule in C++11 and C++14 is for it. They guarantee that the string is zero terminated and contiguous, at least – Johannes Schaub - litb Sep 02 '14 at 17:39
-
1Ah, so in 03 it was not guaranteed to have a null terminator? That makes sense. – rsethc Sep 02 '14 at 18:55
-
2@rsethc what I worried more about is the `end() + 1`, not so much about the null terminator (I am no library expert, but I don't think that any of the popular library implementations around today have `std::string` without a trailing `\0`). In debug builds, some library implementations have containers where `.end()` returns a class object that throws/core-dumps on `.end() + 1`. So I better be cautious and write code that I definitely know works :) – Johannes Schaub - litb Sep 02 '14 at 20:21
-
1That sounds incredibly wasteful, but I'm sure there's some reason for it. I very rarely use the C++ standard library and stick to the C stdlib, so I haven't had much practice with these. Would have expected that `.end()` would return a pointer-size int, or something similar. – rsethc Sep 03 '14 at 03:01
-
-
4Solutions involving `strcpy()` or `strdup()` can fail if the `std::string` contains embedded null characters. – Keith Thompson Nov 03 '15 at 21:13
-
3Instead of `boost::scoped_array
`, one can also use `std::unique_ptr – tmlen Jun 06 '16 at 11:25` from the STL: `std::unique_ptr writable(new char[str.size() + 1]);`. It also deallocates the array using `delete[]` when it goes out of scope. -
26As of C++17, [`std::string::data()`](http://en.cppreference.com/w/cpp/string/basic_string/data) now returns a `CharT*` instead of a `const CharT*`. It might be a good idea to update this answer :) – Rakete1111 Mar 31 '17 at 12:06
-
Given that the issues with simply using `data` or `&s[0]` have been fixed for three released language versions now, this all seems overly complicated. Even if the string is `const`, a simple copy of it should be enough. – Alex Celeste Jun 01 '18 at 13:54
-
1`std::unique_ptr
writable(str.size() + 1)` can be used the same way as `boost::scoped_array` – tmlen Oct 31 '20 at 20:52 -
I've took liberty to remove the mention of manual memory management (we shouldn't recommend that), and other ways of managing memory (if you want a mutable copy of the string, just copy the string). – HolyBlackCat Nov 10 '22 at 18:25
-
@HolyBlackCat I can't imagine why you would *remove* it from the answer. The char* copy approach was nearly exactly what I was looking for. Please keep in mind that answers aren't just *recommendations* and that their authors are not simply writing code *for* other people. Answers are for informational purposes. If there is a concern you have with an answer, I would suggest you make note of it in the comments, or better, directly in the answer. Almost 2/3rds of the answer seems to have been deleted in your edit. – Kröw Mar 09 '23 at 10:02
-
@Kröw Can you explain a bit what your use case is? I can't imagine why one would want to allocate a char array manually, except perhaps to pass it to a C library that takes ownership of it. – HolyBlackCat Mar 09 '23 at 10:15
Given say...
std::string x = "hello";
Getting a `char *` or `const char*` from a `string`
How to get a character pointer that's valid while x
remains in scope and isn't modified further
C++11 simplifies things; the following all give access to the same internal string buffer:
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...
All the above pointers will hold the same value - the address of the first character in the buffer. Even an empty string has a "first character in the buffer", because C++11 guarantees to always keep an extra NUL/0 terminator character after the explicitly assigned string content (e.g. std::string("this\0that", 9)
will have a buffer holding "this\0that\0"
).
Given any of the above pointers:
char c = p[n]; // valid for n <= x.size()
// i.e. you can safely read the NUL at p[x.size()]
Only for the non-const
pointer p_writable_data
and from &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
Writing a NUL elsewhere in the string does not change the string
's size()
; string
's are allowed to contain any number of NULs - they are given no special treatment by std::string
(same in C++03).
In C++03, things were considerably more complicated (key differences highlighted):
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]
throughx[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.
- returns
&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 callf(&x[0], x.size());
whenx.empty()
- just usef(x.data(), ...)
.
- e.g. given
- otherwise, as per
x.data()
but:- for non-
const
x
this yields a non-const
char*
pointer; you can overwrite string content
- for non-
- for empty strings this has undefined behaviour (21.3.4)
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']).
- returns
Consequences of accessing outside legal indices
Whichever way you get a pointer, you must not access memory further along from the pointer than the characters guaranteed present in the descriptions above. Attempts to do so have undefined behaviour, with a very real chance of application crashes and garbage results even for reads, and additionally wholesale data, stack corruption and/or security vulnerabilities for writes.
When do those pointers get invalidated?
If you call some string
member function that modifies the string
or reserves further capacity, any pointer values returned beforehand by any of the above methods are invalidated. You can use those methods again to get another pointer. (The rules are the same as for iterators into string
s).
See also How to get a character pointer valid even after x
leaves scope or is modified further below....
So, which is better to use?
From C++11, use .c_str()
for ASCIIZ data, and .data()
for "binary" data (explained further below).
In C++03, use .c_str()
unless certain that .data()
is adequate, and prefer .data()
over &x[0]
as it's safe for empty strings....
...try to understand the program enough to use data()
when appropriate, or you'll probably make other mistakes...
The ASCII NUL '\0' character guaranteed by .c_str()
is used by many functions as a sentinel value denoting the end of relevant and safe-to-access data. This applies to both C++-only functions like say fstream::fstream(const char* filename, ...)
and shared-with-C functions like strchr()
, and printf()
.
Given C++03's .c_str()
's guarantees about the returned buffer are a super-set of .data()
's, you can always safely use .c_str()
, but people sometimes don't because:
- 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
As a further hint, if a function's parameters require the (const
) char*
but don't insist on getting x.size()
, the function probably needs an ASCIIZ input, so .c_str()
is a good choice (the function needs to know where the text terminates somehow, so if it's not a separate parameter it can only be a convention like a length-prefix or sentinel or some fixed expected length).
How to get a character pointer valid even after x
leaves scope or is modified further
You'll need to copy the contents of the string
x
to a new memory area outside x
. This external buffer could be in many places such as another string
or character array variable, it may or may not have a different lifetime than x
due to being in a different scope (e.g. namespace, global, static, heap, shared memory, memory mapped file).
To copy the text from std::string x
into an independent character array:
// 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);
Other reasons to want a char*
or const char*
generated from a string
So, above you've seen how to get a (const
) char*
, and how to make a copy of the text independent of the original string
, but what can you do with it? A random smattering of examples...
- give "C" code access to the C++
string
's text, as inprintf("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 usestrncat
) - return a
const char*
orchar*
from a function (perhaps for historical reasons - client's using your existing API - or for C compatibility you don't want to return astd::string
, but do want to copy yourstring
'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
- be careful not to return a pointer that may be dereferenced by the caller after a local

- 102,968
- 15
- 177
- 252
-
4Nice one. Another reason to want a char* (non const) is to operate with MPI broadcast. It looks nicer if you don't have to copy back and forth. I would have personally offered a char* const getter to string. Const pointer, but editable string. Although it may have messed with the implicit conversion from const char* to string... – bartgol Oct 30 '14 at 22:50
Use the .c_str()
method for const char *
.
You can use &mystring[0]
to get a char *
pointer, but there are a couple of gotcha's: you won't necessarily get a zero terminated string, and you won't be able to change the string's size. You especially have to be careful not to add characters past the end of the string or you'll get a buffer overrun (and probable crash).
There was no guarantee that all of the characters would be part of the same contiguous buffer until C++11, but in practice all known implementations of std::string
worked that way anyway; see Does “&s[0]” point to contiguous characters in a std::string?.
Note that many string
member functions will reallocate the internal buffer and invalidate any pointers you might have saved. Best to use them immediately and then discard.

- 1
- 1

- 299,747
- 42
- 398
- 622
-
1you should note that data() returns const char * :) what you mean is &str[0], which returns a contiguous, but not necassary null terminated string. – Johannes Schaub - litb Dec 07 '08 at 19:44
-
1@litb, Argh! That's what I get for trying to whip up a quick answer. I've used your solution in the past, don't know why it wasn't the first thing that came to mind. I've edited my answer. – Mark Ransom Dec 07 '08 at 19:54
-
2
-
1@MSalters, thanks - I didn't know that. I'd be hard pressed to find an implementation where that wasn't the case, though. – Mark Ransom Dec 08 '08 at 20:04
-
2
C++17
C++17 (upcoming standard) changes the synopsis of the template basic_string
adding a non const overload of data()
:
charT* data() noexcept;
Returns: A pointer p such that p + i == &operator for each i in [0,size()].
CharT const *
from std::basic_string<CharT>
std::string const cstr = { "..." };
char const * p = cstr.data(); // or .c_str()
CharT *
from std::basic_string<CharT>
std::string str = { "..." };
char * p = str.data();
C++11
CharT const *
from std::basic_string<CharT>
std::string str = { "..." };
str.c_str();
CharT *
from std::basic_string<CharT>
From C++11 onwards, the standard says:
- The char-like objects in a
basic_string
object shall be stored contiguously. That is, for anybasic_string
objects
, the identity&*(s.begin() + n) == &*s.begin() + n
shall hold for all values ofn
such that0 <= n < s.size()
.
const_reference operator[](size_type pos) const;
reference operator[](size_type pos);
Returns:
*(begin() + pos)
ifpos < size()
, otherwise a reference to an object of typeCharT
with valueCharT()
; 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 eachi
in[0,size()]
.
There are severable possible ways to get a non const character pointer.
1. Use the contiguous storage of C++11
std::string foo{"text"};
auto p = &*foo.begin();
Pro
- Simple and short
- Fast (only method with no copy involved)
Cons
- Final
'\0'
is not to be altered / not necessarily part of the non-const memory.
2. Use std::vector<CharT>
std::string foo{"text"};
std::vector<char> fcv(foo.data(), foo.data()+foo.size()+1u);
auto p = fcv.data();
Pro
- Simple
- Automatic memory handling
- Dynamic
Cons
- Requires string copy
3. Use std::array<CharT, N>
if N
is compile time constant (and small enough)
std::string foo{"text"};
std::array<char, 5u> fca;
std::copy(foo.data(), foo.data()+foo.size()+1u, fca.begin());
Pro
- Simple
- Stack memory handling
Cons
- Static
- Requires string copy
4. Raw memory allocation with automatic storage deletion
std::string foo{ "text" };
auto p = std::make_unique<char[]>(foo.size()+1u);
std::copy(foo.data(), foo.data() + foo.size() + 1u, &p[0]);
Pro
- Small memory footprint
- Automatic deletion
- Simple
Cons
- Requires string copy
- Static (dynamic usage requires lots more code)
- Less features than vector or array
5. Raw memory allocation with manual handling
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;
}
Pro
- Maximum 'control'
Con
- Requires string copy
- Maximum liability / susceptibility for errors
- Complex

- 24,090
- 7
- 47
- 71
Just see this:
string str1("stackoverflow");
const char * str2 = str1.c_str();
However, note that this will return a const char *
.
For a char *
, use strcpy
to copy it into another char
array.

- 7,904
- 4
- 42
- 42

- 1,007
- 2
- 14
- 28
-
27Hi, what you posted has already been said multiple times, with more details, in other answers to the 5 year old question. It's fine to answer older questions, but only if you add new information. Otherwise, it's just noise. – Mat May 12 '13 at 08:21
-
9
I am working with an API with a lot of functions that get a char*
as an input.
I have created a small class to face this kind of problem, and I have implemented the RAII idiom.
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_; }
};
And you can use it as:
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
I have called the class DeepString
because it is creating a deep and unique copy (the DeepString
is not copyable) of an existing string.

- 30,738
- 21
- 105
- 131

- 3,918
- 1
- 27
- 41
-
3I would avoid this naming convention. `c_str()` as used by `std` is an abbreviation for "C-string" not "const string" and `str()` always returns a `std::basic_string`, not `char*` (for example `std::stringstream::str()`) – bcrist Sep 05 '15 at 22:27
char* result = strcpy((char*)malloc(str.length()+1), str.c_str());

- 2,937
- 33
- 60
-
2looks fancy but really hard to understand... Simple is the best IMO – Naeem A. Malik Dec 15 '14 at 11:53
-
4strcpy(), malloc(), length() and c_str() are basic functions and there is nothing hard in this. Just allocating memory and copying. – cegprakash Dec 17 '14 at 08:55
-
6yes the functions are basic but you've twisted and bent them to look like bowl of spaghetti or one liner Frankenstein's monster :) – Naeem A. Malik Dec 17 '14 at 20:41
-
4__Yes the functions are basic but...__ did you remember when you start to deal with a programming language? Some lines more to explain and it will really help a neophyte to learn why for example is different or better than [this answer](http://stackoverflow.com/a/16505452/3569208):) – Hastur Sep 25 '15 at 12:08
-
3@cegprakash: Whenever there is a malloc(), there also has to be a free(). Otherwise the code leaks memory, and so does the solution in your answer. Allocating memory without at least hinting to the required deallocation is bad practice for such questions. – Striezel Aug 23 '16 at 19:03
Converting from c++ std string to C style string is really easy now.
For that we have string::copy
function which will easily convert std string to C style string. reference
string::copy
functions parameters serially
- char string pointer
- string size, how many characters will b copied
- position, from where character copy will start
Another important thing,
This function does not append a null character at the end of operation. So, we need to put it manually.
Code exam are in below -
// 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;
Vice Versa, Converting from C style string to C++ std string is lot more easier
There is three ways we can convert from C style string to C++ std string
First one is using constructor,
char chText[20] = "I am a Programmer";
// using constructor
string text(chText);
Second one is using string::assign
method
// 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);
Third one is assignment operator(=), in which string class uses operator overloading
// 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;
third one can be also write like below -
// char string
char chText[20] = "I am a Programmer";
// c++ string
string text;
// convertion from char string to c++ string
text = chText;

- 2,558
- 2
- 25
- 44
let's say, string str="stack";
1)converting string to char*
char* s_rw=&str[0];
The above char*(i.e., s_rw) is readable and writeable and points to the base address of the string which needs to be converted to char*
2)Converting string to const char*
const char* s_r=&str[0];
The above const char* (i.e., s_r) is readable but not writeable and points to the base address of the string.

- 486
- 5
- 5
This is especially useful when passing the underlying char*
buffer of a std::string
to C calls which expect and write to a char*
buffer. This way you get the best of both worlds!: the niceties of the C++ std::string
and the usability of it directly with C libraries you are calling from C++.
How to use a modern C++ std::string
as a C-style read/writable char*
or read-only null-terminated const char*
How can I convert a
std::string
to achar*
or aconst char*
?
Despite being a really old and highly-upvoted question, the information I'm about to cover isn't already well-covered, if covered at all, so this is a necessary addition, in particular the part about needing to pre-allocate the underlying C-string using the .resize()
method if you'd like to use it as a writable buffer.
All of the usages below require C++11 or later, except for the char* data()
call, which requires C++17 or later.
To run and test all example code below, and more, see and run my string__use_std_string_as_a_c_str_buffer.cpp file in my eRCaGuy_hello_world repo.
Quick summary:
#include <string>
constexpr size_t BUFFER_SIZE = 100;
std::string str;
// IMPORTANT: pre-allocate the underlying buffer to guarantee what size it is
str.resize(BUFFER_SIZE);
// -----------------------------------------------------------------------------
// Get read-writeable access to the underlying `char*` C-string at index i
// -----------------------------------------------------------------------------
char* c_str1 = &str[i]; // <=== my favorite!
char* c_str2 = str.data() + i;
char* c_str3 = &(*str.begin()) + i;
// NB: the C-strings above are NOT guaranteed to be null-terminated, so manually
// write in a null terminator at the index location where you want it if
// desired. Ex:
//
// 1. write a null terminator at some arbitrary position you choose (index 10
// here)
c_str1[10] = '\0';
// 2. write a null terminator at the last guaranteed valid position in the
// underlying C-string/array of chars
c_str2[str.size() - i - 1] = '\0';
// -----------------------------------------------------------------------------
// Get read-only access to the underlying `const char*` C-string at index i
// -----------------------------------------------------------------------------
const char* const_c_str1 = &str[i];
const char* const_c_str2 = str.c_str() + i; // guaranteed to be null-terminated,
// but not necessarily at the
// position you desire; the
// guaranteed null terminator will
// be at index location
// `str.size()`
Summary:
If in a hurry and you need:
- A read-writable
char*
C-string of the underlying buffer: just use section A Technique 1 in the code example just below:char* c_str1 = &str[i];
.- Just be sure to pre-allocate the underlying buffer size first via
str.resize(BUFFER_SIZE)
, if needed, is all, to ensure the underlying buffer is big enough for your needs.
- Just be sure to pre-allocate the underlying buffer size first via
- A read-only
const char*
C-string of the underlying buffer: use the same thing as above (const char* const_c_str1 = &str[i];
), orconst char* const_c_str1 = str.c_str() + i;
.
#include <string>
constexpr size_t BUFFER_SIZE = 100;
std::string str;
// IMPORTANT: pre-allocate the underlying buffer to guarantee what size it is
str.resize(BUFFER_SIZE);
// =============================================================================
// Now you can use the `std::string`'s underlying buffer directly as a C-string
// =============================================================================
// ---------------------------------------------------------
// A. As a read-writeable `char*` C-string
// ---------------------------------------------------------
// Technique 1 [best option if using C++11]: array indexing using `operator[]`
// to obtain a char, followed by obtaining its address with `&`
// - Documentation:
// https://en.cppreference.com/w/cpp/string/basic_string/operator_at
char* c_str1 = &str[0];
char* c_str2 = &str[10];
char* c_str3 = &str[33];
// etc.
// Technique 2 [best option if using C++17]: use the `.data()` method to obtain
// a `char*` directly.
// - Documentation:
// https://en.cppreference.com/w/cpp/string/basic_string/data
char* c_str11 = str.data(); // same as c_str1 above
char* c_str12 = str.data() + 10; // same as c_str2 above
char* c_str13 = str.data() + 33; // same as c_str3 above
// Technique 3 [fine in C++11 or later, but is awkward, so don't do this. It is
// for demonstration and learning purposes only]: use the `.begin()` method to
// obtain an iterator to the first char, and then use the iterator's
// `operator*()` dereference method to obtain the iterator's `char`
// `value_type`, and then take the address of that to obtain a `char*`
// - Documentation:
// - https://en.cppreference.com/w/cpp/string/basic_string/begin
// - https://en.cppreference.com/w/cpp/named_req/RandomAccessIterator
char* c_str21 = &(*str.begin()); // same as c_str1 and c_str11 above
char* c_str22 = &(*str.begin()) + 10; // same as c_str2 and c_str12 above
char* c_str23 = &(*str.begin()) + 33; // same as c_str3 and c_str13 above
// ---------------------------------------------------------
// B. As a read-only, null-terminated `const char*` C-string
// ---------------------------------------------------------
// - Documentation:
// https://en.cppreference.com/w/cpp/string/basic_string/c_str
const char* const_c_str1 = str.c_str(); // a const version of c_str1 above
const char* const_c_str2 = str.c_str() + 10; // a const version of c_str2 above
const char* const_c_str3 = str.c_str() + 33; // a const version of c_str3 above
Note that you can also use the .at(i)
and .front()
std::string
methods too, but I won't go into those since I think my examples are sufficient. For their documentation, see:
- https://en.cppreference.com/w/cpp/string/basic_string/at
- https://en.cppreference.com/w/cpp/string/basic_string/front
Details:
See also the note just above. I'm not going to cover the techniques using the .at(i)
and .front()
std::string
methods, since I think the several techniques I already present are sufficient.
1. Use a std::string
as a read/writable char*
To use a C++ std::string
as a C-style writable char*
buffer, you MUST first pre-allocate the string's internal buffer to change its .size()
by using .resize()
. Note that using .reserve()
to increase only the .capacity()
is NOT sufficient! The cppreference.com community wiki page for std::string::operator[]
correctly states:
If
pos > size()
, the behavior is undefined.
The resize()
method is what changes the size, not the reserve()
method, which changes only the capacity()
.
Ex:
#include <cstring> // `strcpy()`
#include <iostream>
#include <string>
constexpr size_t BUFFER_SIZE = 100;
std::string str;
str.resize(BUFFER_SIZE); // pre-allocate the underlying buffer
// check the size
std::cout << "str.size() = " << str.size() << "\n";
For all examples below, assume you have these C-strings:
constexpr char cstr1[] = "abcde ";
constexpr char cstr2[] = "fghijk";
Once you have pre-allocated an underlying buffer which is sufficiently large with resize()
, you can then access the underlying buffer as
a char*
in at least 3 ways:
- Technique 1 [best option if using C++11]: array indexing using
operator[]
to obtain a char, followed by obtaining its address with&
. Ex:
What if you have a pointer to achar* c_str; c_str = &str[0]; c_str = &str[5]; // etc. // Write these 2 C-strings into a `std::string`'s underlying buffer strcpy(&str[0], cstr1); strcpy(&str[sizeof(cstr1) - 1], cstr2); // `- 1` to overwrite the first // null terminator // print the string std::cout << str << "\n"; // output: `abcde fghijk`
std::string
? If you have a ptr to astd::string
, it must be dereferenced first with*pstr
before you can index into it as an array with theoperator[]
as&(*pstr)[0]
, so the syntax above becomes a little more awkward. Here is a full example:std::string str2; std::string* pstr = &str2; pstr->resize(BUFFER_SIZE); c_str = &(*pstr)[0]; // <=== dereference the ptr 1st before indexing into it // Or, to make the order of precedence // (https://en.cppreference.com/w/cpp/language/operator_precedence) really // obvious, you can optionally add extra parenthesis like this: c_str = &((*pstr)[0]);
- Technique 2 [best option if using C++17]: use the
.data()
method to obtain achar*
directly. Ex:char* c_str; c_str = str.data(); c_str = str.data() + 5; // etc. // Write these 2 C-strings into the `std::string`'s underlying buffer strcpy(str.data(), cstr1); strcpy(str.data() + (sizeof(cstr1) - 1), cstr2); // `- 1` to overwrite the // first null terminator // print the string std::cout << str << "\n"; // output: `abcde fghijk`
- Technique 3 [fine in C++11 and later, but is awkward, so don't do this. It is for demonstration and learning purposes only]: use the
.begin()
method to obtain an iterator to the first char, and then use the iterator'soperator*()
dereference method to obtain the iterator'schar
value_type
, and then take the address of that to obtain achar*
. Ex:char* c_str; c_str = &(*str.begin()); c_str = &(*str.begin()) + 5; // etc. // Write these 2 C-strings into the `std::string`'s underlying buffer strcpy(&(*str.begin()), cstr1); strcpy(&(*str.begin()) + (sizeof(cstr1) - 1), cstr2); // `- 1` to overwrite // the first null // terminator // print the string std::cout << str << "\n"; // output: `abcde fghijk`
Something important to be aware of is that when you call str.resize(100)
, it reserves at least 100 bytes for the underlying string, sets the size()
of the string to 100
, and initializes all 100
of those chars to char()
--AKA: the default value initialization value for char
(see my question here), which is the binary zero null-terminator, '\0'
. Therefore, whenever you call str.size()
it will return 100
even if the string simply has "hello"
in it followed by 95 null-terminators, or zeros. To get the length, or number of non-null-terminators in the string, you'll have to resort to the C function strlen()
, like this:
std::cout << strlen(str.c_str()) << "\n"; // prints `12` in the examples above
// instead of:
std::cout << str.size() << "\n"; // prints `100` in the examples above
2. Access a std::string
as a read-only, null-terminated const char*
To obtain a readable null-terminated const char*
from a std::string
, use the .c_str()
method. It returns a C-style string that is guaranteed to be null-terminated. Note that the .data()
method is NOT the same thing, as it is NOT guaranteed to be null-terminated!
Example:
std::string str = "hello world";
printf("%s\n", str.c_str());
References
(questions on Stack Overflow)
- How to convert a std::string to const char* or char*: How to convert a std::string to const char* or char*
- Directly write into char* buffer of std::string: Directly write into char* buffer of std::string
- Is there a way to get std:string's buffer: Is there a way to get std:string's buffer
(my content)
- [my test code] string__use_std_string_as_a_c_str_buffer.cpp
- [my Q] See the "Adjacently related" section at the bottom of my question here: What is a call to `char()`, `uint8_t()`, `int64_t()`, integer `T()`, etc, as a function in C++?
- *****+ [my comments about pre-allocating a buffer in the std::string]: Directly write into char* buffer of std::string
- *****+ [my comment on how to pre-allocate storage in a std::string, to be used as a char* buffer] Is there a way to get std:string's buffer
(from the cppreference.com community wiki)
https://en.cppreference.com/w/cpp/string/basic_string:
The elements of a basic_string are stored contiguously, that is, for a basic_string s, &*(s.begin () + n) == &*s.begin() + n for any n in [0, s.size()), or, equivalently, a pointer to s[0] can be passed to functions that expect a pointer to the first element of a null-terminated (since C++11)CharT[] array.
https://en.cppreference.com/w/cpp/string/basic_string/operator_at
Returns a reference to the character at specified location pos. No bounds checking is performed. If pos > size(), the behavior is undefined.
https://en.cppreference.com/w/cpp/string/basic_string/resize
https://en.cppreference.com/w/cpp/string/basic_string/reserve

- 36,492
- 15
- 194
- 265