Почему невозможно назначить массиву несколько элементов на месте, тогда как это возможно при инициализации массива при его определении?

#arrays #c #pointers

#массивы #c #указатели

Вопрос:

Мы можем сделать это:

 int list[] = {1, 2, 3, 4, 5};
  

Но мы не можем этого сделать:

 int list[5];
list = {1, 2, 3, 4, 5};
  

Я предполагаю list , что во втором случае он просто распадается на указатель, но все же он не распадается при определении like int list[5] . Я не совсем понимаю, что происходит, когда массив определен и когда к нему обращаются после определения, и в чем разница, и почему эта разница вообще существует. Мне не удалось найти ответ, я удалю сообщение, если оно есть.

Комментарии:

1. Имя массива не может быть назначено. Это неизменяемое l-значение.

2. @haccks тем не менее, это так, если инициализируется сразу при определении

3. Первоначально C разрешал инициализаторы массива только для статических массивов. Позже они добавили его для нестатических массивов, что является ограниченной формой динамического назначения массива, но только в инициализаторах.

4. @haccks что list[] int list[] = { ... } тогда? Разве мы все еще не присваиваем несколько значений имени?

5. @Kaiyaha Нет, имя массива во втором случае не распадается на указатель. Имя массива просто не допускается в левой части такого присваивания. Это ошибка. Имена массивов распадаются на указатели только в определенных контекстах. Появление пустого места в левой части присваивания не является одним из них. Попробуйте изменить назначение на что-то вроде list = 0; сообщения об ошибке, в котором будет сказано что-то вроде «присвоение выражению с типом массива». Не тип указателя. Тип массива.

Ответ №1:

 int list[] = {1, 2, 3, 4, 5};
  

это не присвоение. Это инициализация.

 int list[5];
list = {1, 2, 3, 4, 5};
  

является определением неинициализированного массива, за которым следует (попытка) присвоения.

Хотя вы можете инициализировать массив (за исключением массивов переменной длины, которые даже не могут быть инициализированы!), Вы не можете назначить ему.

Причина кроется в некоторых довольно исторических решениях, принятых в начале 1970-х годов. C был сделан более или менее совместимым с языком с именем B. В B не было типа массива, вместо этого то, что было именем массива, было указателем в B; и вы могли присвоить ему, не для изменения значений внутри массива, а для того, чтобы он указывал в другом месте.

Массивы C отличались тем, что массивы C сами по себе являются объектами, имеющими размер и все. Чтобы помочь в переносе программ B на C, было введено «имя массива распадается на указатель на первый элемент». Единственной проблемой было назначение массива, которое не могло соответствовать семантике B — так что это было сделано в целом ошибкой.

Более подробная информация доступна на странице истории C Ritchie.

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

 memcpy(list, (const int[]){1, 2, 3, 4, 5}, sizeof list);