Повторное знакомство с массивами в свете указателей...118
Обратимся к странному и мистическому миру массивов. Ещё раз воспользуемся в качестве примера домами моих соседей. Массив тоже очень похож на городской квартал. Каждый элемент массива выступает в качестве дома в этом квартале. Дома — элементы массива — отсчитываются по порядку от начала квартала. Дом на углу улицы отстоит на 0 домов от угла, следующий дом отстоит на 1 дом от угла и т.д. Пользуясь терминологией массивов, можно сказать, что cityBlock[ 0 ] представляет собой дом по адресу 123 Main Street, cityBlock[ 1 ] — дом по адресу 124 Main Street и т.д.
Теперь представим себе массив из 32-х однобайтовых значений, имеющий имя charArray. Если первый элемент массива находится по адресу 0x110 , тогда массив будет продолжаться вплоть до адреса 0x12f. Таким образом, элемент массива charArray[ 0 ] находится по адресу 0x110 , charArray[ 1 ] — по адресу 0x111 , charArray[ 2 ] — по адресу 0x112 и т.д.
Можно создать указатель ptr на нулевой элемент массива. После выполнения строки ptr = &charArray[ 0 ] ; указатель ptr будет содержать адрес 0x110. Можно прибавить к этому адресу целочисленное смещение и перейти к необходимому элементу массива. Операции над массивами с использованием указателей приведены в табл. 9.2. Эта таблица демонстрирует, каким образом добавление смещения n вызывает переход к следующему элементу массива charArray.
Таблица 9.2. Добавление смещения
_________________
Смещение — Результат — Соответствует
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
+0 — 0x110 — charArray[ 0 ]
+1 — 0x111 — charArray[ 1 ]
+2 — 0x112 — charArray[ 2]
... — ... — ...
+n — 0х110+n — charArray[ n ]
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
Как видите, добавление смещения к указателю на массив равнозначно переходу к соответствующему значению.
Таким образом, если char* ptr — &charArray[ 0 ] ;, то *( ptr + n ) соответствует элементу charArray [ n ].
«Поскольку * имеет более высокий приоритет, чем сложение, операция *ptr + n привела бы к сложению n со значением, на которое указывает ptr. Чтобы выполнить сначала сложение и лишь затем переход к переменной по указателю, следует использовать скобки. Выражение *( ptr + n ) возвращает элемент, который находится по адресу ptr плюс n элементов.»
[Атас!]
_________________
118 стр. Часть 2. Становимся функциональными программистами
В действительности соответствие между двумя формами выражений настолько строго, что С++ рассматривает элемент массива array[ n ] как *( ptr + n ), где ptr указывает на первый элемент array. С++ интерпретирует array[ n ] как *( &аrray [ 0 ] +n ). Таким образом, если дано char charArray[ 20 ], то charArray определяется как &charArray[ 0 ].
Имя массива, записанное без индекса элемента, интерпретируется как адрес нулевого элемента массива ( или просто адрес массива ). Таким образом, можно упростить приведённую выше запись, поскольку array[ n ] С++ интерпретирует как *( array + n ).
Использование операций над указателями для адресации внутри массива...119
Концепция соответствия между индексацией массива и арифметикой указателей весьма полезна.
Например, функция displayArray( ), которая выводит содержимое целочисленного массива, может быть реализована следующим образом:
/* displayArray — отображает элементы массива, имеющего длину nSize */
void displayArray( int intArray[ ] , int nSize )
{
cout << "Значения элементов массива равны:\n" ;
for ( int n = 0 ; n < nSize ; n++ )
{
cout << n << ": " << intArray[ n ] << "\n" ;
}
cout << "\n" ;
}
Эта версия функции использует операции над массивами, которые знакомы нам по предыдущим главам. Если воспользоваться для написания этой функции указателями, программа приобретёт такой вид: