Consider the following code:
const char foo[] = "lorem ipsum"; // foo is an array of 12 characters
const auto length = strlen(foo); // length is 11
string bar(length, '\0'); // bar was constructed with string(11, '\0')
strncpy(data(bar), foo, length);
cout << data(bar) << endl;
My understanding is that string
s are always allocated with a hidden null element. If this is the case then bar
really allocates 12 characters, with the 12th being a hidden '\0'
and this is perfectly safe... If I'm wrong on that then the cout
will result in undefined behavior because there isn't a null terminator.
Can someone confirm for me? Is this legal?
There have been a lot of questions about why to use strncpy
instead of just using the string(const char*, const size_t)
constructor. My intent has been to make my toy code close to my actual code which contains a vsnprintf
. Unfortunately even after getting excellent answers here I've found that vsnprintf
doesn't behave the same as strncpy
, and I've asked a follow up question here: Why is vsnprintf Not Writing the Same Number of Characters as strncpy Would?
This is safe, as long as you copy [0, size())
characters into the string . Per [basic.string]/3
In all cases,
[data(), data() + size()]
is a valid range,data() + size()
points at an object with valuecharT()
(a “null terminator”), andsize() <= capacity()
istrue
.
So string bar(length, '\0')
gives you a string with a size()
of 11, with an immutable null terminator at the end (for a total of 12 characters in actual size). As long as you do not overwrite that null terminator, or try to write past it, you're okay.