Существует множество свидетельств того факта, что операции с массивами зачастую являются операциями с указателями. Одно из них — при использовании массива как инициализатора переменной, определенной с использованием спецификатора auto
(см. раздел 2.5.2), выводится тип указателя, а не массива.
int ia[] = {0,1,2,3,4,5,6,7,8,9}; //
auto ia2(ia); //
ia2 = 42; //
//
Хотя ia
является массивом из десяти целых чисел, при его использовании в качестве инициализатора компилятор рассматривает это как следующий код:
auto ia2(&ia[0]); //
Следует заметить, что это преобразование не происходит, если используется спецификатор decltype
(см. раздел 2.5.3). Выражение decltype(ia)
возвращает массив из десяти целых чисел:
//
decltype(ia) ia3 = {0,1,2,3,4,5,6,7,8,9};
ia3 = p; //
ia3[4] = i; //
Указатели, содержащие адреса элементов в массиве, обладают дополнительными возможностями, кроме описанных в разделе 2.3.2. В частности, указатели на элементы массивов поддерживают те же операции, что и итераторы векторов или строк (см. раздел 3.4). Например, можно использовать оператор инкремента для перемещения с одного элемента массива на следующий:
int arr[] = {0,1,2,3,4,5,6,7,8,9};
int *p = arr; //
++p; //
Подобно тому, как итераторы можно использовать для перебора элементов вектора, указатели можно использовать для перебора элементов массива. Конечно, для этого нужно получить указатели на первый элемент и элемент, следующий после последнего. Как упоминалось только что, указатель на первый элемент можно получить при помощи самого массива или при обращении к адресу первого элемента. Получить указатель на следующий элемент после последнего можно при помощи другого специального свойства массива. Последний элемент массива arr
находится в позиции 9, а адрес несуществующего элемента массива, следующего после него, можно получить так:
int *е = &arr[10]; //
//
Единственное, что можно сделать с этим элементом, так это получить его адрес, чтобы инициализировать указатель е
. Как и итератор на элемент после конца (см. раздел 3.4.1), указатель на элемент после конца не указывает ни на какой элемент. Поэтому нельзя ни обратиться к его значению, ни прирастить.
Используя эти указатели, можно написать цикл, выводящий элементы массива arr
.
for (int *b = arr; b != e; ++b)
cout << *b << endl; //
begin()
и end()
begin()
и end()
. Эти функции действуют подобно одноименным функциям-членам контейнеров (см. раздел 3.4.1). Однако массивы — не классы, и данные функции не могут быть функциями-членами. Поэтому для работы они получают массив в качестве аргумента.
int ia[] = {0,1,2,3,4,5,6,7,8,9}; // ia -
int *beg = begin(ia); //
int *last = end(ia); //
Функция begin()
возвращает указатель на первый, а функция end()
на следующий после последнего элемент данного массива. Эти функции определены в заголовке iterator
.
Используя функции begin()
и end()
, довольно просто написать цикл обработки элементов массива. Предположим, например, что массив arr
содержит значения типа int
. Первое отрицательное значение в массиве arr
можно найти следующим образом: