In the below code
#include<iostream>
#include<string>
using namespace std;
int main()
{
string a,c="!";
cin>>a;
int l=a.size();
for(int i=0;i<l;i++)
{
c=c+"#"+a[i];
}
cout<<c;
}
If I replace c=c+"#"+a[i]
with c+="#"+a[i]
i get unexpected output.
Output in the second case is !boxboxboxbox irrespective of input on https://www.onlinegdb.com/ .
On "dev c++" the output is -
But a += b is equivalent to a = a + b . Then what is the reason for the difference in output?
std::string is compatible with STL algorithms and other containers. C strings are not char * or const char * ; they are just null-terminated character arrays. Even string literals are just character arrays.
Neither C or C++ have a default built-in string type. C-strings are simply implemented as a char array which is terminated by a null character (aka 0 ). This last part of the definition is important: all C-strings are char arrays, but not all char arrays are c-strings.
In C++, a string is typically just an array of (or a pointer to) chars, terminated with a NULL (\0) character. You can process a string by indexing also as you would process any array. But in Java , a strings are not arrays. Java strings are objects of type java.
There is no string type in C . You have to use char arrays.
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.
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).
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With