Выбрать главу

Повторное знакомство с массивами в свете указателей...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" ;

      }

Эта версия функции использует операции над массивами, которые знакомы нам по предыдущим главам. Если воспользоваться для написания этой функции указателями, программа приобретёт такой вид: