18. Записи

Записи - это объекты, объединяющие данные разных типов. Записи состоят из полей. Описание записи имеет вид:

RECORD описания полей END; где описания полей - обычные описания переменных. Имена полей могут совпа­дать с именами других переменных, описанных в программе, и с именами полей других записей. Поля могут иметь любой тип, в том числе могут быть записями. Опишем несколько записей:

VAR c : RECORD

Name : STRING[40]; Phone : STRING[20];

END;

TYPE CoordType = RECORD

x,y : Integer;

END;

VAR a : ARRAY[1..3] OF CoordType;

TYPE PointType = RECORD

c      : CoordType;

Color : Word; END;

VAR T : PointType;

Чтобы обратиться в программе к полю записи, нужно использовать состав­ное имя: имя записи.имя поля, например: c.Name[25] , a[2].x , T.c.y. Поэтому имена полей и не обязаны быть уникальными. Поля записей можно использовать точно так же, как и простые переменные того же типа. Однотипные записи мож­но присваивать друг другу. Иногда полные имена полей бывают довольно гро­моздкими и усложняют текст программы, этого можно избежать, используя опе­ратор WITH, который записывается в виде:

WITH имя записи DO оператор/блок

Внутри оператора WITH можно использовать простые имена полей данной записи. Однако будьте осторожны: если имена полей не уникальны, любые име­на, совпадающие с именем какого-нибудь поля записи, внутри оператора WITH всегда интерпретируются как имена полей, хотя вы, возможно, хотели использо­вать здесь имя простой переменной. Типизированные константы - записи - до­пускаются и инициализируются в виде:

CONST имя:тип=(имя поля:значение; имя поля:значение; ...);

Опишем, например, константу типа PoinType :

CONST p : PointType = (c:(x:100; y:20); Color:15); Выведем эту константу:

WRITELN(p.c.x,p.c.y,p.Color);

или

WITH p DO WRITELN(c.x,c.y,Color);

или

WITH p.c DO WRITELN(x,y,p.Color);

Теперь решим более содержательную задачу : даны n точек на плоскости, каждая из которых окрашена в свой цвет, упорядочить точки по цвету, а точки одного цвета - по неубыванию радиус-вектора. Будем считать, что n не превос­ходит 100.

TYPE CoordType = RECORD x,y : REAL; END;

PointType = RECORD XY:CoordType; Color:Word; R:Real; END; VAR p : ARRAY[1..100] OF PointType; Min : PointType; n,i,j,Num : Byte; BEGIN WRITE('Введите количество точек '); READ(n); FOR i:=1 TO n DO BEGIN

WRITE('Введите 'Д:2,'-ю точку '); WITH p[i] DO READ(XY.x,XY.y,Color);

END;

FOR i:=1 TO n DO WITH p[i] DO R:=Sqrt(Sqr(XY.x)+Sqr(XY.y)); FOR i:=1 TO n-1 DO BEGIN

Min:=p[i]; Num:=i;

FOR j:=i+1 TO n DO WITH p[j] DO

IF (Color<Min.Color) OR (Color=Min.Color) AND (R<Min.R)

THEN BEGIN

Min:=p[j]; Num:=j; END;

IF Num<>i THEN BEGIN p[Num]:=p[i]; p[i]:=Min; END;

END;

WRITELN('Упорядоченное множество точек :');

FOR i:=1 TO n DO WITH p[i] DO WRITELN(XY.x :10:1,XY.y: 10:1,Color:5);

END.

В Паскале записи могут содержать так называемые вариантные поля, в кото­рых могут храниться одновременно (в одном и том же месте памяти) данные разных типов. Описание вариантного поля имеет вид:

CASE тип OF

константа 1 : (описание поля); константа 2 : (описание поля);

Здесь тип - любой порядковый тип (фактически компилятор Turbo Pascal^ никак не использует этот тип, поэтому можно всегда писать, например, Byte); кон­станта 1, константа 2 и т.д. - это любые константы порядкового типа (их зна­чение также не используется компилятором). Запись может иметь только одно вариантное поле, и это поле должно быть последним. Память для размещения вариантного поля отводится по самому большому варианту. Приведем пример использования такой записи: VAR z : RECORD x,y : Integer;

CASE Byte OF

0      : (L : LongInt);

TRUE : (W : ARRAY[0..1] OF WORD);

'D'       : (B0: Byte; B : ARRAY[0..3] OF Byte);

-22    : (S : STRING);

END;

BEGIN z.S:='12345'; WITH z DO WRITELN(B0,B[0]:3,B[1]:3,B[2]:3,B[3]:3,' ',S); z.L:=1000; WITH z DO WRITELN(L,' ',W[0],' ',W[1]);

END.

Программа вывела : 5 49 50 51 52 12345

1000 1000 0

Действительно, в первом байте вариантного поля первоначально хранилась длина строки - 5, а в следующих четырех - символы '1','2','3','4', т.е. байты 49-52. После выполнения второго оператора присваивания в младшем слове оказалось число 1000, а в старшем - 0. Фактически вариантное поле занимает 256 байт па­мяти, но при обращении к нему по именам L и W нам доступны первые 4 байта, а при обращении по имени B - первые 5 байт.

Таким образом, вариантное поле - это некоторый участок памяти, к которому можно обращаться с разными именами, каждое имя однозначно связано с опре­деленным типом. Значение, хранящееся в этом участке памяти, конечно, в каж­дый момент времени совершенно определенное и не зависит от способа обраще­ния, но интерпретация этой последовательности байтов зависит от используе­мого типа. Сам способ описания вариантного поля, который в нашем примере имеет вполне "дикий" вид (это сделано намеренно), остался в языке Паскаль от его ранних диалектов, в которых все конструкции имели совершенно определен­ный смысл. Сейчас компилятору они не нужны, но тем не менее их необходимо записывать, чтобы не нарушать синтаксис языка.