Типы массивов позволяют работать с регулярными структурами данных, каждый элемент которых относится к одному и тому же базовому типу. Существует другая разновидность составных конструируемых типов данных, которые позволяют определять и использовать нерегулярные структуры данных, элементы которых могут относиться к разным встроенным или явно определенным типам данных. Собирательно типы этой разновидности называются типами записи или структурными типами.
К счастью, общее понятие типа записи практически одинаково в сильно и слабо типизированных языках (с некоторыми оговорками, которые мы отложим до раздела, посвященного указателям). Идея состоит в том, что в определении структурного типа перечисляются имена полей записи, и для каждого поля указывается его тип данных. После этого можно определять переменные вновь сконструированного типа и производить доступ к полям переменных. На языке Модула-2 определение структурного типа "комплексные числа" могло бы выглядеть следующим образом:
Пример 14.1. На языке Модула-2 определение структурного типа
type complex = record re: real; im: real end
Вот аналог этого определения на языке Си:
После этого можно объявить переменную x комплексного типа (var x: complex; или struct complex x;) и обращаться к действительной и мнимой частям x с помощью конструкции x.re (или x.im соответственно). Поскольку размер составного значения структурного типа точно специфицирован, допускается присваивание таких значений, а также функции, вырабатывающие структурные значения и т.п.
Замечание: мы все же вынуждены отметить одну (не связанную с указателями) особенность использования структурных типов в языках линии Си, отражающую, на наш взгляд, слабость типизации. Кроме корректного с точки зрения типизации отдельного определения именованного структурного типа с использованием затем этого имени при объявлении переменных, можно определять безымянный структурный тип с одновременным объявлением переменных. Например, в языке Си допустимы следующие объявления переменных x, y и z:
Пример 14.3. На языке Си определение переменных
struct { float re; float im; } x, y; struct { float r; float i; } z;
После этих объявлений понятно, что переменные x и y имеют один и тот же тип и что, в частности, допустимо присваивание x = y. Но чтобы понять, что на самом деле таким же типом обладает и переменная z, приходится решать громоздкую задачу определения структурной эквивалентности типов, возникновения которой обычно стремятся избежать в сильно типизированных языках программирования.