#c #arrays
#c #массивы
Вопрос:
int main ()
{
int arr[10][1];
arr[1][0]=44;
arr[0][1]=55;
printf("%i",arr[1][0]);
return 0;
}
Должно ли это выводить «55» или «44»???
Комментарии:
1. Это должно вызвать назальных демонов.
2. Это не ДОМАШНЕЕ задание, мистер Штром.. Я думал, что знаю о массивах C, но этот простой код выдал результат, которого я не ожидал (который в этом случае равен 55). Итак, я ищу объяснение..
3. UB FTW
4. Если бы вы знали о массивах C, где вы ожидали, что будут сохранены эти 55?
Ответ №1:
Нет такого элемента, как arr[0][1]
— так же, как нет элемента arr[10][0]
— индексы массива основаны на нуле.
Если вы объявите:
int arr[10][2];
Ваш код будет работать так, как вы задумали.
С объявлением
int arr[10][1];
когда вы обращаетесь arr[0][1]
, вы обращаетесь к концу первой «строки» массива. Доступ к памяти в C не проверяется, поэтому ваш доступ присваивает псевдоним элементу, хранящемуся в arr[1][0]
.
Если бы вы поменяли местами порядок двух операторов присваивания, вы бы увидели, что отображаемое значение зависит от порядка этих двух присваиваний. Более позднее присваивание записывает значение из более раннего присвоения. Т.е.:
int main ()
{
int arr[10][1];
arr[0][1]=55;
arr[1][0]=44;
printf("%i",arr[1][0]);
return 0;
}
… напечатал бы 44, просто потому, что это было бы конечное значение, записанное в это место в памяти размером int.
РЕДАКТИРОВАТЬ: Потому что у нас так много людей, комментирующих здесь, утверждающих, что интерпретируют паршивый стандарт C99 как объявляющий поведение, которое вы вызвали, как «неопределенное поведение»… Учтите, что следующий код выполняет то же самое, что и выше, в соответствии с разделом 6.5.2.1:
int main(int argc, char *argv[])
{
int arr[10][1];
arr[1][0] = 44;
arr[0][1] = 55;
printf("Value is: %dn", 0[arr][1]);
return 0;
}
В связанном вопросе было заявлено, что компилятор C может выбрать заполнение пространства между «строками» массива из-за проблем с выравниванием. Это дезинформация; ни один стандарт C не говорит, что это возможно.
Комментарии:
1. Большое вам спасибо за указание на очевидное. Я знаю, что если я объявлю это как [10][2], проблем не будет. но почему программа присваивает 55 arr[1][0], это выше моего понимания…
2. ОК. После небольшого размышления я теперь могу это понять. Спасибо, что уделили мне время.
3. Мне жаль, что вы подумали, что это «очевидно» — вы не прояснили в своем вопросе, что вы это знали. Я предполагаю, что шаг, который вы упускаете, заключается в том, что все элементы массива хранятся последовательно в памяти, так что arr[1][0] находится сразу после arr[0][0], и запись arr[0][1] означает то же самое, что «int сразу после arr[0][1]». Я не уверен, как вам помочь больше — этот материал о указателях, сглаживании и массивах является своего рода основой C. Может быть, вернуться и прочитать оригинальный K amp; R? На самом деле это действительно хорошо.
4. Нет, я пропускаю 8 часов сна, которые я должен был иметь. Извините, если я все равно вас обидел. Еще раз спасибо за ответ.
5.
arr
это массив, ноarr[0]
черезarr[9]
проходят 10 массивов по одному элементу в каждом.arr[0]
в частности, это одноэлементный массив, поэтому вы не можете сделатьarr[0][1]
больше, чем вы можете сделатьint a[1]; a[1] = 42;
. Тот факт, чтоarr[1][0]
занимает ту же память, что иarr[0][1]
, не имеет значения для стандарта:arr[0][1]
это UB.
Ответ №2:
Нет, они не совпадают. Вы объявили массив из десяти массивов, каждый из которых содержит один целочисленный элемент. arr[0][1]
больше вашего индекса массива, поэтому должна быть ошибка. Результат должен быть 44.
Комментарии:
1. Тем не менее, результат получается как 55. Почему это должно быть?
2. @Anc — Потому что
arr[0][1]
это незаконно. Вы объявили свой массив какint arr[10][1]
, что означает, что он содержит 10 столбцов и 1 строку. Затемarr[0][1]
пытается получить доступ ко второй строке первого столбца, который не существует, поэтому он делает сумасшедшие вещи.3. @Chris — Это не незаконно. Это просто не то, чего ожидал OP.
4. @Chris Lutz: неопределенный означает неопределенный; компилятору не требуется отклонять код или вызывать сообщение об ошибке в двоичном файле. Возможен любой результат, и, насколько это касается стандарта, одинаково правильный.
5. @Chris, @John — Покажите мне, где какой-либо стандарт C указывает, что это поведение не определено. Фактически, ISO 9899: TC2, раздел 6.5.2.1 определяет, как это будет себя вести. Я понимаю, что любой доступ за пределы хранилища, определенного для массива, наверняка вызовет неопределенное поведение. Но я полагаю, что то, что вы говорите об индексах массива, доступе к указателю и т.д., Просто неверно. Доступ, о котором идет речь, находится в пределах определенного пространства, просто доступ осуществляется странным образом.