Приведем снова текст программы.
#include<iostream.h> int a[] = { 0,1,2,3,4 }; main () { int *p; for (int i=0; i<=4; i++) cout << "a[" << i << "]=" << a[i] << " "; /* Печать 1 */ cout << endl; for (p=&a[0]; p<=&a[4]; p++) cout << "*p=" << *p << " "; /* Печать 2 */ cout << endl; for (p=&a[0],i=1; i<=5; i++) cout << "p[" << i << "]=" << p[i] << " "; /* Печать 3 */ cout << endl; for (p=a,i=0;p+i<=a+4;p++,i++) cout << "*(p+" << i << ")=" << *(p+i) << " "; /* Печать 4 */ cout << endl; for (p=a+4; p>=a; p--) cout << "*p=" << *p << " "; /* Печать 5 */ cout << endl; for (p=a+4,i=0; i<=4; i++) cout << "p[" << 4-i << "]=" << p[-i] << " "; /* Печать 6 */ cout << endl; for (p=a+4;p>=a;p--) cout << "a[" << p-a << "]=" << a[p-a] << " "; /* Печать 7 */ cout << endl; }
Результаты работы программы:
Печать 1 : a[0]=0 a[1]=1 a[2]=2 a[3]=3 a[4]=4 Печать 2 : *p=0 *p=1 *p=2 *p=3 *p=4 Печать 3 : p[1]=1 p[2]=2 p[3]=3 p[4]=4 p[5]=23393 Печать 4 : *(p+0)=0 *(p+1)=2 *(p+2)=4 Печать 5 : *p=4 *p=3 *p=2 *p=1 *p=0 Печать 6 : p[4]=4 p[3]=3 p[2]=2 p[1]=1 p[0]=0 Печать 7 : a[4]=4 a[3]=3 a[2]=2 a[1]=1 a[0]=0
Комментарии.
int a[]={0,1,2,3,4};
for (i=0;i<=4;i++)
cout << "a[" << i << "]=" << a[i] << " ";
Переменная a определена как массив из пяти целых с элементами a[i]=i для i от 0 до 4. Переменная i, принимая значения от 0 до 4, последовательно "пробегает" все элементы массива a, и "Печать 1" напечатает следующее:
a[0]=0 a[1]=1 a[2]=2 a[3]=3 a[4]=4
int *p; В этой задаче переменная p описана как ссылка на целое. for (p=&a[0]; &a[0] является адресом a[0]. p<=&a[4];p++;) Элементы массива хранятся в памяти в по- рядке возрастания индексов, т.е. a[0] предшествует a[1], которое предшествует a[2] и т.д. Так что p, инициализируемое значением &a[0], меньше, чем &a[4]. cout<< "*p=" << *p ; Выражение *p дает целое, хранящееся по ад- ресу, содержащемуся в p. Поскольку p со- держит &a[0], то *p есть a[0]. p++; Если к ссылке применить операцию увеличе- ния, то она будет указывать на следующий элемент типа int. Фактически же значение ссылки увеличивается на sizeof (int). В языке не предполагается проверка того, что получившийся в результате адрес действи- тельно есть адрес доступного элемента типа int. В этой задаче p будет указывать на следующий элемент массива a. p<=&a[4] Значение p проверяется на конец массива a. Цикл заканчивается, когда p будет указы- вать "за" последний элемент массива. В те- ле цикла p последовательно указывает на элементы массива в порядке возрастания ин- дексов. И Печать 2 напечатает: *p=0 *p=1 *p=2 *p=3 *p=4
for (p=&a[0],i=1;i<=5; i++) Переменная p указывает на начало массива a. Переменная i "пробегает" значения от 1 до 5. cout << "p[" << i << Ссылка p[i] последовательно указывает на "]=" << p[i]; элементы массива a.
Хотя до сих пор обозначение [] находило свое обычное применение - индексация массива, на самом деле [] обозначает общую операцию индексирования. x[i] определяется как *(x+i), где x обычно является адресом и i - целое. В соответствии с правилами адресной арифметики i должно быть кратно sizeof (базовый тип x).
Базовым типом мы будем называть тип объекта языка, на который ссылается указатель. (К этому моменту должно быть ясно, почему массивы индексируются начиная с 0. Имя массива по сути есть ссылка на первый элемент массива. Индекс - это смещение относительно начала массива. Смещение первого элемента относительно начала массива равно 0.)
В предыдущем фрагменте i используется для индексации ссылки p: p[i]=*(p+i)=*(a+i)=a[i]. Переменная i "пробегает" значения от 1 до 5. Когда i принимает значение 5, p+i указывает "за" массив a, т.е. значение, находящееся по адресу p+i, неизвестно. Это настолько распространенная ошибка, что стоит подчеркнуть опять: индекс массива из n элементов принимает значения от 0 до n-1.
for(p=a,i=0; Ссылке p присваивается адрес первого эле- мента a. p+i<=a+4; p=a, i=0, так что p+i=a+0, что меньше, чем a+4. cout << "*(p+" << i << ")=" << *(p+i) *(p+i)=*(a+0)=a[0]. << " "; p++,i++;) p указывает на второй элемент a, i равно 1. p+i<=a+4; p=a+1, i=1, значит, p+i=a+2. cout << "*(p+" << i << ")=" << *(p+i) *(p+i)=a[2]. << " "; p++,i++ p=а+2, i=2. p+i<=a+4; p+i=a+4. cout << "*(p+" << i << ")=" << *(p+i) *(p+i)=a[4]. << " "; p++,i++ p=а+3, i=3. p+i<=a+4; p+i=a+6, цикл заканчивается.
for (p=a+4; Ссылка p указывает на пятый элемент мас- сива a. p>=a; Цикл заканчивается, когда p указывает "за" a. cout << "*p=" << *p ; Печатается целое, на которое указывает p. p-- При уменьшении p "настраивается" на преды- дущий элемент массива.
for (p=a+4,i=0;i<=4;i++) Ссылка p указывает на последний элемент массива a, i "пробегает" от 0 до 4. cout << "p[" << 4-i Печатается i-й от конца массива элемент. << "]=" << p[-i];
for (p=a+4;p>=a;p--) Ссылка p последовательно указывает на все элементы массива a, от последнего до пер- вого. cout << "a[" << p-a Значение p-a равно смещению элемента масси- << "]=" << a[p-a] ва (на который указывает p от начала). Дру- << " "; гими словами, p-a есть индекс элемента, на который указывает p.