In the example
char* a = "abc";
the token "abc"
produces a literal object in the program image, and denotes an expression which yields that object's address.
In the example
char a[] = "abc";
The token "abc"
is serves as an array initializer, and doesn't denote a literal object. It is equivalent to:
char a[] = { 'a', 'b', 'c', 0 };
The individual character values of "abc"
are literal data is recorded somewhere and somehow in the program image, but they are not accessible as a string literal object.
The array a
isn't a literal, needless to say. Modifying a
doesn't constitute modifying a literal, because it isn't one.
Regarding the remark:
That would not work since string literal is read-only.
That isn't accurate. The ISO C standard (no version of it to date) doesn't specify any requirements for what happens if a program tries to modify a string literal. It is undefined behavior. If your implementation stops the program with some diagnostic message, that's because of undefined behavior, not because it is required.
C implementations are not required to support string literal modification, which has the benefits like:
standard-conforming C programs can be translated into images that can be be burned into ROM chips, such that their string literals are accessed directly from that ROM image without having to be copied into RAM on start-up.
compilers can condense the storage for string literals by taking advantage of situations when one literal is a suffix of another. The expression "string" + 2 == "ring"
can yield true. Since a strictly conforming program will not do something like "ring"[0] = 'w'
, due to that being undefined behavior, such a program will thereby avoid falling victim to the surprise of "string"
unexpectedly turning into "stwing"
.