В C почему законно делать
char * str = "Hello";
но незаконно делать
int * arr = {0,1,2,3};
В C почему законно делать
char * str = "Hello";
но незаконно делать
int * arr = {0,1,2,3};
Я предполагаю, что как инициализаторы работают на C. Однако вы можете сделать:
int *v = (int[]){1, 2, 3}; /* C99. */
Что касается C89:
"A string"
, если используется внешняя инициализация массива char
, является строковым литералом; в стандарте говорится, что когда вы используете строковый литерал, как если бы вы создали глобальный массив char
, инициализированный этим значением, и написали его имя вместо литерального (там также дополнительное ограничение, которое любая попытка изменить строковый литерал приводит к undefined). В коде вы инициализируете char *
строковым литералом, который распадается на указатель char
, и все работает нормально.
Однако, если вы используете строковый литерал для инициализации массива char
, в действие действуют несколько магических правил, поэтому он больше не "как будто массив... и т.д." (который не будет работать в инициализации массива), но это просто хороший способ рассказать компилятору, как должен быть инициализирован массив.
Способ инициализации массивов {1, 2, 3}
сохраняет только эту семантику: это только для инициализации массива, это не "литерал массива".
В случае:
char * str = "Hello";
"Hello"
- строковый литерал. Он загружается в память (но часто только для чтения) при запуске программы и имеет адрес памяти, который может быть назначен указателю, например char *str
. Однако строковые литералы - это исключение.
С
int * arr = {0,1,2,3};
.. вы фактически пытаетесь указать на массив, который не был помещен нигде в частности в память. arr
- это указатель, а не массив; он содержит адрес памяти, но сам по себе не хранит данные массива. Если вы используете int arr[]
вместо int *arr
, то он работает, потому что такой массив связан с хранилищем для его содержимого. Хотя массив распадается на указатель на свои данные во многих контекстах, это не одно и то же.
Даже со строковыми литералами char *str = "Hello";
и char str[] = "Hello";
делают разные вещи. Первый устанавливает указатель str
на строковый литерал, а второй инициализирует массив str
со значениями из "Hello"
. В массиве есть хранилище для связанных с ним данных, но указатель просто указывает на данные, которые уже загружены в память.
Потому что нет смысла в объявлении и инициализации указателя на массив int, когда имя массива может использоваться как указатель на первый элемент. После того, как
int arr[] = { 0, 1, 2, 3 };
вы можете использовать arr
как int *
почти во всех контекстах (исключение является операндом sizeof
).
... или вы можете злоупотреблять строковыми литералами и хранить числа в виде строкового литерала, который для маленькой конечной машины выглядит следующим образом:
int * arr = (int *)"\0\0\0\0\1\0\0\0\2\0\0\0\3\0\0\0";