Читаем Программирование полностью

  double d = v[1];  // отлично (использует неконстантный вариант [ ])

  v[1] = 2.0;       // отлично (использует неконстантный вариант [ ])

}

Поскольку объекты класса vector часто передаются по константной ссылке, эта версия оператора operator[]() с ключевым словом const является существенным дополнением. 

<p id="AutBody_Root331"><strong>18.5. Массивы</strong></p>

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

• Как глобальные переменные (правда, использование глобальных переменных часто является плохой идеей).

• Как локальные переменные (однако массивы накладывают на них серьезные ограничения).

• Как аргументы функции (но массив не знает своего размера).

• Как член класса (хотя массивы, являющиеся членами класса, трудно инициализировать).

  Возможно, вы заметили, что мы отдаем заметное предпочтение классу vector по сравнению с массивами. Класс std::vector следует использовать при любой возможности. Однако массивы существовали задолго до появления векторов и являлись их приблизительным прототипом во многих языках (особенно в языке C), поэтому их следует знать хорошо, чтобы иметь возможность работать со старыми программами или с программами, написанными людьми, не признающими преимущества класса vector.

  Итак, что такое массив? Как его определить и как использовать? Массив — это однородная последовательность объектов, расположенных в смежных ячейках памяти; иначе говоря, все элементы массива имеют один и тот же тип, и между ними нет пробелов. Элементы массива нумеруются, начиная с нуля в возрастающем порядке. В объявлении массив выделяется квадратными скобками.

const int max = 100;

int gai[max];   // глобальный массив (из 100 чисел типа int);

                // "живет всегда"

void f(int n)

{

  char lac[20]; // локальный массив; "живет" до конца области

                // видимости

  int lai[60];

  double lad[n]; // ошибка: размер массива не является константой

  // ...

}

Обратите внимание на ограничение: количество элементов именованного массива должно быть известно на этапе компиляции. Если мы хотим, чтобы количество элементов массива было переменным, то должны разместить его в свободной памяти и обращаться к нему через указатель. Именно так поступает класс vector с массивами элементов.

Как и к элементам массивов, размещенных в свободной области, доступ к элементам именованных массивов осуществляется с помощью операторов индексирования и разыменования ([ ] и *). Рассмотрим пример.

void f2()

{

  char lac[20];   // локальный массив; "живет" до конца области

                  // видимости

  lac[7] = 'a';

  *lac = 'b';     // эквивалент инструкции lac[0]='b'

  lac[–2] = 'b';  // ??

  lac[200] = 'c'; // ??

}

  Эта функция компилируется, но, как мы знаем, не все скомпилированные функции работают правильно. Использование оператора [ ] очевидно, но проверка выхода за пределы допустимого диапазона отсутствует, поэтому функция f2() компилируется, а результат записи lac[–2] и lac[200] приводит к катастрофе (как всегда, при выходе за пределы допустимого диапазона). Не делайте этого. Массивы не проверяют выход за пределы допустимого диапазона. И снова здесь нам приходится непосредственно работать с физической памятью, так как на системную поддержку рассчитывать не приходится.

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

<p id="AutBody_Root332"><strong>18.5.1. Указатели на элементы массива</strong></p>

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

double ad[10];

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

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

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

*p =7;

p[2] = 6;

p[–3] = 9;

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

Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже