What actually is done when `string::c_str()` is invoked? - c++

What actually is done when string::c_str() is invoked?
string::c_str() will allocate memory, copy the internal data of the string object and append a null-terminated character to the newly allocated memory?
or
Since string::c_str() must be O(1), so allocating memory and copying the string over is no longer allowed. In practice having the null-terminator there all the time is the only sane implementation.
Somebody in the comments of this answer of this question says that C++11 requires that std::string allocate an extra char for a trailing '\0'. So it seems the second option is possible.
And another person says that std::string operations - e.g. iteration, concatenation and element mutation - don't need the zero terminator. Unless you pass the string to a function expecting a zero terminated string, it can be omitted.
And more voice from an expert:
Why is it common for implementers to make .data() and .c_str() do the same thing?
Because it is more efficient to do so. The only way to make .data() return something that is not null terminated, would be to have .c_str() or .data() copy their internal buffer, or to just use 2 buffers. Having a single null terminated buffer always means that you can always use just one internal buffer when implementing std::string.
So I am really confused now, what actually is done when string::c_str() is invoked?
Update:
If c_str() is implemented as simply returning the pointer it's already allocated and managed.
A. Since c_str() must be null-terminated, the internal buffer needs to be always be null-terminated, even if for an empty std::string, e.g: std::string demo_str;, there should be a \0 in the internal memory of demo_str. Am I right?
B.What would happen when std::string::substr() is invoked? Automactically append a \0 to sub-string?

Since C++11, std::string::c_str() and std::string::data() are both required to return a pointer to the string's internal buffer. And since c_str() (but not data()) must be null-terminated, that effectively requires the internal buffer to always be null-terminated, though the null terminator is not counted by size()/length(), or returned by std::string iterators, etc.
Prior to C++11, the behavior of c_str() was technically implementation-specific, but most implementations I've ever seen worked this way, as it is the simplest and sanest way to implement it. C++11 just standardized the behavior that was already in wide use.
UPDATE
Since C++11, the buffer is always null-terminated, even for an empty string. However, that does not mean the buffer is required to be dynamically allocated when the string is empty. It could point to an SSO buffer, or even to a single static nul character. There is no guarantee that the pointer returned by c_str()/data() remains pointing at the same memory address as the content of the string changes.
std::string::substr() returns a new std::string with its own null-terminated buffer. The string being copied from is unaffected.

