std::string difference in output when use c+=expression and c=c+expression
Given c+="#"+a[i];
, "#"+a[i]
is evaluated at first. "#"
is of type const char[2]
and could decay to pointer as const char*
, a[i]
is of type char
which is an integral type, then "#"+a[i]
just performs pointer arithmetic and won't concatenate strings as you expected. (And the result of pointer arithmetic might get out of the bound of the array and then leads to UB.)
On the other hand, in c=c+"#"+a[i];
, c+"#"
is evaluated at first, it appends "#"
on c
and returns a new std::string
(by operator+
for std::string
), on which a[i]
is appended and the result is assigned to c
.
But a += b is equivalent to a = a + b
If you put b
in integration, i.e. add parentheses as ("#"+a[i])
, then both c+=("#"+a[i]);
and c=c+("#"+a[i]);
yields the same result, even it's not what you expected.
With c=c+"#"+a[i]
all the operators in the right of the expression are the same so the expression is processed from left to right, the first element is a std::string
to which a const char*
is added creating a new std::string
then add a char
creating another std::string
which is finally assigned to c
.
With c+="#"+a[i]
the right of the expression starts with a const char*
to which you add a char
, this invokes pointer arithmetic producing an invalid address which is then appended to the string c
which is undefined behaviour. To fix it you have to force the first argument to be a std::string
: c+=std::string("#")+a[i]
Fundamentally because C++ started its life as "C with classes". Over the years a bunch of new functionality was added and some rules were tightened but C++'s background as an extended C is still clearly visible. In particular.
- The language doesn't make a proper distinction between characters and integers. Type "char" is simply the smallest integer type in the language.
- A regular string literal evaluates to a pointer the first character in a constant array containing a null-terminated string, not to a modern string type.
std::string (strictly the std::basic_string template but lets ignore that detail for now) does it's best to help you. It defines sensible overloads for (again ignoring the detail of rvalue references).
- std::string + std::string
- std::string + char*
- std::string + char
- char* + std::string
- char + std::string
But it can't do anything about operators where neither argument is a std::string. Those work in C++ in the same way they work in C.
- char* + char* --> error
- char + char --> integer addition
- char* + char --> pointer arithmetic
- char + char* --> pointer arithmetic
The result of this is that order of operations becomes very important.
c=c+"#"+a[i];
is equivalent to c=((c+"#")+a[i]);
. This works fine, in the innermost operation one argument is a std::string so the overloaded operators do the right thing and concatenate the arguments to produce another std::string. The same applies when we concatenate the result of that innermost operation to the a[i]
c+="#"+a[i];
is functionally equivalent* to c=(c+("#"+a[i]));
so now we are trying to use the + operator between a string literal which evaluates to a char * and an operation which evaluates to a char. So we add the character code for the character at a[i] to the pointer to the string "#".
since "#" is a rather short string, this will almost certainly result in a pointer that is past the end of the string. This is undefined behaviour by the language spec.
I would guess that "!boxboxbox" is a sandbox error from onlinegdb. It has detected your code doing something it shouldn't and refused to let it go ahead.
Many compilers/linkers put different string data together, so on a regular compiler displaying (part of) another string from the executable (or libraries that it uses) is a likely outcome of running off the end of a string.
C++11 did add support for std::string literals, so one fix could be to add
using namespace std::string_literals;
Then change "#"
to "#"s
* Note that in general with overloaded operators in c++ "+" and "+=" are separate operators and nothing forces the implementer of the class to make them functionally equivalent. Sane class designers generally will though.
Also += may be more efficient as it may be able to perform the concatenation in-place rather than creating a new string.