В самом деле, если задана последовательность операций выделения составляющих типов данных, то по ней можно восстановить симметричную ей последовательность определения типов. Так в выражении
A.name[k]
мы несомненно имеем дело со структурированной переменной (операция "." ), элементом которой является массив name (операция [] ). Такой способ задания типа переменной в окружении (контексте) операций выделения составляющего типа будем называть контекстным определением типа. В нем могут использоваться только следующие операции:
- [] -элемент массива;
- * -косвенное обращение по указателю;
-() -вызов функции;
- () -круглые скобки, устанавливающие последовательность выполнения операций.
Заметим, что операции ("." и ->), соответствующие структуре, здесь не упоминаются. Это значит, что структурированный тип данных может быть определен только явно. Это связано с тем, что структура конструируется из разнородных элементов, а остальные типы данных строятся на основе однородных.
Контекстное определение типа понимается следующим образом. Если взять переменную некоторого неизвестного пока типа данных и выполнить над ней последовательность операций выделения составляющих типов данных, то в результате получится переменная того типа данных, который указан в левой части определения. При этом должны соблюдаться приоритеты выполнения операций, а для их изменения использоваться круглые скобки. Заданная последовательность выполнения операций дает, таким образом, обратную последовательность определения типов. Попытаемся с использованием этих правил расшифровать ряд контекстов.
int *p;
Переменная, при косвенном обращении к которой получается целое -указатель на целое.
char *p[];
Переменная, которая является массивом, при косвенном обращении к элементу которого получаем указатель на символ (строку) - массив указателей на символы (строки).
char (*p)[][80];
Переменная, при косвенном обращении к которой получается двумерный массив, состоящий из массивов по 80 символов - указатель на двумерный массив строк по 80 символов в строке.