// 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. Эти операции, обращения к значению, инкремента, сравнения, добавления целочисленного значения, вычитания двух указателей, имеют для указателей на элементы встроенного массива то же значение, что и для итераторов.

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

constexpr size_t sz = 5;

int arr[sz] = {1,2,3,4,5};

int *ip = arr;     // эквивалент int *ip = &arr[0]

int *ip2 = ip + 4; // ip2 указывает на arr[4], последний элемент в arr

Результатом добавления 4 к указателю ip будет указатель на элемент, расположенный в массиве на четыре позиции далее от того, на который в настоящее время указывает ip.

Результатом добавления целочисленного значения к указателю должен быть указатель на элемент (или следующую позицию после конца) в том же массиве:

// ok: arr преобразуется в указатель на его первый элемент;

// p указывает на позицию после конца arr

int *p = arr + sz;  // использовать осмотрительно - не обращаться

                    // к значению!

int *p2 = arr + 10; // ошибка: arr имеет только 5 элементов;

                    // значение p2 неопределенно

При сложении arr и sz компилятор преобразует arr в указатель на первый элемент массива arr. При добавлении sz к этому указателю получается указатель на позицию sz (т.е. на позицию 5) этого массива. Таким образом, он указывает на следующую позицию после конца массива arr. Вычисление указателя на более чем одну позицию после последнего элемента является ошибкой, хотя компилятор таких ошибок не обнаруживает.

Подобно итераторам, вычитание двух указателей дает дистанцию между ними. Указатели должны указывать на элементы в том же массиве:

auto n = end(arr) - begin(arr); // n - 5, количество элементов

                                // массива arr

Результат вычитания двух указателей имеет библиотечный тип ptrdiff_t. Как и тип size_t, тип ptrdiff_t является машинозависимым типом, определенным в заголовке cstddef. Поскольку вычитание способно возвратить отрицательное значение, тип ptrdiff_t — знаковый целочисленный.

Для сравнения указателей на элементы (или позицию за концом) массива можно использовать операторы сравнения. Например, элементы массива arr можно перебрать следующим образом:

int *b = arr, *е = arr + sz;

while (b < e) {

 // используется *b

 ++b;

}

Нельзя использовать операторы сравнения для указателей на два несвязанных объекта.

int i = 0, sz = 42;

int *p = &i, *е = &sz

// неопределенно: p и е не связаны; сравнение бессмысленно!

while (p < е)

Перейти на страницу:

Похожие книги