The reason this is so perplexing might be, “But what happens if I set str1[1] = 'u';
?” Since it’s implementation-defined whether str1 == str3
(and whether the address of the literal "world!"
is the address of "hello, world!"
plus 7), does that aldo turn str3
into a German prince?
The answer is: maybe. Or maybe it only changes str1
, or maybe it silently fails to change either, or maybe it crashes the program because you wrote to read-only memory, or maybe it causes some other subtle bug because it re-used those bytes for yet another purpose, or something else entirely.
The fact that you can even assign a string literal to a char*
at all, instead of needing to use const char*
, is basically cruft for the sake of decades-old legacy code. The first versions of C did not have const
. Some existing compilers let programs change string constants, and some didn’t. When the standards committee decided to add the const
keyword from C++ to C, they weren’t willing to break all that code, so they gave compilers permission to do basically anything when a program changes a string literal.
The practical implication of this is: never assign a string literal to a char*
that isn’t const
. And never assume that string constants do or do not overlap (unless you guarantee this with restrict
). That type of code has been obsolete since 1989, and just lets you shoot yourself in the foot. If you want a pointer to a string literal (which might or might not share memory with other constants), store it in a const char*
or, better yet, const char* const
. That warns you if you try to modify it. If you want an array of char
that can be modified (and is guaranteed not to alias any other variable), store it in a char[]
.
If you think you want to compare strings by their addresses, what you really want is either a hash value or a unique handle.