This declares array s
with an initializer:
char s[9] = "foobar"; //ok
But this is an invalid assignment expression with array s
on the left:
s = "foobar"; //doesn't work. Why?
Assignment expressions and declarations with initializers are not the same thing syntactically, although they both use an =
in their syntax.
The reason that the assignment to the array s
doesn't work is that the array decays to a pointer to its first element in the expression, so the assignment is equivalent to:
&(s[0]) = "foobar";
The assignment expression requires an lvalue on the left hand side, but the result of the &
address operator is not an lvalue. Although the array s
itself is an lvalue, the expression converts it to something that isn't an lvalue. Therefore, an array cannot be used on the left hand side of an assignment expression.
For the following:
char *s = "foobar"; //works
The string literal "foobar"
is stored as an anonymous array of char
and as an initializer it decays to a pointer to its first element. So the above is equivalent to:
char *s = &(("foobar")[0]); //works
The initializer has the same type as s
(char *
) so it is fine.
For the subsequent assignment:
s[1] = 'z'; //doesn't work
It is syntactically correct, but it violates a constraint, resulting in undefined behavior. The constraint that is being violated is that the anonymous arrays created by string literals are not modifiable. Assignment to an element of such an array is a modification and not allowed.
The subsequent assignment:
s = "foobar"; //unlike arrays, works here
is equivalent to:
s = &(("foobar")[0]); //unlike arrays, works here
It is assigning a char *
value to a variable of type char *
, so it is fine.
Contrast the following use of the initializer "foobar"
:
char *s = "foobar"; //works
with its use in the earlier declaration:
char s[9] = "foobar"; //ok
There is a special initialization rule that allows an array of char
to be initialized by a string literal optionally enclosed by braces. That initialization rule is being used to initialize char s[9]
.
The string literal used to initialize the array also creates an anonymous array of char
(at least notionally) but there is no way to access that anonymous array of char
, so it may get omitted from the output of the compiler. This is in contrast with the anonymous array of char
created by the string literal used to initialize char *s
which can be accessed via s
.