Сегодня я просмотрел некоторый исходный код (это был пример файла, объясняющего использование программной среды) и обнаружил много такого кода:
int* array = new int[10]; // or malloc, who cares. Please, no language wars. This is applicable to both languages
for ( int* ptr = &(array[0]); ptr <= &(array[9]); ptr++ )
{
...
}
Таким образом, в основном, они сделали «взять адрес объекта, который лежит по адресу array + x
».
Обычно я бы сказал, что это просто глупость, так как написание array + 0
или же array + 9
напрямую делает то же самое. Я бы даже переписывал такой код в цикл size_t for, но это вопрос стиля.
Но чрезмерное использование этого заставило меня задуматься: я упускаю что-то явно очевидное или что-то скрытно скрытое в темных уголках языка?
Для тех, кто хочет взглянуть на оригинальный исходный код, со всеми его неприятностями goto
с, malloc
S и, конечно, эта вещь указатель, не стесняйтесь посмотри на это онлайн.
Вы ничего не упускаете, они означают одно и то же.
Однако, чтобы попытаться пролить немного света на это, я должен сказать, что время от времени я также пишу подобные выражения для большей ясности.
Я лично склонен мыслить в терминах объектно-ориентированного программирования, то есть я предпочитаю ссылаться на «адрес n
элемент массива «, а не» n
th смещение от начального адреса массива «. Хотя эти две вещи эквивалентны в C, когда я пишу код, я имею в виду первое — поэтому я выражаю это.
Возможно, так рассуждает и человек, который это написал.
Да, нет веской причины для первого. Это точно так же:
int *ptr = array;
Я согласен и со вторым, а может просто написать:
ptr < (array + 10)
Конечно, вы могли бы просто сделать это for
зацикливание от 0 до 9 и установите временный указатель так, чтобы он указывал на начало массива.
for(int i = 0, *ptr = array; i < 10; ++i, ++ptr)
/* ... */
Это, конечно, предполагает, что ptr
не изменяется в теле цикла.
Изменить: это частично неверен. Прочитайте комментарии.
Проблема с &(array[0])
является то, что он расширяется до &(*(array + 0))
который включает в себя разыменование. Теперь каждый компилятор, очевидно, будет оптимизировать это так же, как array + 0
, но что касается языка, разыменование может вызвать UB в местах, где array + 0
не будет.
Я думаю, что причина, по которой они так написали, заключалась в том, что
&(array[0])
а также
&(array[9])
просто похожи. Другим способом было бы написать это
array + 0
а также
array + 9
соответственно. Как вы уже упоминали, они, по сути, делают то же самое (по крайней мере, большинство компиляторов, я надеюсь, относятся к нему одинаково)
Вы можете по-разному интерпретировать два разных типа выражений: первое можно прочитать как «адрес элемента 0/9». Второй можно прочитать как «указатель массива со смещением элемента 0/9». Первый звучит более высокоуровнево, второй — более низкоуровневый. Однако большинство людей склонны использовать вторую форму.
Сейчас с array + 0
конечно такой же как array
Вы могли бы просто написать array
, Я думаю, что дело здесь в том, что начало и конец цикла выглядят «аналогично» друг другу. Вопрос личного вкуса.
Согласно классической математике:
Array[n]
относится к энный элемент в массиве.
Чтобы «взять адрес» энный элемент, &
или же address of
оператор применяется:
&Array[n]
Чтобы убрать любые предполагаемые неоднозначности, добавлены круглые скобки:
&(Array[n])
Для читателя, читающего слева направо, это выражение имеет значение:
Вернуть адрес элемента в позиции ‘n’
Страхование могло развиться как защита от старых неисправных компиляторов.
Некоторые люди считают это более читабельным, чем:
Array + n
Извините, но я старая школа и предпочитаю использовать&версия, парен или без. Я потрачу впустую свое время, делая код легче читаемым, чем беспокоясь о том, какая версия компилируется дольше или какая более эффективна.
Четко прокомментированный раздел кода имеет более высокую рентабельность инвестиций, чем раздел кода, который оптимизирован на микроуровне для эффективности или использует разделы языка, которые незнакомы юристам, не владеющим языком.