Reputation: 43
Why does concatenation of a string and char in C++ return an empty string?
#include <iostream>
#include <string>
#include <assert.h>
int main() {
std::string s = "hello" + '4';
assert(s == ""); // why does s equal "" here?
}
Upvotes: 4
Views: 884
Reputation: 36616
The problem is in
std::string s = "hello" + '4';
which doesn't do anything remotely similar to appending a '4'
to a string. The actual behaviour is completely different from your expectations.
The string literal "hello"
is represented as an array of six const char
, with values 'h'
, 'e'
, 'l'
, 'l'
, 'o'
, and '\0'
. (the last character is known as a terminating null).
The value '4'
is a char
literal that (assuming your compiler uses ASCII or compatible character set, which is not guaranteed by the standard) has a numeric value of 52
.
The expression "hello" + '4'
is then seen by the compiler as "hello" + (char)52
. A char
is an integral type, so the net result of "hello" + '4'
is a pointer to the 53rd character of the string literal (which doesn't exist, since the string literal "hello"
is represented as an array of six elements).
So the result of "hello" + 4
is a pointer to a non-existent character.
The initialisation of s
in std::string s = "hello" + '4';
then passes that pointer to a constructor of std::string
. That constructor incorrectly ASSUMES it is passed the address of the first character of a null terminated string. That's not what is passed, so the result is undefined behaviour.
The assertion assert(s == "")
is not actually guaranteed to be true. It happens to be true, with your compiler and on your host system. But, because undefined behaviour has occurred, any result is possible (including, notionally, reinstalling your operating system in the process of initialising s
, and never reaching the assert()
).
To do what you intend, you need to force the compiler to work with std::string
objects in the right hand side (rather than pointer arithmetic). One option to do this is
std::string s = std::string("hello") + '4';
This works by constructing a std::string
from the literal "hello"
. std:string
supports an operator+()
that can be used to concatenate a char
to a std::string
(and returns a std::string
that is used to initialise s
).
The above works with all C++ standards (since 1998). A second alternative (since C++14) is to use the literal notation
std::string s = "hello"s + '4';
which works in essentially the same way (the s
in "hello"s
forms a literal of type std::string
rather than one represented as an array of char
, so the result of addition is also a std::string
).
The reason things are like this is historical.
Upvotes: 12
Reputation: 10165
In C++, end of a string is marked by zero byte.
Consider this code:
const char* str1 = "hello"; // Length is 6 bytes
const char* str2 = str1 + 52 // Numerical value of '4'
str2
is now a pointer past the end of the string. Accessing that memory location is undefined behavior, but if there happens to be 0 in that memory location, then str2
is equal to an empty string.
Upvotes: 3