Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Программирование лекции.doc
Скачиваний:
49
Добавлен:
12.11.2019
Размер:
5.53 Mб
Скачать

6.Записи

Запись (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), а можно – в полярной (Рис. 6 .12). В полярной системе положение точки задается длиной и углом поворота отрезка, соединяющего эту точку с началом координат.

Рис. 6.12. Полярная система координат.

Создадим структуру данных, которая сможет хранить координаты точек как в декартовой, так и в полярной системах:

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)