Why does name
misbehave in the following C++ code?
string name = "ab"+'c';
How would the equivalent code behave in Java/C#?
Why does name
misbehave in the following C++ code?
string name = "ab"+'c';
How would the equivalent code behave in Java/C#?
You can concatenate strings and chars in C# - it's not as strict as C++ I guess.
This works just fine in C#:
string test = "foo" + 'b';
Try
std::string name = "ab" "c";
or
std::string name = std::string("ab") + c;
In C++, "ab" is not a std::string
, but rather a pointer to a string of chars. When you add an integral value to a pointer, you get a new pointer that points farther down the string:
char *foo = "012345678910121416182022242628303234";
std::string name = foo + ' ';
name
gets set to "3234", since the integer value of ' ' is 32 and 32 characters past the begining of foo is four characters before the end of the string. If the string was shorter, you'd be trying to access something in undefined memory territory.
The solution to this is to make a std:string out of the character array. std:strings let you append characters to them as expected:
std::string foo = "012345678910121416182022242628303234";
std::string name = foo + ' ';
name
gets set to "012345678910121416182022242628303234 "
Java:
public class Main
{
public static void main(String[] args)
{
System.out.println("AB" + 'c');
}
}
Output is:
ABc
Edit:
Actually the compiler hard codes the String ABc...
If you do "AB" + argv[0].charAt(0); to make it use a variable then the compiler does this (basically):
StringBuilder b = new StringBuilder;
b.append("AB");
b.append(argv[0].charAt(0));
System.out.println(b.toString());
In C++, the compiler is looking for a function with this prototype:
T operator+ (const char*, char);
Since there isn't one, it can't figure out what T is and can't resolve the operator<<
call, so it falls back to the only solution left: pointer addition. There is no problem with catenating to a string as in Josh's answer, because a function exists for it.
The problem is that "ab" is not a C++ std::string
, but a const char[3]
.
So the + operator it's looking for is operator+ (const char[3], char)
. That doesn't exist, so the compiler tries letting the array decay to a pointer, so it looks for operator+ (const char[3], char)
. That exists, so the compiler picks that, but it does the wrong thing. Adding an integral value (the char) to a pointer (the const char*) is a common enough operation, and obviously, that's what this operator+ does. The key to understanding this is to realize that the first argument is 1) an array, and 2) a pointer whenever array doesn't make sense. It was used as a string in C as well, yes, but it is not a string. It is a pointer (or occasionally, an array)
There is a operator+ (const std::string&, char)
which concatenates, but the compiler won't even look for it, because the first argument isn't a std::string.
So a solution is to manually create the string:
string name = std::string("ab")+'c';
Now the compiler can figure out the correct operator+ to call.
A C++ compiler doesn't automatically concatenate string-literals with character-literals. But it will concatenate string-literals with each other. The syntax is like this:
const char * cs = "ab" "c"; // append string-literals
As others have mentioned, string
is not a built-in C++ language type. But there is a string
type in the C++ Standard Library. Here are some usage examples:
#include <string>
const char * cs = "ab" "c";
std::string s1( cs );
std::string s2( "ab" "c" );
std::string s3 = "ab" "c";
Given the C++ code:
std::string name = "ab"+'c';
The equivalent in Java is:
String name = "ab".substring('c');
Both promote char to int. Of course in Java it gets range checked and hence throws an exception. In C++ you just get undefined behaviour (or somesuch).
Well, what I usually would do in C++ is
string name = string("ab") +'c';
Remember that the literal "ab" is not of type string. What you were doing was hoping that there was no "+" that works between char arrays and chars, and then hoping the compiler could somehow notice that you really want the result to be a std::string, and then go parse your expression on the right hand side for some combination of implicit conversions that could combine with the operator(s) to produce a result of that type. Seems like a rather tall order to me.
Regardless, it doesn't matter. You see, in C the only difference between an array and a pointer is how their memory is allocated. Once you have one, you essentially have an "array/pointer thing". Thus "+" is an operator defined on all arrays and pointers, which takes another argument of any integer type and does pointer math, returning a pointer to that many elements past that spot. Also, in C "char" is really just another kind of integer type. These C design decisions were both useful hacks, but as often happens with hacks, they combine with intuitively unexpected results. So all "ab" + 'c' does for you is return an address 99 bytes past wherever the "ab" literal happens to be stored in memory.
Sometimes you can rely on implicit conversions, but you really have to be prepared to help your compiler out a bit at other times.