Вход/Регистрация
Программирование. Принципы и практика использования C++ Исправленное издание
вернуться

Страуструп Бьерн

Шрифт:

А не мог ли компилятор как-то увидеть, что массив
lac
содержит только двадцать элементов, так что выражение
lac[200]
— это ошибка? В принципе мог бы, но, как нам известно, в настоящее время не существует ни одного такого компилятора. Дело в том, что отследить границы массива на этапе компиляции невозможно в принципе, а перехват простейших ошибок (таких как приведены выше) не решает всех проблем.

18.5.1. Указатели на элементы массива

Указатель может ссылаться на элемент массива. Рассмотрим пример.

double ad[10];

double* p = &ad[5]; // ссылается на элемент ad[5]

Указатель

p
ссылается на переменную типа
double
, известную как
ad[5]
.

Этот указатель можно индексировать и разыменовывать.

*p =7;

p[2] = 6;

p[–3] = 9;

Теперь ситуация выглядит следующим образом.

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

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

p += 2; // переносим указатель p на два элемента вправо

Итак, приходим к следующей ситуации.

Аналогично,

p –= 5; // переносим указатель p на пять элементов вправо

В итоге получим следующее.

Использование операций
+
,
–
,
+=
и
–=
для переноса указателей называется арифметикой указателей (pointer arithmetic). Очевидно, поступая так, мы должны проявлять большую осторожность, чтобы не выйти за пределы массива.

p += 1000; // абсурд: p ссылается на массив, содержащий

// только 10 чисел

double d = *p; // незаконно: возможно неправильное значение

// (совершенно непредсказуемое)

*p = 12.34; // незаконно: можно задеть неизвестные данные

К сожалению, не все серьезные ошибки, связанные с арифметикой указателей, легко обнаружить. Лучше всего просто избегать использования арифметики указателей.

Наиболее распространенным использованием арифметик указателей является инкрементация указателя (с помощью оператора

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

for (double* p = &ad[0]; p<&ad[10]; ++p) cout << *p << '\n';

И в обратном порядке:

for (double* p = &ad[9]; p>=&ad[0]; ––p) cout << *p << '\n';

Это использование арифметики указателей не слишком широко распространено. Однако, по нашему мнению, последний (“обратный”) пример небезопасен. Почему

&ad[9]
, а не
&ad[10]
? Почему
>=
, а не
>
? Эти примеры были бы одинаково хороши (и одинаково эффективны), если бы мы использовали индексацию. Кроме того, они были бы совершенно эквивалентны в классе
vector
, в котором проверка выхода за пределы допустимого диапазона осуществляется проще.

Отметим, что в большинстве реальных программ арифметика указателей связана с передачей указателя в качестве аргумента функции. В этом случае компилятор не знает, на сколько элементов ссылается указатель, и вы должны следить за этим сами. Этой ситуации необходимо избегать всеми силами.

Почему в языке C++ вообще разрешена арифметика указателей? Ведь это так хлопотно и не дает ничего нового по сравнению с тем, что можно сделать с помощью индексирования. Рассмотрим пример.

double* p1 = &ad[0];

  • Читать дальше
  • 1
  • ...
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: