Приведем снова текст программы.

   #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

    Комментарии.


    Печать 1.
     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


    Печать 2.
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


    Печать 3.
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.


    Печать 4.
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, цикл заканчивается.


    Печать 5.
for (p=a+4;           Ссылка p  указывает  на  пятый элемент мас-
                      сива a.
p>=a;                 Цикл заканчивается, когда p  указывает "за"
                      a.
cout << "*p=" << *p ; Печатается целое, на которое указывает p.
p--                   При уменьшении p "настраивается" на  преды-
                      дущий элемент массива.


    Печать 6.
for
 (p=a+4,i=0;i<=4;i++) Ссылка p  указывает  на  последний  элемент
                      массива a, i "пробегает" от 0 до 4.
cout << "p[" << 4-i   Печатается i-й от конца массива элемент.
     << "]=" << p[-i];


    Печать 7.
for (p=a+4;p>=a;p--)  Ссылка p  последовательно  указывает на все
                      элементы массива a, от последнего  до  пер-
                      вого.
cout << "a[" << p-a   Значение p-a равно смещению элемента масси-
  << "]=" << a[p-a]   ва (на который указывает p от начала). Дру-
    << "  ";          гими словами,  p-a есть индекс элемента, на
                      который указывает p.