C. Бочков - Язык программирования Си для персонального компьютера
Индексное выражение обычно используется для доступа к элементам массива, однако индексацию можно применить к любому указателю.
Индексное выражение вычисляется путем сложения целого значения со значением указателя (или с адресом массива) и последующим применением к результату операции косвенной адресации. Операция косвенной адресации описана в разделе 4.3.2. Например, для одномерного массива следующие четыре выражения эквивалентны, если а — массив или указатель, а b — целое.
а[b]
*(а + b)
*(b + а)
b[а]
В соответствии с правилами преобразования типов для операции сложения (смотри раздел 4.3.4) целочисленное значение при сложении с указателем (адресом) должно умножаться на размер типа, адресуемого указателем. Предположим, например, что идентификатор line определен как массив типа int. При вычислении выражения line[i], целое значение i умножается на размер типа int. Полученное значение представляет i ячеек типа int. Это значение складывается со значением указателя line, что дает адрес объекта, смещенного на i ячеек типа int относительно line, т.е. адрес i-го элемента line.
Заключительным шагом вычисления индексного выражения является применение к полученному адресу операции косвенной адресации. Результатом является значение i-го элемента массива line.
Следует помнить, что индексное выражение line[0] представляет значение первого элемента массива, так как индексация элементов массива начинается с нуля. Следовательно, выражение line[5] ссылается на шестой по порядку следования в памяти элемент массива.
Доступ к многомерному массивуИндексное выражение может иметь более одного индекса. Синтаксис такого выражения следующий:
<выражение1>[<выражение2>][<выражение3>]…
Индексное выражение интерпретируется слева направо. Сначала вычисляется самое левое индексное выражение — <выражение1>[<выражение2>]. С адресом, полученным в результате сложения <выражения1> и <выражения2>, складывается (по правилам сложения указателя и целого) <выражение3> и т. д. <ВыражениеЗ> и последующие <выражения> имеют целый тип. Операция косвенной адресации осуществляется после вычисления последнего индексного выражения. Однако, если значение последнего указателя адресует значение типа массив, операция косвенной адресации не применяется (смотри третий и четвертый примеры ниже).
Выражения с несколькими индексами ссылаются на элементы многомерных массивов. Многомерный массив в языке Си понимается как массив, элементами которого являются массивы. Например, элементами трехмерного массива являются двумерные массивы.
Примеры:
int рrор[3][4][6];
int i, *ip, (*ipp)[6];
i = prop[0][0][1]; /* пример 1 */
i = prop[2][1][3]; /* пример 2 */
ip = prop[2][1]; /* пример 3 */
ipp = prop[2]; /* пример 4 */
Массив с именем prop содержит 3 элемента, каждый из которых является двумерным массивом значений типа int. В примере 1 показано, каким образом получить доступ ко второму элементу (типа int) массива prop. Поскольку массив заполняется построчно, последний индекс меняется наиболее быстро. Выражение prop[0][0][2] ссылается на следующий (третий) элемент массива и т. д.
Во втором примере выражение вычисляется следующим образом:
1) Первый индекс 2 умножается на размер двумерного массива (4 на 6), затем на размер типа int и прибавляется к значению указателя prop. Результат будет указывать на третий двумерный массив (размером 4 на 6 элементов) в трехмерном массиве prop.
2) Второй индекс 1 умножается на размер 6-элементного массива типа int и прибавляется к адресу, представляемому выражением prop[2].
3) Каждый элемент 6-элементного массива имеет тип int, поэтому индекс 3 умножается на размер типа int и прибавляется к адресу, представляемому выражением prop[2][1]. Результирующий указатель адресует четвертый элемент массива из шести элементов.
4) На последнем шаге вычисления выражения рrор[2][1][3] выполняется косвенная адресация по указателю. Результатом является элемент типа int, расположенный по вычисленному адресу.
В примерах 3 и 4 представлены случаи, когда косвенная адресация не применяется. В примере 3 выражение prop[2][1] представляет указатель на массив из шести элементов в трехмерном массиве prop. Поскольку значение указателя адресует массив, операция косвенной адресации не применяется. Аналогично, результатом вычисления выражения prop[2] в примере 4 является значение указателя, адресующего двумерный массив.
Выбор элемента
Синтаксис:
<выражение>.<идентификатор>
<выражение> -> <идентификатор>
Выражение выбора элемента позволяет получить доступ к элементу структуры или объединения. Выражение имеет значение и тип выбранного элемента.
В первой синтаксической форме <выражение> представляет значение типа struct или union, а идентификатор именует элемент специфицированной структуры или объединения. Во второй синтаксической форме <выражение> представляет указатель на структуру или объединение, а идентификатор именует элемент специфицированной структуры.
Обе синтаксические формы выражения выбора элемента дают одинаковый результат. Запись
<выражение> -> <идентификатор>
для случая, когда <выражение> имеет тип указатель, эквивалентна записи
(*<выражение>).<идентификатор>
однако более наглядна.
Примеры:
struct pair {
int a;
inl b;
struct pair *sp;
} item, list[10];
item.sp = &item; /* пример 1 */
(item.sp)->a = 24; /* пример 2 */
list[8].b = 12; /* пример 3 */
В первом примере адрес структуры Нет присваивается элементу sp этой же структуры. В результате структура item содержит указатель на себя.
Во втором примере используется адресное выражение item.sp с операцией выбора элемента ->, присваивающее значение элементу а. Учитывая результат примера 1, пример 2 эквивалентен записи
item.a = 24;
В третьем примере показано, каким образом в массиве структур осуществить доступ к элементу отдельной структуры.
Операции и L-выражения
В зависимости от используемых операций выражения подразделяются на первичные, унарные, бинарные, тернарные, выражения присваивания и выражения приведения типа.
Первичные выражения рассмотрены в разделах 4.2.4, 4.2.5, 4.2.6.
Унарное выражение состоит из операнда с предшествующей ему унарной операцией.
Синтаксис:
<унарная-операция> <операнд>
Унарные операции рассмотрены в разделе 4.3.2.
Бинарное выражение состоит из двух операндов, разделенных бинарной операцией.
Синтаксис:
<операнд1> <бинарная-операция> <операнд2>
Бинарные операции рассмотрены в разделах 4.3.3 — 4.3.9.
Тернарное выражение состоит из трех операндов, разделенных знаками условной операции "?:".
Синтаксис:
<операнд1> ? <операнд2> : <операнд3>
Условная операция рассмотрена в разделе 4.3.10.
Выражения присваивания используют унарные или бинарные операции присваивания. Унарными операциями присваивания являются инкремент "++" и декремент "--". Бинарные операции присваивания — это простое присваивание "=" и составные операции присваивания. Каждая составная операция присваивания представляет собой комбинацию какой-либо бинарной операции с простой операцией присваивания.
Синтаксис выражений присваивания:
Унарные операции присваивания:
<операнд> ++
<операнд> --
++ <операнд>
--<операнд>
Бинарные операции присваивания:
<операнд1> = <операнд2>
<операнд1> <составное-присваивание> <операнд2>
Операция присваивания рассмотрена в разделе 4.4.
Выражения приведения типа используют операцию приведения типа для явного преобразования типа переменной скалярного типа (целого, перечислимого, плавающего, пустого, указателя).