double d = v[1]; // отлично (использует неконстантный вариант [ ])
v[1] = 2.0; // отлично (использует неконстантный вариант [ ])
}
Поскольку объекты класса vector
часто передаются по константной ссылке, эта версия оператора operator[]()
с ключевым словом const
является существенным дополнением.
18.5. Массивы
• Как глобальные переменные (правда, использование глобальных переменных часто является плохой идеей).
• Как локальные переменные (однако массивы накладывают на них серьезные ограничения).
• Как аргументы функции (но массив не знает своего размера).
• Как член класса (хотя массивы, являющиеся членами класса, трудно инициализировать).
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]
— это ошибка? В принципе мог бы, но, как нам известно, в настоящее время не существует ни одного такого компилятора. Дело в том, что отследить границы массива на этапе компиляции невозможно в принципе, а перехват простейших ошибок (таких как приведены выше) не решает всех проблем.
18.5.1. Указатели на элементы массива
Указатель может ссылаться на элемент массива. Рассмотрим пример.
double ad[10];
double* p = &ad[5]; // ссылается на элемент ad[5]
Указатель p
ссылается на переменную типа double
, известную как ad[5]
.
Этот указатель можно индексировать и разыменовывать.
*p =7;
p[2] = 6;
p[–3] = 9;
Теперь ситуация выглядит следующим образом.