Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

delphi / 08.записи

.doc
Скачиваний:
33
Добавлен:
26.03.2016
Размер:
71.17 Кб
Скачать

ЛЕКЦИЯ 8

Записи.

Записи

Продолжая изучение структурированных типов данных, переходим к записям.

Как и массивы, записи являются структурами прямого доступа, однако, в отличие от массивов, могут хранить элементы, относящиеся к разным типам данных.

Таким образом, запись - это вектор, компоненты которого (поля) могут относиться к разным типам данных.

Описание записей

В разделе var переменную типа запись описывают так:

var <имя_записи>: record <имя_поля1>: <тип_поля1>;

[<имя_поля2>: <тип_поля2>;]

[...]

end;

Имена полей должны подчиняться общим правилам построения идентификаторов. Повторение имен полей внутри одной записи не допускается.

Замечание: Имена полей могут совпадать с именами других переменных, поскольку на самом деле являются составными:

<имя_записи>.<имя_поля>.

Поэтому можно записать:

var x: real;

r: record x: real;

y: real

end;

Поля могут относиться к любым стандартным (базовым или сконструированным) или определенным ранее типам, даже к файловому или процедурному (см. лекцию 6).

Если несколько подряд идущих полей принадлежат к одному типу данных, их описания можно объединить:

var <имя_записи>: record <имя_поля1>,_,<имя_поляN>: <тип_полей>;

<имя_поляS>: <тип_поляS>;

...

end;

Например:

var zap1: record x,y: real;

i,j,k: integer;

flag: boolean;

s: set of 'a'..'z';

a: array[1..100] of byte;

data: record day:1..31;

month: 1..12;

year: 1900..2100;

end;

end;

Эта запись содержит 9 полей, три из которых сами являются составными.

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

var tabl: array[1..100] of zap1;

Задание записей константой

Как и массивы, записи не могут быть заданы неименованной или нетипизированной константой.

Для того чтобы задать запись типизированной константой, следует вначале описать соответствующий тип в разделе type, а затем воспользоваться им в разделе const:

type <имя_типа> = record <имя_поля1>: <тип_поля1>;

[<имя_поля2>: <тип_поля2>;]

[...]

end;

const <имя_константы>: <имя_типа> = <начальное_значение>;

Начальное значение для переменной типа запись задается перечислением в круглых скобках начальных значений для всех полей (соответствующих типов!) с обязательным указанием имени задаваемого поля. Имя поля от его начального значения отделяется двоеточием, значения соседних полей разделяются точкой с запятой:

(<имя_поля1>: <значение_поля1>; _; <имя_поляN>: <значение_поляN>);

Например:

type data = record day: 1..31;

month: 1..12;

year: 1900..2100;

end;

const my_birthday: data = (day:17; month:3; year:2004);

Можно, конечно, не описывать тип константы отдельно, а объединить оба определения:

const my_birthday: record day: 1..31;

month: 1..12;

year: 1900..2100;

end;

= (day:17; month:3; year:2004);

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

type family = (mother, father, child);

const birthdays : array[family] of data

= ((day: 8; month: 3; year: 1975),

(day: 23; month: 2; year: 1970),

(day: 1; month: 9; year: 2000));

Доступ к полям

Обратиться к полю записи можно следующим способом:

<имя_записи>.<имя_поля>

Например:

month:= my_birthday.month +1;

Как уже было упомянуто, коллизий между переменной с именем month и полем записи my_birthday.month не возникает.

Доступ к полю двумерной таблицы осуществляется аналогичным образом (жирные скобки являются обязательным элементом синтаксиса):

<имя_таблицы>[<индекс>].<имя_поля>

Эту запись можно трактовать так:

(<имя_таблицы>[<индекс>]).<имя_поля>

Например:

birthdays[mother].day := 9;

Оперирование несколькими полями

Если программе предстоит несколько раз подряд обращаться к полям одной и той же записи, может оказаться неудобным записывать это обращение полностью:

my_birthday.day:= 17;

my_birthday.month:= 3;

my_birthday.year:= 2004;

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

with <имя_записи> do

begin <операторы>

{имена полей здесь используются как <имя_поля>,

а не как <имя_записи>.<имя_поля>}

end;

Например:

with my_birthday do

begin day:= 17;

month:= 3;

year:= 2004;

end;

Замечание. Для того чтобы внутри оператора with можно было обратиться не к полю записи, а к глобальной переменной с таким же именем, перед этой переменной нужно указать (через точку) имя программы:

<имя_программы>.<имя_переменной>.

Например:

with my_birthday do

begin day:= 17;

month:= 3; {поле записи birthday.month}

year:= 2004;

programma.month:= 5; {глобальная переменная month}

end;

Вложенные операторы with

Если возникает необходимость расположить один оператор with внутри другого, то любую переменную (если перед ней явно не указано имя записи), находящуюся под внутренним оператором with, компилятор пытается интерпретировать в такой последовательности:

  1. если во внутренней записи есть поле с искомым именем, то поиск заканчивается;

  2. если во внутренней записи поля с таким именем нет, то поиск производится среди полей внешней записи (если вложенных операторов with больше, чем два, то поиск ведется последовательно во всех задействованных записях в направлении "изнутри наружу");

  3. если среди полей всех вложенных записей нет искомого идентификатора, компилятор считает его глобальной переменной.

Например:

type date = record day: 1..31;

month: 1..12;

year: 1900..2005;

end;

student = record name: string[100];

year: 1950..2005; {год поступления}

gruppa: string[5];

birth: date;

end;

var ivanov: student;

begin

...

with ivanov do

begin

...

with birth do

begin

...

year:= 2001; {birth.year}

gruppa:= 'IT01'; {ivanov.gruppa}

...

end;

...

end;

end;

Запись с вариантной частью

Если заранее известно, что в массиве записей (таблице) некоторые поля могут оставаться пустыми (наборы пустых полей могут быть разными для разных записей), то вполне понятно желание как-то сократить неиспользуемый, но занимаемый объем памяти.

Специально для таких случаев существуют записи с вариантной частью.

Описание записи с вариантной частью

В разделе var запись с вариантной частью описывают так:

var <имя_записи>: record <поле1>: <тип1>;

[<поле2>: <тип2>;]

[...]

case <поле_переключатель>: <тип> of

<варианты1>: (<поле3>: <тип3>;

<поле4>: <тип4>;

...);

<варианты2>: (<поле5>: <тип5>;

<поле6>: <тип6>;

...);

[...]

end;

Невариантная часть записи (до ключевого слова case) подчиняется тем же правилам, что и обычная запись. Вообще говоря, невариантная часть может и вовсе отсутствовать.

Вариантная часть начинается зарезервированным словом case, после которого указывается то поле записи, которое в дальнейшем будет служить переключателем. Как и в случае обычного оператора case, переключатель обязан принадлежать к одному из перечислимых типов данных (см. лекцию 3 «Ввод/вывод. Операторы»). Список вариантов может быть константой, диапазоном или объединением нескольких констант или диапазонов. Набор полей, которые должны быть включены в структуру записи, если выполнился соответствующий вариант, заключается в круглые скобки.

Пример. Для того чтобы описать содержимое библиотеки, необходима следующая информация:

Для книг

Для газет

Для журналов

Автор

Название

Название

Название

Дата выхода (день, месяц, год)

Год и месяц издания

Год издания

Издательство

Номер

Издательство

Издательство

Графы "Название" и "Издательство" являются общими для всех трех вариантов, а остальные поля зависят от типа печатного издания. Для реализации этой структуры воспользуемся записью с вариантной частью:

type biblio = record

name,publisher: string[20];

case item: char of

'b': (author: string[20]; year: 0..2004);

'n': (data: date);

'm': (year: 1700..2004;

month: 1..12;

number: integer);

end;

В зависимости от значения поля item, в записи будет содержаться либо 4, либо 5, либо 6 полей.

Механизм использования записи с вариантной частью

Количество байтов, выделяемых компилятором под запись с вариантной частью, определяется самым "длинным" ее вариантом. Более "короткие" наборы полей из других вариантов занимают лишь некоторую часть выделяемой памяти.

В приведенном выше примере самым "длинным" является вариант 'b': для него требуется 23 байта (21 байт для строки и 2 байта для целого числа). Для вариантов 'n' и 'm' требуется 4 и 5 байт соответственно (см. таблицу).

name, publisher

item

Вариантная часть

'b'

author

year

'n'

data

'm'

year

month

number

'b'

author

year