Указатель арифметический замаскированный &(массив[0])


Сегодня я просмотрел некоторый исходный код (это был пример файла, объясняющий использование программного фреймворка) и обнаружил много кода, подобного этому:

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 для цикла, но это вопрос стиля.

Но чрезмерное использование этого получило я думаю: не упускаю ли я чего-то явно очевидного или чего-то тонко скрытого в темных уголках языка?

Для тех, кто хочет взглянуть на исходный код, со всеми его неприятными goto s, malloc s и, конечно, эта указательная вещь, не стесняйтесь смотреть на него онлайн.

5 4

5 ответов:

Вы ничего не упускаете, они означают одно и то же.

Однако, чтобы попытаться пролить на это больше света, я должен сказать, что время от времени я также пишу подобные выражения для большей ясности. Я лично склонен мыслить в терминах объектно-ориентированного программирования, то есть предпочитаю ссылаться на "адрес n - го элемента массива", а не на "смещение n - го от начального адреса массива". Даже если эти две вещи эквивалентны в C, когда я пишу код, я имею в виду первое - поэтому я выражаю это. Возможно, так рассуждает и человек, написавший это письмо.

Да, для первого нет никаких веских причин. Это точно то же самое:

int *ptr = array;

Я согласен и со вторым, можно просто написать:

ptr < (array + 10)

Конечно, вы также можете просто сделать цикл for из 0-9 и установить указатель temp, чтобы он указывал на начало массива.

for(int i = 0, *ptr = array; i < 10; ++i, ++ptr)
    /* ... */
Это, конечно, предполагает, что ptr не изменяется в теле цикла.

Edit: это частично неверно. Читать комментарии.


Проблема с &(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]

Относится кN-му элементу массива.

Чтобы "взять адрес" N-го элемента, применяется оператор & или address of:

  &Array[n]  

Чтобы устранить любые предполагаемые неясности, добавляются скобки:

  &(Array[n])  
Для читателя, читающего слева направо, это выражение имеет смысл::
возвращает адрес элемента в позиции ' n '

Страховка может иметь разработан в качестве защиты от старых неисправных компиляторов.

Некоторые люди считают его более читаемым, чем:

  Array + n  

Извините, но я старой школы и предпочитаю использовать версию"&", парен или без. Я буду тратить свое время на то, чтобы сделать код более легким для чтения, чем беспокоиться о том, какая версия занимает больше времени для компиляции или какая версия более эффективна.

Четко прокомментированный раздел кода имеет более высокую отдачу от инвестиций, чем раздел кода, который микро-оптимизирован для эффективности или использует разделы языка, которые незнакомы неязыковым юристам.