JMM
JMM

Reputation: 43

Why does concatenation of a string an char in C++ return an empty string?

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

Answers (2)

Peter
Peter

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

VLL
VLL

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

Related Questions