Запись(record) – наиболее общий сложный тип данных. Переменная типа "запись" объединяет данные разного типа. В этом принципиальное отличие записи от массива - все элементы массива имеют один и тот же тип. Необходимость в таком типе данных вытекает из многих программистских задач. Скажем, нам нужно спроектировать базу данных для хранения информации о сотрудниках фирмы. Для каждого сотрудника надо запомнить его фамилию (текстовая строка), год рождения (целое число), семейное положение (два варианта: женат/замужем – холост/не замужем). Хранение всех этих данных в отдельных переменных типа STRING, WORD и BOOLEAN соответственно – прямой путь к путанице. Гораздо удобнее, когда все данные на одного сотрудника хранятся в одной переменной. Вот тут-то нам и понадобятся записи. Кстати, само название "запись" происходит оттого, что чаще всего переменные такого типа записываются в файлы данных.
Рассмотрим на примере тип данных "запись":
TYPE TDate = RECORD
day: 1..31;
month:1..12;
year:1900..2100;
END;
Представленный здесь тип данных Tdate предназначен для хранения календарных дат. Запись состоит из полей. Каждое поле имеет свое уникальное имя (day, month, year) и для каждого поля указывается его собственный тип данных. Для полей, в которых хранятся номера дней в месяце и месяцев в году, правильным будет применение типов-диапазонов, что позволит сразу выявлять ошибочные даты типа 32.13.2002.
А в этом примере создается структура данных для хранения координат точки:
TYPE TPoint = RECORD
x:REAL;
y: REAL;
END;
Как видно, поля могут иметь и одинаковый тип – запись остается записью.
Тот факт, что каждое поле имеет сове уникальное имя, приводит к невозможности перебора полей записи в цикле. В отличие от массива, по полям записи нельзя пройтись в цикле – нужно знать имя каждого поля. Для обращения к полю по имени название поля отделяется от имени переменной-записи точкой:
TYPE TA=RECORD
x:REAL;
y:BYTE;
END;
VAR A:TA;
…
A.x:=10.0;
A.y:=5;
Полем записи, в свою очередь, может быть другая запись! Возможен следующий вариант:
TYPE TA1=RECORD
a:REAL;
b:BYTE;
END;
TA2=RECORD
c:TA1;
d:WORD;
END;
VAR x:TA2;
…
Label1.Caption:=x.c.a;
У вложенных записейдля обращения к нужному полю может потребоваться несколько точек.
Еще более сложная структура – записи с вариантами. Внутри записи с вариантами создается несколько наборов полей и специальное поле-селектор. Значение селектора определяет, какой набор полей доступен в настоящий момент.
Как известно, координаты точек на плоскости можно выражать в привычной декартовой системе координат (Х и Y), а можно – в полярной (Рис. 3.1). В полярной системе положение точки задается длиной и углом поворота отрезка, соединяющего эту точку с началом координат.

Рис. 6.1. Полярная система координат.
Создадим структуру данных, которая сможет хранить координаты точек как в декартовой, так и в полярной системах:
TYPE TCoord=(Cartesian, polar);
TCrd=RECORD
CASE kind:TCoord OF
Cartesian: x,y: REAL;
polar: r, phi: REAL;
END
END;
Для различения систем координат вводится перечислимый тип данных Tcoord, содержащий два значения: Cartesian для декартовых координат и polar – для полярных. Поле-селектор kind показывает, что, если в kind записано значение Cartesian, то в записи окажутся доступными поля x,y, а если polar – то поля r, phi.
Попробуем вычислить расстояние между двумя точками, причем координаты каждой из точек могут быть заданы как в полярной, так и декартовой системе. Вспомнив геометрию и формулы преобразования координат, получим следующий код:
CASE a.kind OF
Cartesian: CASE b.kind OF
Cartesian: d:=sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));
Polar: d:=sqrt(sqr(a.x-b.r*cos(b.phi)+
sqr(a.y-b.r*sin(b.phi));
END;
Polar: CASE b.kind OF
Cartesian: d:=sqrt(sqr(a.r*cos(a.phi)- b.x)+sqr(a.r*sin(.phi)-b.y));
Polar: d:=sqrt(a.r+sqr(b.r)-2*a.r*cos(a.phi-b.phi))
END;
В записях с вариантами часть полей может существовать всегда, независимо от значения поля-селектора. Например, мы создаем структуру данных для хранения информации о студенте или сотруднике университета. Очевидно, и студент, и профессор имеют имя и возраст. В то же время для студента важен номер его учебной группы, а для профессора – номер кафедры, на которой он работает. Записывается это так:
TYPE Tposition=(student, professor);
Tperson=RECORD
name: STRING;
age: BYTE;
CASE position:Tposition OF
student: group:STRING;
professor: departmentNo: BYTE;
END
END;
Поля name, age, position есть всегда. Поле group есть, если position=student. Поле DepartmentNo есть, если position=professor.
Для повышения эффективности работы с записямив Паскале (в отличие от большинства других языков, в частности, от языка С) предусмотрен очень удобный оператор WITH. Смысл действия оператора WITH заключается в том, чтобы не писать много раз имя переменной-записи при обращении к ее полям. Например, мы хотим занести дату в переменную рассмотренного выше типа Tdate. Придется написать следующее:
a.Date:=28;
a.Month:=2;
a.Year:=2002;
Такая программа не только громоздка, но и медлительна: в каждой строчке для обращения к переменной а ее адрес вычисляется заново. Вот как надо было написать этот фрагмент:
WITH a DO
BEGIN
Date:=28;
Month:=2;
Year:=2002
END;
Между BEGIN и END действует соглашение: все упоминаемые поля считаются полямипеременной a, указанной в операторе WITH. Адрес переменной a теперь вычисляется только один раз, что ускоряет работу программы.
Записи целиком нельзя ввести с клавиатуры или вывести на экран. Приходится делать это по полям:
VAR d:Tdate;
…
WITH d DO
BEGIN
day:=StrToInt(Edit1.Text);
month:=StrToInt(Edit1.Text);
year:=StrToInt(Edit1.Text)
END;
Гораздо чаще приходится сохранять записи в файл. Если создать файл данных, состоящий из записей, то их в него можно будет записывать целиком, а не по полям:
TYPE Ta=RECORD…
VAR a:TA; f:FILE OF Ta;
…
AssignFile(f,’abc.dbf’);
Rewrite(f);
Write(f,a)