В 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";