Массивы указателей
В языке СИ элементы массивов могут иметь любой тип, и, в частности, могут быть
указателями на любой тип. Рассмотрим несколько примеров с использованием указателей.
Следующие объявления переменных
int a[]={10,11,12,13,14,};
int *p[]={a, a+1, a+2, a+2, a+3, a+4};
int **pp=p;
порождают программные объекты, представленные на схеме на рис.4.

При выполнении операции pp-p получим нулевое значение, так как ссылки pp и p равны и
указывают на начальный элемент массива указателей, связанного с указателем p ( на
элемент p[0]).
После выполнения операции pp+=2 схема изменится и примет вид, изображенный на рис.5.

Результатом выполнения вычитания pp-p будет 2, так как значение pp есть адрес третьего
элемента массива p. Ссылка *pp-a тоже дает значение 2, так как обращение *pp есть адрес
третьего элемента массива a, а обращение a есть адрес начального элемента массива a. При
обращении с помощью ссылки **pp получим 12 - это значение третьего элемента массива a.
Ссылка *pp++ даст значение четвертого элемента массива p т.е. адрес четвертого элемента
массива a.
Если считать, что pp=p, то обращение *++pp это значение первого элемента массива a
(т.е. значение 11), операция ++*pp изменит содержимое указателя p[0], таким образом, что
он станет равным значению адреса элемента a[1].
Сложные обращения раскрываются изнутри. Например обращение *(++(*pp)) можно разбить на
следующие действия: *pp дает значение начального элемента массива p[0], далее это
значение инкременируется ++(*p) в результате чего указатель p[0] станет равен значению
адреса элемента a[1], и последнее действие это выборка значения по полученному адресу,
т.е. значение 11.
В предыдущих примерах был использован одномерный массив, рассмотрим теперь пример с
многомерным массивом и указателями. Следующие объявления переменных
int a[3][3]={ { 11,12,13 },
{ 21,22,23 },
{ 31,32,33 } };
int *pa[3]={ a,a[1],a[2] };
int *p=a[0];
порождают в программе объекты представленные на схеме на рис.6.

Согласно этой схеме доступ к элементу a[0][0] получить по указателям a, p, pa при помощи
следующих ссылок: a[0][0], *a, **a[0], *p, **pa, *p[0].
Рассмотрим теперь пример с использованием строк символов. Объявления переменных
char *c[]={ "abs", "dx", "yes", "no" };
char **cp[]={ c+3, c+2 , c+1 , c };
char ***cpp=cp;
можно изобразить схемой представленной на рис.7.
