Does std :: end have to specify a null terminator for strings?
I noticed that I std::end
will always refer to the null terminator when it comes to strings or character arrays. I thought I std::end
should have been referring to the end of the array following the last valid element. Is it '\0'
not a valid item? This is part of the array. Here are some tests that return true:
#include <iostream>
int main()
{
std::string s("hello!");
auto s_end = *(s.data() + s.size() + 1);
std::cout << std::boolalpha << (*std::end(s) == s_end) << "\n"
<< (s_end == '\0') << "\n";
char buf[6 + 1];
std::copy(s.begin(), s.end(), &buf[0]);
auto buf_end = *(buf + s.size() + 1);
std::cout << (*std::end(buf) == buf_end) << "\n"
<< (buf_end == '\0') << "\n";
char test[3] = {'h', '\0', 'e'};
std::cout << (*std::end(test) == '\0');
return 0;
}
source to share
For a character array, std::end
indeed specifies the last character in the array. For
char test[3] = {'h', '\0', 'e'};
pointer std::end(test)
matches test + 3
. A dereference expression is the same as an evaluation test[3]
. This behavior is undefined. In your particular case, it happened that he gave '\0'
. But in general it can lead to a different value, or to a failure, or something else entirely. std::end(test)
points not to the character '\0'
at index 1 in the array test
!
Note that it std::end
behaves evenly across all arrays. That is, if we have an array T a[N]
, then it std::end(a)
returns a + N
, regardless of whether T
char
or what the content is a
. It doesn't give you the end of the line; it gives you the end of the array. Again, the return value is always a + N
. NO EXCEPTIONS!
A std::string
terminating null character exists for, but it is not considered part of the string. (Unlike other characters, you are not allowed to change it, when the pain is undefined.) If you have
std::string s("hello");
it s[5]
will have a null character value, but as I said, it is not considered part of the string: s
it is considered to have five characters, not six. It's best to think of it std::string
as not null terminated at all. The last character s[4]
that matters 'o'
, a std::end(s)
is the iterator passed only std::begin(s) + 4
, that is std::begin(s) + 5
.
This is a little more subtle than it looks, as the standard does not technically guarantee that std::end(s)
it makes no difference at all, so you cannot say that it points to a trailing null. In practice, it points to a trailing null, but dereferences it is still undefined.
source to share