Here is an empirical "proof" that the complexity of .c_str() is o(1):
#include <stdio.h>
#include <string>
using namespace std;
int main(int argc, char **argv)
{
std::string x(5000000, 'b'); // <--- single time allocation
// std::string x(5, 'b'); // <--- compare to a much shorter string
for (unsigned int i=0;i<1000000;i++)
{
const char *y = x.c_str(); // <--- copy entire content ?
}
}
compiled with -O0 to avoid optimizing out anything
timing 2 versions: I get identical performance
this is an empirical "proof" that (at least my machine's implementation)
extracts the internal representation of a null terminated string
doesn't copy content every time .c_str() is called.

There's a lot of great answers and comments already provided. But to demonstrate that std::string is typically backed by a null terminated string, I've provided a simple, yet naive implementation. It's not complete, doesn't do error checking, and is certainly not optimized. But it's complete enough to show you how a string class is typically implemented with a null terminated buffer as a member variable.
class string
{
public:
string()
{
assign("", 0);
}
string(const char* s)
{
assign(s, strlen(s));
}
string(const char* s, size_t len)
{
assign(s, len);
}
string(const string& s)
{
assign(s._ptr, s._len);
}
~string()
{
delete [] _ptr;
}
string& operator=(const string& s)
{
const char* oldptr = _ptr;
assign(s._ptr, s._len);
delete [] oldptr;
}
const char* data()
{
return _ptr;
}
const char* c_str()
{
return _ptr;
}
size_t length()
{
return _len;
}
// substr always returns a new string
std::string substr(size_t pos, size_t count)
{
std::string s(_ptr+pos, count);
return s;
}
private:
char* _ptr;
size_t _len;
void assign(const char* ptr, size_t len)
{
_len = len;
_ptr = new char[_len+1]; // +1 for null termination
memcpy(_ptr, ptr, len);
_ptr[_len] = '\0'; // always null terminate
}
};

What would happen when std::string::substr() is invoked? Automactically append a \0 to sub-string?
Yes because std::string holds modifiable values. If you want something like std::string::substr() that does not allocate the respective content, C++17 has std::string_view for this purpose:
std::string returns_str();
auto v = std::string_view{returns_str()}.substr(3, 10);

Related

How do you convert string to c_str() in this situation? [duplicate]

How can I convert an std::string to a char* or a const char*?
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.
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] 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']).
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 strings).
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 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
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.
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 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()].
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
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.
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.
char* result = strcpy((char*)malloc(str.length()+1), str.c_str());
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;
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.
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 a char* or a const 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.
A read-only const char* C-string of the underlying buffer: use the same thing as above (const char* const_c_str1 = &str[i];), or const 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:
char* 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`
What if you have a pointer to a std::string? If you have a ptr to a std::string, it must be dereferenced first with *pstr before you can index into it as an array with the operator[] 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 a char* 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's operator*() dereference method to obtain the iterator's char value_type, and then take the address of that to obtain a char*. 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
https://en.cppreference.com/w/cpp/string/basic_string/data
https://en.cppreference.com/w/cpp/string/basic_string/c_str
https://en.cppreference.com/w/cpp/string/basic_string/clear
Try this
std::string s(reinterpret_cast<const char *>(Data), Size);

string.c_str() is const? [duplicate]

This question already has answers here:
Can I get a non-const C string back from a C++ string?
(14 answers)
Closed 5 years ago.
I have a function in a library that takes in a char* and modifies the data.
I tried to give it the c_str() but c++ docs say it returns a const char*.
What can I do other than newing a char array and copying it into that?
You can use &str[0] or &*str.begin() as long as:
you preallocate explicitly all the space needed for the function with resize();
the function does not try to exceed the preallocated buffer size (you should pass str.size() as the argument for the buffer size);
when the function returns, you explicitly trim the string at the first \0 character you find, otherwise str.size() will return the "preallocated size" instead of the "logical" string size.
Notice: this is guaranteed to work in C++11 (where strings are guaranteed to be contiguous), but not in previous revisions of the standard; still, no implementation of the standard library that I know of ever did implement std::basic_string with noncontiguous storage.
Still, if you want to go safe, use std::vector<char> (guaranteed to be contiguous since C++03); initialize with whatever you want (you can copy its data from a string using the constructor that takes two iterators, adding a null character in the end), resize it as you would do with std::string and copy it back to a string stopping at the first \0 character.
Nothing.
Because std::string manages itself its contents, you can't have write access to the string's underlying data. That's undefined behavior.
However, creating and copying a char array is not hard:
std::string original("text");
std::vector<char> char_array(original.begin(), original.end());
char_array.push_back(0);
some_function(&char_array[0]);
If you know that the function will not modify beyond str.size() you can obtain a pointer in one of different ways:
void f( char* p, size_t s ); // update s characters in p
int main() {
std::string s=...;
f( &s[0], s.size() );
f( &s.front(), s.size() );
}
Note, this is guaranteed in C++11, but not in previous versions of the standard where it allowed for rope implementations (i.e. non-contiguous memory)
If your implementation will not try to increase the length of the string then:
C++11:
std::string data = "This is my string.";
func(&*data.begin());
C++03:
std::string data = "This is my string.";
std::vector<char> arr(data.begin(), data.end());
func(&arr[0]);
Here's a class that will generate a temporary buffer and automatically copy it to the string when it's destroyed.
class StringBuffer
{
public:
StringBuffer(std::string & str) : m_str(str)
{
m_buffer.push_back(0);
}
~StringBuffer()
{
m_str = &m_buffer[0];
}
char * Size(int maxlength)
{
m_buffer.resize(maxlength + 1, 0);
return &m_buffer[0];
}
private:
std::string & m_str;
std::vector<char> m_buffer;
};
And here's how you would use it:
// this is from a crusty old API that can't be changed
void GetString(char * str, int maxlength);
std::string mystring;
GetString(StringBuffer(mystring).Size(MAXLEN), MAXLEN);
If you think you've seen this code before, it's because I copied it from a question I wrote: Guaranteed lifetime of temporary in C++?

std::string.c_str() has different value than std::string?

I have been working with C++ strings and trying to load char * strings into std::string by using C functions such as strcpy(). Since strcpy() takes char * as a parameter, I have to cast it which goes something like this:
std::string destination;
unsigned char *source;
strcpy((char*)destination.c_str(), (char*)source);
The code works fine and when I run the program in a debugger, the value of *source is stored in destination, but for some odd reason it won't print out with the statement
std::cout << destination;
I noticed that if I use
std::cout << destination.c_str();
The value prints out correctly and all is well. Why does this happen? Is there a better method of copying an unsigned char* or char* into a std::string (stringstreams?) This seems to only happen when I specify the string as foo.c_str() in a copying operation.
Edit: To answer the question "why would you do this?", I am using strcpy() as a plain example. There are other times that it's more complex than assignment. For example, having to copy only X amount of string A into string B using strncpy() or passing a std::string to a function from a C library that takes a char * as a parameter for a buffer.
Here's what you want
std::string destination = source;
What you're doing is wrong on so many levels... you're writing over the inner representation of a std::string... I mean... not cool man... it's much more complex than that, arrays being resized, read-only memory... the works.
This is not a good idea at all for two reasons:
destination.c_str() is a const pointer and casting away it's const and writing to it is undefined behavior.
You haven't set the size of the string, meaning that it won't even necessealy have a large enough buffer to hold the string which is likely to cause an access violation.
std::string has a constructor which allows it to be constructed from a char* so simply write:
std::string destination = source
Well what you are doing is undefined behavior. Your c_str() returns a const char * and is not meant to be assigned to. Why not use the defined constructor or assignment operator.
std::string defines an implicit conversion from const char* to std::string... so use that.
You decided to cast away an error as c_str() returns a const char*, i.e., it does not allow for writing to its underlying buffer. You did everything you could to get around that and it didn't work (you shouldn't be surprised at this).
c_str() returns a const char* for good reason. You have no idea if this pointer points to the string's underlying buffer. You have no idea if this pointer points to a memory block large enough to hold your new string. The library is using its interface to tell you exactly how the return value of c_str() should be used and you're ignoring that completely.
Do not do what you are doing!!!
I repeat!
DO NOT DO WHAT YOU ARE DOING!!!
That it seems to sort of work when you do some weird things is a consequence of how the string class was implemented. You are almost certainly writing in memory you shouldn't be and a bunch of other bogus stuff.
When you need to interact with a C function that writes to a buffer there's two basic methods:
std::string read_from_sock(int sock) {
char buffer[1024] = "";
int recv = read(sock, buffer, 1024);
if (recv > 0) {
return std::string(buffer, buffer + recv);
}
return std::string();
}
Or you might try the peek method:
std::string read_from_sock(int sock) {
int recv = read(sock, 0, 0, MSG_PEEK);
if (recv > 0) {
std::vector<char> buf(recv);
recv = read(sock, &buf[0], recv, 0);
return std::string(buf.begin(), buf.end());
}
return std::string();
}
Of course, these are not very robust versions...but they illustrate the point.
First you should note that the value returned by c_str is a const char* and must not be modified. Actually it even does not have to point to the internal buffer of string.
In response to your edit:
having to copy only X amount of string A into string B using strncpy()
If string A is a char array, and string B is std::string, and strlen(A) >= X, then you can do this:
B.assign(A, A + X);
passing a std::string to a function from a C library that takes a char
* as a parameter for a buffer
If the parameter is actually const char *, you can use c_str() for that. But if it is just plain char *, and you are using a C++11 compliant compiler, then you can do the following:
c_function(&B[0]);
However, you need to ensure that there is room in the string for the data(same as if you were using a plain c-string), which you can do with a call to the resize() function. If the function writes an unspecified amount of characters to the string as a null-terminated c-string, then you will probably want to truncate the string afterward, like this:
B.resize(B.find('\0'));
The reason you can safely do this in a C++11 compiler and not a C++03 compiler is that in C++03, strings were not guaranteed by the standard to be contiguous, but in C++11, they are. If you want the guarantee in C++03, then you can use std::vector<char> instead.

Can I get a non-const C string back from a C++ string?

Const-correctness in C++ is still giving me headaches. In working with some old C code, I find myself needing to assign turn a C++ string object into a C string and assign it to a variable. However, the variable is a char * and c_str() returns a const char []. Is there a good way to get around this without having to roll my own function to do it?
edit: I am also trying to avoid calling new. I will gladly trade slightly more complicated code for less memory leaks.
C++17 and newer:
foo(s.data(), s.size());
C++11, C++14:
foo(&s[0], s.size());
However this needs a note of caution: The result of &s[0]/s.data()/s.c_str() is only guaranteed to be valid until any member function is invoked that might change the string. So you should not store the result of these operations anywhere. The safest is to be done with them at the end of the full expression, as my examples do.
Pre C++-11 answer:
Since for to me inexplicable reasons nobody answered this the way I do now, and since other questions are now being closed pointing to this one, I'll add this here, even though coming a year too late will mean that it hangs at the very bottom of the pile...
With C++03, std::string isn't guaranteed to store its characters in a contiguous piece of memory, and the result of c_str() doesn't need to point to the string's internal buffer, so the only way guaranteed to work is this:
std::vector<char> buffer(s.begin(), s.end());
foo(&buffer[0], buffer.size());
s.assign(buffer.begin(), buffer.end());
This is no longer true in C++11.
There is an important distinction you need to make here: is the char* to which you wish to assign this "morally constant"? That is, is casting away const-ness just a technicality, and you really will still treat the string as a const? In that case, you can use a cast - either C-style or a C++-style const_cast. As long as you (and anyone else who ever maintains this code) have the discipline to treat that char* as a const char*, you'll be fine, but the compiler will no longer be watching your back, so if you ever treat it as a non-const you may be modifying a buffer that something else in your code relies upon.
If your char* is going to be treated as non-const, and you intend to modify what it points to, you must copy the returned string, not cast away its const-ness.
I guess there is always strcpy.
Or use char* strings in the parts of your C++ code that must interface with the old stuff.
Or refactor the existing code to compile with the C++ compiler and then to use std:string.
There's always const_cast...
std::string s("hello world");
char *p = const_cast<char *>(s.c_str());
Of course, that's basically subverting the type system, but sometimes it's necessary when integrating with older code.
If you can afford extra allocation, instead of a recommended strcpy I would consider using std::vector<char> like this:
// suppose you have your string:
std::string some_string("hello world");
// you can make a vector from it like this:
std::vector<char> some_buffer(some_string.begin(), some_string.end());
// suppose your C function is declared like this:
// some_c_function(char *buffer);
// you can just pass this vector to it like this:
some_c_function(&some_buffer[0]);
// if that function wants a buffer size as well,
// just give it some_buffer.size()
To me this is a bit more of a C++ way than strcpy. Take a look at Meyers' Effective STL Item 16 for a much nicer explanation than I could ever provide.
You can use the copy method:
len = myStr.copy(cStr, myStr.length());
cStr[len] = '\0';
Where myStr is your C++ string and cStr a char * with at least myStr.length()+1 size. Also, len is of type size_t and is needed, because copy doesn't null-terminate cStr.
Just use const_cast<char*>(str.data())
Do not feel bad or weird about it, it's perfectly good style to do this.
It's guaranteed to work in C++11. The fact that it's const qualified at all is arguably a mistake by the original standard before it; in C++03 it was possible to implement string as a discontinuous list of memory, but no one ever did it. There is not a compiler on earth that implements string as anything other than a contiguous block of memory, so feel free to treat it as such with complete confidence.
If you know that the std::string is not going to change, a C-style cast will work.
std::string s("hello");
char *p = (char *)s.c_str();
Of course, p is pointing to some buffer managed by the std::string. If the std::string goes out of scope or the buffer is changed (i.e., written to), p will probably be invalid.
The safest thing to do would be to copy the string if refactoring the code is out of the question.
std::string vString;
vString.resize(256); // allocate some space, up to you
char* vStringPtr(&vString.front());
// assign the value to the string (by using a function that copies the value).
// don't exceed vString.size() here!
// now make sure you erase the extra capacity after the first encountered \0.
vString.erase(std::find(vString.begin(), vString.end(), 0), vString.end());
// and here you have the C++ string with the proper value and bounds.
This is how you turn a C++ string to a C string. But make sure you know what you're doing, as it's really easy to step out of bounds using raw string functions. There are moments when this is necessary.
If c_str() is returning to you a copy of the string object internal buffer, you can just use const_cast<>.
However, if c_str() is giving you direct access tot he string object internal buffer, make an explicit copy, instead of removing the const.
Since c_str() gives you direct const access to the data structure, you probably shouldn't cast it. The simplest way to do it without having to preallocate a buffer is to just use strdup.
char* tmpptr;
tmpptr = strdup(myStringVar.c_str();
oldfunction(tmpptr);
free tmpptr;
It's quick, easy, and correct.
In CPP, if you want a char * from a string.c_str()
(to give it for example to a function that only takes a char *),
you can cast it to char * directly to lose the const from .c_str()
Example:
launchGame((char *) string.c_str());
C++17 adds a char* string::data() noexcept overload. So if your string object isn't const, the pointer returned by data() isn't either and you can use that.
Is it really that difficult to do yourself?
#include <string>
#include <cstring>
char *convert(std::string str)
{
size_t len = str.length();
char *buf = new char[len + 1];
memcpy(buf, str.data(), len);
buf[len] = '\0';
return buf;
}
char *convert(std::string str, char *buf, size_t len)
{
memcpy(buf, str.data(), len - 1);
buf[len - 1] = '\0';
return buf;
}
// A crazy template solution to avoid passing in the array length
// but loses the ability to pass in a dynamically allocated buffer
template <size_t len>
char *convert(std::string str, char (&buf)[len])
{
memcpy(buf, str.data(), len - 1);
buf[len - 1] = '\0';
return buf;
}
Usage:
std::string str = "Hello";
// Use buffer we've allocated
char buf[10];
convert(str, buf);
// Use buffer allocated for us
char *buf = convert(str);
delete [] buf;
// Use dynamic buffer of known length
buf = new char[10];
convert(str, buf, 10);
delete [] buf;

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

How can I convert an std::string to a char* or a const char*?
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.
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] 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']).
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 strings).
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 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
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.
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 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()].
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
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.
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.
char* result = strcpy((char*)malloc(str.length()+1), str.c_str());
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;
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.
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 a char* or a const 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.
A read-only const char* C-string of the underlying buffer: use the same thing as above (const char* const_c_str1 = &str[i];), or const 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:
char* 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`
What if you have a pointer to a std::string? If you have a ptr to a std::string, it must be dereferenced first with *pstr before you can index into it as an array with the operator[] 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 a char* 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's operator*() dereference method to obtain the iterator's char value_type, and then take the address of that to obtain a char*. 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
https://en.cppreference.com/w/cpp/string/basic_string/data
https://en.cppreference.com/w/cpp/string/basic_string/c_str
https://en.cppreference.com/w/cpp/string/basic_string/clear
Try this
std::string s(reinterpret_cast<const char *>(Data), Size);