Отличия между доступом по имени массива и по указателю
Идентификатор массива является адресом первого элемента, входящего в этот массив, т.е. имеет место равенство
a == &a [ 0 ]
а присваивание ptr_a = a [ 0 ] можно короче записать так:
ptr_a = a;
a [ i ] можно эквивалентно записать как *(a + i) – это даст нам элемент массива а с индексом i, т.е.:
a [ i ] = *(a + i);
Начальный элемент массива можно просто записать как *а, т.е.:
a [ 0 ] = = *a == 1 ; // в нашем случае
Предположим, имеется массив из 100 целых чисел. Запишем двумя способами программу суммирования элементов этого массива:
long array[100];
long sum = 0;
for (int i = 0; i < 100; i++)
sum += array[i];
То же самое можно сделать с помощью указателей:
long array[100];
long sum = 0;
for (long* ptr = &array[0]; // long* ptr = array
ptr < &array[99] + 1; ptr++)
sum += *ptr;
Элементы массива расположены в памяти последовательно, и увеличение указателя на единицу означает смещение к следующему элементу массива. Упоминание имени массива без индексов преобразуется в адрес его первого элемента:
for (long* ptr = array;
ptr < &array[99] + 1; ptr++)
sum += *ptr;
Хотя смешивать указатели и массивы можно, мы бы не стали рекомендовать такой стиль, особенно начинающим программистам.
При использовании многомерных массивов указатели позволяют обращаться к срезам или подмассивам. Если мы объявим трехмерный массив exmpl:
long exmpl[5][6][7]
то выражение вида exmpl[1][1][2] – это целое число, exmpl[1][1] – вектор целых чисел (адрес первого элемента вектора, т.е. имеет тип *long), exmpl[1] – двухмерная матрица или указатель на вектор (тип (*long)[7]). Таким образом, задавая не все индексы массива, мы получаем указатели на массивы меньшей размерности.
Эквивалентность между именем массива и указателем основано на доступе или адресации смежных фрагментов памяти. Способы, по которым идентификатор массива и указатель получают доступ к этой памяти, совершенно различны.
1). При определении массива выделяется блок памяти, размер которого достаточен для хранения описанного массива.
Идентификатор массива инициализируется адресом этой памяти. Этот адрес не может меняться внутри программы. Поэтому а нельзя изменять внутри программы и такая запись будет ошибочной:
а++;// а менять нельзя
А так писать можно:
*( а + i ) или a [ i ]
Идентификатор массива по поведению эквивалентен постоянному указателю на объект данного типа.
Например,
int const *(cptr_a);
будет вести себя как а.
2). При определении указателя выделяется память, размер которой достаточен для хранения адреса памяти. Программист должен сначала установить указатель на адрес некоторого ранее определенного объекта или фрагмент памяти, после чего может безопасно им пользоваться. Один из способов сделать так – присвоить указателю адрес ранее определенного объекта:
int a [ 4 ] = { 1, 2, 3, 4 } ;
int ptr_a = a;// теперь ptr_a указывает на выделенную память
Кроме этого, указатель – это переменная и его можно увеличивать или уменьшать:
ptr_a++; // теперь ptr_a указывает на a [ 1 ] : *ptr_a == 2
Программа, иллюстрирующая различные способы применения указателей при обращении к элементам массива.
// Указатели и массивы
// Иллюстрация различных способов обращение к элементам массива на примере вычисления
// суммы пяти элементов вектора
#include <iostream>
using namespace std;
int main()
{
int a[ ] = { 1, 2, 3, 4, 5 }; // определяем массив а
int *ptr_a = a; // инициализируем указатель ptr_a значением адреса первого элемента
// массива а ( адресом элемента a[0] )
// Данный оператор компилятор по умолчанию воспринимает как:
// int * const ptr_a = a;
int s = 0;
for(int i=0; i<4; i++)
s += a[i];
cout << "s = " << s; // результат 10
s = 0;
for(i=0; i<4; i++)
s += *(ptr_a+i); // помним, что ptr_a указывает на a[0], а
// ptr_a + 1 указывает на элемент a[1] и т.д.
cout << " s = " << s; // результат 10
s = 0;
for(i=0; i<4; i++)
s += *(a+i); // помним, что имя массива (а) является указателем
// на первый элемент массива
cout << " s = " << s; // результат 10
s = 0;
for(i=0; i<4; i++)
s += ptr_a[i]; // это "указатель-индекс". Указатель можно индексировать
// точно также, как и массив
cout << " s = " << s; // результат 10
getchar();
return 0;
}