467

I want to convert a std::string into a char* or char[] data type.

std::string str = "string";
char* chr = str;

Results in: “error: cannot convert ‘std::string’ to ‘char’ ...”.

What methods are there available to do this?

  • Does this answer your question? [How to convert a std::string to const char\* or char\*](https://stackoverflow.com/questions/347949/how-to-convert-a-stdstring-to-const-char-or-char) – ead Jun 24 '21 at 14:05

18 Answers18

821

It won't automatically convert (thank god). You'll have to use the method c_str() to get the C string version.

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

Note that it returns a const char *; you aren't allowed to change the C-style string returned by c_str(). If you want to process it you'll have to copy it first:

std::string str = "string";
char *cstr = new char[str.length() + 1];
strcpy(cstr, str.c_str());
// do stuff
delete [] cstr;

Or in modern C++:

std::vector<char> cstr(str.c_str(), str.c_str() + str.size() + 1);
orlp
  • 112,504
  • 36
  • 218
  • 315
  • 5
    @Kerrek SB: It was an example, would use a smart pointer in real code, or more likely avoid this `c_str` madness completely. – orlp Sep 08 '11 at 17:37
  • 16
    The answer is bulky, inelegant, non-local, uses raw arrays, and requires attention to exception safety. `vector` was invented precisely as a wrapper for dynamic arrays, so not using it seems like a missed opportunity at best, and in violation of the spirit of C++ at worst. – Kerrek SB Sep 08 '11 at 20:11
  • 30
    First of all, yes the answer is bulky. First I explain the OP's error (thinking that `std::string` would automatically convert) and then I explain what he should use, with a short code sample. Thinking forward I also explain some side effects of the use of this function, of which one is that you may not edit the string returned by `c_str()`. You mistakenly see my short examples as real problem-solving code, which it's not. – orlp Sep 08 '11 at 20:19
  • 9
    I downvoted the answer. This answer is indeed not useful and the fact that it was accepted is most unfortunate. This answer completely disregards good C++ programming practices and exception safety and there are far superior solutions, some of which are given in other answers to this question (e.g. the answer given by ildjarn which uses `std::vector`). – James McNellis Sep 08 '11 at 20:27
  • @nightcracker I was not expecting it to convert automatically, I just did not know how to make the conversion and gave that code as example to demonstrate what I was trying to achieve. I understand that some types have nothing to do with others even if they look similar at first glance. –  Sep 09 '11 at 16:09
  • 151
    @james-mcnellis, I picked this answer as the correct one because it answered **EXACTLY** what I was asking for... No more, no less. I did not ask for what you think that I should do, I did not ask for a different solution for what you think that I am doing, I did not ask for good practices. You have no idea what I am working in, where my code is going to be implemented and under what conditions. Some should learn to read, understand questions and to answer what is actually being asked. No need to show off here. –  Sep 09 '11 at 16:19
  • 4
    @Mario: Fair enough. It's not always obvious what the exact thing is that you're after. In this case, you seem to prefer adding manual memory management (along with its adherent complexity) to your solution, and that's fine; it was just not obvious from the start that that was part of your goals. – Kerrek SB Sep 09 '11 at 16:32
  • @kerrek, dont worry, a 10 bytes `char` data to call a single function once in my program won’t ruin my life. I wish that the author of that function expected something better than plain old char arrays but well, I sure can overcome this sad hit in my life. –  Sep 09 '11 at 16:37
  • @Mario: What's the function if I may ask? I've just smacked my head over a similar interface in the `mcrypt` functions which require mutable char arrays for blatantly constant strings... – Kerrek SB Sep 09 '11 at 17:26
  • @kerrek its a function I got somewhere, for me to be able to comunicate with bash scripts... I do not remember where I got it from, but it only accepted a char* as argument and changing it required too much code to be modified. –  Sep 09 '11 at 18:12
  • shouln't it be delete[] cstr; for the last line... not the author has put a space between delete and [] which is wrong. http://www.cplusplus.com/reference/new/operator%20delete[]/ – Deb Sep 14 '13 at 08:55
  • 2
    @Deb Are you seriously referencing [cplusplus.com](http://cplusplus.com/)? The actual C++11 standard actually defines `delete [ ]`, with the exception that _"Whenever the delete keyword is immediately followed by empty square brackets, it shall be interpreted as the second alternative."_ (the second alternative is `delete [ ]` in the original text). – orlp Sep 14 '13 at 17:30
  • I think many are missing the point of the complaints about this answer. I agree that this answers the question most simply, but a lot of coders are going to come to this question and not realize that there exists better alternatives from using a char *. It's worth it to include the alternatives as well. – aquirdturtle Jan 10 '16 at 20:25
  • 2
    To get an actual char* in the "modern" implementation, you might want to do: std::vector cvec(str.c_str(), str.c_str() + str.size() + 1); char *cstr = cvec.data(); – Avi Feb 14 '18 at 03:54
  • Why isn't the modern C++ answer `std::vector cstr(begin(str), end(str));` ? – Zitrax Nov 30 '18 at 14:51
  • @Zitrax `cstr` is not null-terminated in your example. – orlp Nov 30 '18 at 14:55
  • For everyone complaining about the memory allocation and use of char*: sometimes you have APIs which you can't change that take `(char* str, int start, int end)` and modify char* returning a new end. This is a solution for wrapping the call and allowing a new api of `std::string`. – Trevor Hickey Aug 18 '19 at 15:26
  • The "modern alternative" of this answer should be much more prominent than the out-dated `new[]` solution. But still, the real modern alternative is to use `.data()` which returns a non-const `char*`. – François Andrieux May 08 '20 at 14:24
  • 1
    This answer is long and causes a danger in memory leak if memory is not deleted properly with delete[]. How does it even deserve so many upvotes? Look at the answer by bobobobo, aka. the actual clean way of removing the const by grabbing the memory address to the 0th position of the string. – ProgrammingFreak Aug 13 '20 at 23:16
241

More details here, and here but you can use

string str = "some string" ;
char *cstr = &str[0];

As of C++11, you can also use the str.data() member function, which returns char *

string str = "some string" ;
char *cstr = str.data();
bobobobo
  • 64,917
  • 62
  • 258
  • 363
  • 24
    FWIW, in my book, this is the only correct answer to the question that was actually asked. An std::string is inherently mutable: people who are making it sound like modifying the contents of the string is somehow the devil's work seem to be missing this fact. – Jay Freeman -saurik- Oct 04 '13 at 01:25
  • 4
    yes, this is the correct answer. it's silly that, given the frequency of use, there isn't a standart method to do this, like msoft's lockbuffer. – Erik Aronesty Jan 28 '15 at 17:24
  • 1
    I changed 0 to 0u. Because some compilers/libraries will (believe it or not) complain about some ambiguity when warnings are turned all the way on for the &str[0] construct – Erik Aronesty Jan 28 '15 at 18:05
  • I doubt when the str is deleted, the char *cstr is made null. So I guess here only a pointer of the string is assigned to the char pointer. So the conversion of string to char* is not literally complete. String is only pointed to char* but its value is not converted. Am I correct??? – Samitha Chathuranga Dec 12 '15 at 08:30
  • 9
    Note that this is C++11 only. Previous versions might not have continuous storage or are missing the terminating null – Flamefire Jun 29 '17 at 20:14
  • 1
    This is the only one that worked for me, for some reason `c_str()` kept stopping at my null bytes even though my reading seems to indicate that it shouldn't. Maybe I did something else wrong somewhere else, but swapping `c_str()` with this (or even &str.first()) worked perfectly – Brian Leishman Aug 06 '18 at 13:36
  • 1
    i couldn't up vote this answer, because, not worked if (modified char array size) > (std::string instance initial size) – sailfish009 Jul 11 '19 at 03:02
  • Why would it "work" when you wrote beyond the buffer's bounds? That applies to _any_ pointer use, @sailfish. – Lightness Races in Orbit Aug 22 '19 at 15:05
  • @LightnessRacesinOrbit, i don't understand your comment, but i am saying this answer seems to be not right answer. even it is harmful. orlp's answer is enough for me. – sailfish009 Aug 25 '19 at 10:03
  • @sailfish009 And I'm saying that your statement has nothing to do with this answer and does not make it wrong in any way. – Lightness Races in Orbit Aug 25 '19 at 23:17
  • @LightnessRacesinOrbit, i think we need a talk. we are different. you insist it, but i don't agree. – sailfish009 Aug 27 '19 at 08:21
  • @sailfish009 Let's agree to disagree then. – Lightness Races in Orbit Aug 27 '19 at 10:27
  • 1
    This will work until str goes out of scope: ``` char *cstr = nullptr; { string str = "some string" ; cstr = &str[0]; } std::cout< – Cosmo May 28 '21 at 15:09
49

If I'd need a mutable raw copy of a c++'s string contents, then I'd do this:

std::string str = "string";
char* chr = strdup(str.c_str());

and later:

free(chr); 

So why don't I fiddle with std::vector or new[] like anyone else? Because when I need a mutable C-style raw char* string, then because I want to call C code which changes the string and C code deallocates stuff with free() and allocates with malloc() (strdup uses malloc). So if I pass my raw string to some function X written in C it might have a constraint on it's argument that it has to allocated on the heap (for example if the function might want to call realloc on the parameter). But it is highly unlikely that it would expect an argument allocated with (some user-redefined) new[]!

James McNellis
  • 348,265
  • 75
  • 913
  • 977
Nordic Mainframe
  • 28,058
  • 10
  • 66
  • 83
25

(This answer applies to C++98 only.)

Please, don't use a raw char*.

std::string str = "string";
std::vector<char> chars(str.c_str(), str.c_str() + str.size() + 1u);
// use &chars[0] as a char*
ildjarn
  • 62,044
  • 9
  • 127
  • 211
  • 1
    I actually just needed something like this earlier today. I was wondering, is it OK to say `vector(str.c_str(), str.c_str() + str.size() + 1)`, without assigning the char pointer to a temporary? – Kerrek SB Sep 08 '11 at 17:30
  • 1
    @Kerrek : Yes, the return value of `std::basic_string<>::c_str()` is valid until the `string` is changed or destroyed. This also implies that it returns the same value on subsequent calls as long as the `string` isn't modified. – ildjarn Sep 08 '11 at 17:32
  • I could (partially) agree with statement that std::vector is more "c++'ish" way. But can you explain why would you need speed/space overheads and **code complexity** for simple string manipulating/streaming? – friendzis Sep 08 '11 at 17:39
  • 2
    @friendzis : There is no speed or space overhead using `vector` in this way. And if one were to write **exception-safe** code without a RAII mechanism (i.e., using raw pointers), the code complexity would be much higher than this simple one-liner. – ildjarn Sep 08 '11 at 17:40
  • 8
    It's a myth that `vector` has a huge amount of overhead and complexity. If your requirement is that you have a **mutable** char array, then in fact a vector of chars is pretty much the ideal C++ wrapper. If your requirement actually just calls for a const-char pointer, then just use `c_str()` and you're done. – Kerrek SB Sep 08 '11 at 17:41
  • @friendzis: You don't. Using the original `std::string` is free. – Lightness Races in Orbit Sep 08 '11 at 17:42
  • 1
    @ildjarn isn't it true that you could just use `char* chars=&str[0];` instead of creating a `std::vector` as an intermediary. – bobobobo May 11 '13 at 21:42
  • @bobobobo : Only in C++11; prior to that, std::string's storage was not guaranteed to be contiguous. – ildjarn May 15 '13 at 19:13
  • 3
    @ildjarn: Actually, [it basically was](http://stackoverflow.com/a/2256521/560648). – Lightness Races in Orbit Jul 10 '13 at 10:00
19
  • If you just want a C-style string representing the same content:

    char const* ca = str.c_str();
    
  • If you want a C-style string with new contents, one way (given that you don't know the string size at compile-time) is dynamic allocation:

    char* ca = new char[str.size()+1];
    std::copy(str.begin(), str.end(), ca);
    ca[str.size()] = '\0';
    

    Don't forget to delete[] it later.

  • If you want a statically-allocated, limited-length array instead:

    size_t const MAX = 80; // maximum number of chars
    char ca[MAX] = {};
    std::copy(str.begin(), (str.size() >= MAX ? str.begin() + MAX : str.end()), ca);
    

std::string doesn't implicitly convert to these types for the simple reason that needing to do this is usually a design smell. Make sure that you really need it.

If you definitely need a char*, the best way is probably:

vector<char> v(str.begin(), str.end());
char* ca = &v[0]; // pointer to start of vector
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • 1
    Why `&str.front(), &str.back()` (which aren't present in C++03) instead of the more common `str.begin()` and `str.end()`? – Armen Tsirunyan Sep 08 '11 at 17:30
  • 1
    what about `str.begin()`, or even `std::begin(str)`, iterator-like? I don't believe `string` has any obligation to be in contiguous memory like `vector`, or has it? – xtofl Sep 08 '11 at 17:33
  • 1
    @xtofl: I already edited those in. And yes, as of C++11 there is an obligation; this was implicit in C++03. – Lightness Races in Orbit Sep 08 '11 at 17:34
  • @xtofl: Not in C++03. In C++11 we have that guarantee, along with the front() and back() functions, which were misused in the original answer anyway – Armen Tsirunyan Sep 08 '11 at 17:35
  • @Armen: Not "misused" in any way. We're on C++11 now, but I edited the answer anyway. And even in C++03, it is impossible for `std::string` to _not_ be contiguous; that this wasn't explicitly stated was a bug that was fixed in C++11's wording, but the fundamental semantics of the container didn't suddenly change, trust me. FYI, http://stackoverflow.com/questions/2256160/how-bad-is-code-using-stdbasic-stringt-as-a-contiguous-buffer. – Lightness Races in Orbit Sep 08 '11 at 17:37
  • 1
    @Tomalak: They were misused in that you needed `&back() + 1`, not `&back()` – Armen Tsirunyan Sep 08 '11 at 17:39
  • @Armen: Ah, well that's true. :) You didn't mention that before. This is still the most comprehensive answer, and as of 5 minutes ago it is correct.... – Lightness Races in Orbit Sep 08 '11 at 17:40
  • @Tomalak: I haven't downvoted you anyway, so I guess that doesn't matter :) – Armen Tsirunyan Sep 08 '11 at 17:40
  • @Armen: I guess not! I'd like to know who did, and ask them to reconsider. – Lightness Races in Orbit Sep 08 '11 at 17:41
  • What about the much shorter and, even more important, much more concise and direct `vector v(str.begin(), str.end())` than all this create resize and copy madness in your last example? – Christian Rau May 12 '13 at 01:05
  • in the last example char* will not be null terminated. You would need to push back a null character into the vector first. – Eric Roller Jun 29 '18 at 21:42
  • @EricRoller: If you need it to be null terminated yes – Lightness Races in Orbit Jun 30 '18 at 14:57
  • @LightnessRacesinOrbit speaking of contiguous memory, I'm not sure which C++03 rule would have required it. Perhaps there was a O(1) complexity requirement in there. But earlier than that I know it wasn't required because for funsies I had implemented a string-compatible class based on `std::deque` which converted to a `std::vector` only when `c_str()` was called. Then it deleted that vector whenever another write operation happened. It was a good debugging tool! Surprising how many people forget about pointer invalidation requirements! – Zan Lynx Dec 16 '20 at 17:58
13

This would be better as a comment on bobobobo's answer, but I don't have the rep for that. It accomplishes the same thing but with better practices.

Although the other answers are useful, if you ever need to convert std::string to char* explicitly without const, const_cast is your friend.

std::string str = "string";
char* chr = const_cast<char*>(str.c_str());

Note that this will not give you a copy of the data; it will give you a pointer to the string. Thus, if you modify an element of chr, you'll modify str.

hairlessbear
  • 341
  • 3
  • 11
  • 1
    There's probably a good reason the API designers made the returned pointer `const char*` and not just `char *`. `const` says "don't modify this object." When you use `const_cast`, you are saying "I know better, I really can modify the object." Or, you are saying "I __won't__ modify the object, I just need to pass it through this function that could have declared its input `const` but didn't. Although it seems safe to just throw away the `const`ness of the C-string, because we know it's mutable data underneath, you really _shouldn't_. You should avoid use of `const_cast` when you can. – bobobobo Feb 26 '22 at 03:30
  • Correct. Sometimes, you *have* to interface with an older API and don't have the luxury of rewriting the whole thing to be "clean and pure". Since on my VS the std::string.data () returns const char*, removing const-ness for few older methods (that have been production tested long before std::string was a thing) is definitely a right thing to do. For my situation. – 3D Coder Mar 23 '23 at 13:50
8

To obtain a const char * from an std::string use the c_str() member function :

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

To obtain a non-const char * from an std::string you can use the data() member function which returns a non-const pointer since C++17 :

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

For older versions of the language, you can use range construction to copy the string into a vector from which a non-const pointer can be obtained :

std::string str = "string";
std::vector<char> str_copy(str.c_str(), str.c_str() + str.size() + 1);
char* chr = str_copy.data();

But beware that this won't let you modify the string contained in str, only the copy's data can be changed this way. Note that it's specially important in older versions of the language to use c_str() here because back then std::string wasn't guaranteed to be null terminated until c_str() was called.

François Andrieux
  • 28,148
  • 6
  • 56
  • 87
8

Assuming you just need a C-style string to pass as input:

std::string str = "string";
const char* chr = str.c_str();
Mark B
  • 95,107
  • 10
  • 109
  • 188
5

Here is one more robust version from Protocol Buffer

char* string_as_array(string* str)
{
    return str->empty() ? NULL : &*str->begin();
}

// test codes
std::string mystr("you are here");
char* pstr = string_as_array(&mystr);
cout << pstr << endl; // you are here
zangw
  • 43,869
  • 19
  • 177
  • 214
  • +1 for checking that the string is empty. I would also add a check to make sure that the string is zero terminated: `if (str[str.length()-1] != 0) str.push_back(0)` – GaspardP Jan 24 '16 at 19:20
5

Conversion in OOP style

converter.hpp

class StringConverter {
    public: static char * strToChar(std::string str);
};

converter.cpp

char * StringConverter::strToChar(std::string str)
{
    return (char*)str.c_str();
}

usage

StringConverter::strToChar("converted string")
  • I like how the cast to char* eliminates the const from the output of c_str, I think the reason c_str returns const char* is to eliminate potential memory access issues, by providing a read only version of the thing. the OP wants to have a char*, but I think he might be better served by const char* output of c_str instead, since that is safer, and functions that take char* usually take const char* as well (assuming functions don't do anything like changing their inputs, which in general, they shouldn't). – Felipe Valdes Feb 21 '19 at 22:37
5

To be strictly pedantic, you cannot "convert a std::string into a char* or char[] data type."

As the other answers have shown, you can copy the content of the std::string to a char array, or make a const char* to the content of the std::string so that you can access it in a "C style".

If you're trying to change the content of the std::string, the std::string type has all of the methods to do anything you could possibly need to do to it.

If you're trying to pass it to some function which takes a char*, there's std::string::c_str().

Rob K
  • 8,757
  • 2
  • 32
  • 36
  • 1
    Incorrect. If you need to pass it to some older API function that requires char*, then *c_str()* won't work because that returns const char *. – 3D Coder Mar 23 '23 at 13:58
4

For completeness' sake, don't forget std::string::copy().

std::string str = "string";
const size_t MAX = 80;
char chrs[MAX];

str.copy(chrs, MAX);

std::string::copy() doesn't NUL terminate. If you need to ensure a NUL terminator for use in C string functions:

std::string str = "string";
const size_t MAX = 80;
char chrs[MAX];

memset(chrs, '\0', MAX);
str.copy(chrs, MAX-1);
Jeffery Thomas
  • 42,202
  • 8
  • 92
  • 117
4

You can make it using iterator.

std::string str = "string";
std::string::iterator p=str.begin();
char* chr = &(*p);

Good luck.

TS.PARK
  • 41
  • 1
4

A safe version of orlp's char* answer using unique_ptr:

std::string str = "string";
auto cstr = std::make_unique<char[]>(str.length() + 1);
strcpy(cstr.get(), str.c_str());
Enhex
  • 118
  • 7
3
char* result = strcpy((char*)malloc(str.length()+1), str.c_str());
Andrew Whitaker
  • 124,656
  • 32
  • 289
  • 307
cegprakash
  • 2,937
  • 33
  • 60
3

Alternatively , you can use vectors to get a writable char* as demonstrated below;

//this handles memory manipulations and is more convenient
string str;
vector <char> writable (str.begin (), str.end) ;
writable .push_back ('\0'); 
char* cstring = &writable[0] //or &*writable.begin () 

//Goodluck  
  • This will allocate new memory for the vector and then copy each character. std::string is already a container, you might as well push_back(0) to your string and do &str[0] – GaspardP Jan 24 '16 at 19:19
2

This will also work

std::string s;
std::cout<<"Enter the String";
std::getline(std::cin, s);
char *a=new char[s.size()+1];
a[s.size()]=0;
memcpy(a,s.c_str(),s.size());
std::cout<<a;  
Genocide_Hoax
  • 843
  • 2
  • 18
  • 42
0

No body ever mentioned sprintf?

std::string s;
char * c;
sprintf(c, "%s", s.c_str());
  • 1
    As-is, this will cause a segmentation fault. You need to allocate memory for the char array before calling sprintf, either on the stack or heap. Easiest thing to do would be to use the length of the string to dictate the size of the char array. – hairlessbear Sep 22 '20 at 05:52