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

int arr[] = {0,1,2,3,4,5,6,7,8,9};

int *p = arr; // p указывает на первый элемент в arr

++p;          // p указывает на arr[1]

Подобно тому, как итераторы можно использовать для перебора элементов вектора, указатели можно использовать для перебора элементов массива. Конечно, для этого нужно получить указатели на первый элемент и элемент, следующий после последнего. Как упоминалось только что, указатель на первый элемент можно получить при помощи самого массива или при обращении к адресу первого элемента. Получить указатель на следующий элемент после последнего можно при помощи другого специального свойства массива. Последний элемент массива arr находится в позиции 9, а адрес несуществующего элемента массива, следующего после него, можно получить так:

int *е = &arr[10]; // указатель на элемент после

                   // последнего в массиве arr

Единственное, что можно сделать с этим элементом, так это получить его адрес, чтобы инициализировать указатель е. Как и итератор на элемент после конца (см. раздел 3.4.1), указатель на элемент после конца не указывает ни на какой элемент. Поэтому нельзя ни обратиться к его значению, ни прирастить.

Используя эти указатели, можно написать цикл, выводящий элементы массива arr.

for (int *b = arr; b != e; ++b)

 cout << *b << endl; // вывод элементов arr

Библиотечные функции begin() и end()

Указатель на элемент после конца можно вычислить, но этот подход подвержен ошибкам. Чтобы облегчить и обезопасить использование указателей, новая библиотека предоставляет две функции: begin() и end(). Эти функции действуют подобно одноименным функциям-членам контейнеров (см. раздел 3.4.1). Однако массивы — не классы, и данные функции не могут быть функциями-членами. Поэтому для работы они получают массив в качестве аргумента.

int ia[] = {0,1,2,3,4,5,6,7,8,9}; // ia - массив из десяти целых чисел

int *beg = begin(ia); // указатель на первый элемент массива ia

int *last = end(ia);  // указатель на следующий элемент ia за последним

Функция begin() возвращает указатель на первый, а функция end() на следующий после последнего элемент данного массива. Эти функции определены в заголовке iterator.

Используя функции begin() и end(), довольно просто написать цикл обработки элементов массива. Предположим, например, что массив arr содержит значения типа int. Первое отрицательное значение в массиве arr можно найти следующим образом:

// pbeg указывает на первый, a pend на следующий после последнего

// элемент массива arr

int *pbeg = begin(arr), *pend = end(arr);

// найти первый отрицательный элемент, остановиться, если просмотрены

// все элементы

while (pbeg != pend && *pbeg >= 0)

 ++pbeg;

Код начинается с определения двух указателей типа int по имени pbeg и pend. Указатель pbeg устанавливается на первый элемент массива arr, a pend — на следующий элемент после последнего. Условие цикла while использует указатель pend, чтобы узнать, безопасно ли обращаться к значению указателя pbeg. Если указатель pbeg действительно указывает на элемент, выполняется проверка результата обращения к его значению на наличие отрицательного значения. Если это так, то условие ложно и цикл завершается. В противном случае указатель переводится на следующий элемент.

Указатель на элемент "после последнего" у встроенного массива ведет себя так же, как итератор, возвращенный функцией end() вектора. В частности, нельзя ни обратиться к значению такого указателя, ни осуществить его приращение.

Арифметические действия с указателями

Указатели на элементы массива позволяют использовать все операции с итераторами, перечисленные в табл. 3.6 и 3.7. Эти операции, обращения к значению, инкремента, сравнения, добавления целочисленного значения, вычитания двух указателей, имеют для указателей на элементы встроенного массива то же значение, что и для итераторов.