Подтвердить что ты не робот

Инициализация указателя в C

В C почему законно делать

char * str = "Hello";

но незаконно делать

int * arr = {0,1,2,3};
4b9b3361

Ответ 1

Я предполагаю, что как инициализаторы работают на C. Однако вы можете сделать:

int *v = (int[]){1, 2, 3}; /* C99. */

Ответ 2

Что касается C89:

"A string", если используется внешняя инициализация массива char, является строковым литералом; в стандарте говорится, что когда вы используете строковый литерал, как если бы вы создали глобальный массив char, инициализированный этим значением, и написали его имя вместо литерального (там также дополнительное ограничение, которое любая попытка изменить строковый литерал приводит к undefined). В коде вы инициализируете char * строковым литералом, который распадается на указатель char, и все работает нормально.

Однако, если вы используете строковый литерал для инициализации массива char, в действие действуют несколько магических правил, поэтому он больше не "как будто массив... и т.д." (который не будет работать в инициализации массива), но это просто хороший способ рассказать компилятору, как должен быть инициализирован массив.

Способ инициализации массивов {1, 2, 3} сохраняет только эту семантику: это только для инициализации массива, это не "литерал массива".

Ответ 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". В массиве есть хранилище для связанных с ним данных, но указатель просто указывает на данные, которые уже загружены в память.

Ответ 4

Потому что нет смысла в объявлении и инициализации указателя на массив int, когда имя массива может использоваться как указатель на первый элемент. После того, как

int arr[] = { 0, 1, 2, 3 };

вы можете использовать arr как int * почти во всех контекстах (исключение является операндом sizeof).

Ответ 5

... или вы можете злоупотреблять строковыми литералами и хранить числа в виде строкового литерала, который для маленькой конечной машины выглядит следующим образом:

int * arr = (int *)"\0\0\0\0\1\0\0\0\2\0\0\0\3\0\0\0";