Это объявляет массив s
с инициализатором :
char s[9] = "foobar"; //ok
Но это недопустимое выражение присваивание с массивом s
слева:
s = "foobar"; //doesn't work. Why?
Выражения присваивания и объявления с инициализаторами синтаксически не одно и то же, хотя оба они используют =
в своем синтаксисе.
Причина, по которой присваивание массиву s
не работает, потому что массив распадается на указатель на свой первый элемент в выражении, поэтому присвоение эквивалентно:
&(s[0]) = "foobar";
Для выражения присваивания требуется lvalue на слева, но результат адресного оператора &
не является lvalue . Хотя сам массив s
является lvalue , выражение преобразует его во что-то, что не является lvalue . Следовательно, массив не может использоваться в левой части выражения присваивания.
Для следующего:
char *s = "foobar"; //works
Строковый литерал "foobar"
хранится как анонимный массив из char
и как инициализатор он распадается на указатель на свой первый элемент. Таким образом, приведенное выше эквивалентно:
char *s = &(("foobar")[0]); //works
Инициализатор имеет тот же тип, что и s
(char *
), поэтому все в порядке.
Для последующего присвоения:
s[1] = 'z'; //doesn't work
Это синтаксически правильно, но нарушает ограничение, приводя к неопределенному поведению . Ограничение, которое нарушается, состоит в том, что анонимные массивы, созданные строковыми литералами, не могут быть изменены . Присвоение элементу такого массива является модификацией и не допускается.
Последующее присвоение:
s = "foobar"; //unlike arrays, works here
эквивалентно:
s = &(("foobar")[0]); //unlike arrays, works here
Он присваивает значение char *
переменной типа char *
, так что это нормально.
Сравните следующее использование инициализатора "foobar"
:
char *s = "foobar"; //works
с его использованием в предыдущем объявлении:
char s[9] = "foobar"; //ok
Существует специальное правило инициализации, которое позволяет инициализировать массив char
строковым литералом, необязательно заключенным в фигурные скобки. Это правило инициализации используется для инициализации char s[9]
.
Строковый литерал, используемый для инициализации массива, также создает анонимный массив char
(по крайней мере, теоретически), но нет способа получить доступ к этому анонимному массиву of char
, поэтому он может быть исключен из вывода компилятора. Это контрастирует с анонимным массивом char
, созданным строковым литералом, используемым для инициализации char *s
, к которому можно получить доступ через s
.