What I'm wondering is why converting a string to a char* seems to make the new char* not equal to the literal string it came from.
If I have:
//raw versions of the string:
string s = "fun";
char* c = "fun";
char* s_convert = strdup(s.c_str()); //converting the string to char*
printf("(string) == 'fun' -> %d\n", (s == "fun"));
printf("(char*) == 'fun' -> %d\n", (c == "fun"));
printf("(char* convert) == 'fun' -> %d\n", (s_convert == "fun"));
printf("(string) == (char*) -> %d\n", (s == c)); //does new char* equal original string
produces:
(string) == 'fun' -> 1 //true
(char*) == 'fun' -> 1 //true
(char* convert) == 'fun' -> 0 //false
(string) == (char* convert) -> 1 //true
So the converted char* still equals the original string it came from. But for some reason char* s_convert
doesn't equal the literal string that it came from, although the original string s
does.
Why does this happen? And is there a better way I can convert a string to char* that won't cause this?
Let's go through your comparisons one by one:
printf("(string) == 'fun' -> %d\n", (s == "fun"));
Compares a std::string
variable with a string literal. Works as expected (i.e. really checks whether s
contains the string "fun"), because std::string
has an overloaded operator==
for that purpose.
printf("(char*) == 'fun' -> %d\n", (c == "fun"));
Compares the address stored in c
with the address of the string literal "fun". The result can be true or false. In your case, it is true, because the compiler optimized your code: It saw you use "fun" multiple times, and only stores the string literal once in memory, so the address will always be the same. If, e.g., c
had been assigned the literal "fun" in a different translation unit, the result would be false.
printf("(char* convert) == 'fun' -> %d\n", (s_convert == "fun"));
Compares the address stored in s_convert
to the address of the string literal "fun". As mentioned above, the string literal "fun" has a particular address chosen by your compiler. It will not compare equal to an explicitly copied string (it's irrelevant that it comes from the std::string
variable). The strdup
creates newly allocated memory, so the address will not compare equal to anything that existed in memory before.
printf("(string) == (char*) -> %d\n", (s == c)); //does new char* equal original string
Again, compares an std::string
to a C-style string. This really compares the strings and checks whether s
contains the null-terminated string stored at the address c
thanks to the overloaded operator==
of std::string
, so the result is true.
To summarize: The effects that you observe have nothing or little to do with the conversions between std::string
and null-terminated C-style strings. You just don't compare what you think you compare. Use strcmp
if you want to compare null-terminated "raw" strings, or use ==
when you compare std::string
to something else, and you will bet the results that you expect.