Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп
Книгу Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп читаем онлайн бесплатно полную версию! Чтобы начать читать не надо регистрации. Напомним, что читать онлайн вы можете не только на компьютере, но и на андроид (Android), iPhone и iPad. Приятного чтения!
Шрифт:
Интервал:
Закладка:

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 на пять элементов вправо
В итоге получим следующее.


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];
double* p2 = p1+7;
double* p3 = &p1[7];
if (p2 != p3) cout << "impossible!n";

18.5.2. Указатели и массивы

char ch[100];
Размер массива ch, т.е. sizeof(ch), равен 100. Однако имя массива без видимых причин превращается в указатель.
char* p = ch;
Здесь указатель p инициализируется адресом &ch[0], а размер sizeof(p) равен 4 (а не 100). Это свойство может быть полезным. Например, рассмотрим функцию strlen(), подсчитывающую количество символов в массиве символов, завершающимся нулем.
int strlen(const char* p) // аналогична стандартной
// функции strlen()
{
int count = 0;
while (*p) { ++count; ++p; }
return count;
}
Теперь можем вызвать ее как с аргументом strlen(ch), так и с аргументом strlen(&ch[0]). Возможно, вы заметили, что такое обозначение дает очень небольшое преимущество, и мы с вами согласны. Одна из причин, по которым имена массивов могут превращаться в указатели, состоит в желании избежать передачи большого объема данных по значению. Рассмотрим пример.
int strlen(const char a[]) // аналогична стандартной
// функции strlen()
{
int count = 0;
while (a[count]) { ++count; }
return count;
}
char lots [100000];
void f()
{
int nchar = strlen(lots);
// ...
Наивно (но частично обоснованно) мы могли бы ожидать, что при выполнении этого вызова будут скопированы 100 тыс. символов, заданных как аргумент функции strlen(), но этого не происходит. Вместо этого объявление аргумента char p[] рассматривается как эквивалент объявления char* p, а вызов strlen(lots) — как эквивалент вызова strlen(&lots[0]). Это предотвращает затратное копирование, но должно вас удивить. Почему вы должны
Прочитали книгу? Предлагаем вам поделится своим отзывом от прочитанного(прослушанного)! Ваш отзыв будет полезен читателям, которые еще только собираются познакомиться с произведением.
Уважаемые читатели, слушатели и просто посетители нашей библиотеки! Просим Вас придерживаться определенных правил при комментировании литературных произведений.
- 1. Просьба отказаться от дискриминационных высказываний. Мы защищаем право наших читателей свободно выражать свою точку зрения. Вместе с тем мы не терпим агрессии. На сайте запрещено оставлять комментарий, который содержит унизительные высказывания или призывы к насилию по отношению к отдельным лицам или группам людей на основании их расы, этнического происхождения, вероисповедания, недееспособности, пола, возраста, статуса ветерана, касты или сексуальной ориентации.
- 2. Просьба отказаться от оскорблений, угроз и запугиваний.
- 3. Просьба отказаться от нецензурной лексики.
- 4. Просьба вести себя максимально корректно как по отношению к авторам, так и по отношению к другим читателям и их комментариям.
Надеемся на Ваше понимание и благоразумие. С уважением, администратор knigkindom.ru.
Оставить комментарий
-
Гость Татьяна24 сентябрь 22:20 Как то не очень... Невеста по ошибке. Я не дам тебе развод - Майя Линн
-
Римма24 сентябрь 21:52 Почему главные героинитпкие идиотки? И сюжет не плохой, и написано хорошо. Но как героиня - так дура дурой.... Хозяйка маленького дома, или Любимая для дракона - Кира Рамис
-
Римма20 сентябрь 12:27 Много ненужных пояснений и отступлений. Весь сюжет теряет свою привлекательность. Героиня иногда так тупит, что читать не... Хозяйка приюта для перевертышей и полукровок - Елена Кутукова