|
| ||||||||||||||||||
Паскаль для новичков (часть 7)Комбинированные типы (записи)Записи и селекторыАвтор: Владислав Демьянишин
Сегодня я поведаю о магических записях, которые нам достались в наследие от прадедов прошлого века.
Комбинированные типы, как и регулярные типы, представляют собой правило формирования составных типов. В отличие от массивов, записи позволяют объединить значения РАЗЛИЧНЫХ типов и поэтому являются, видимо, наиболее гибким механизмом построения данных.
Распространенным случаем является необходимость описать атрибуты (характеристики) некоторого объекта, представляемого и обрабатываемого в программе. Таким объектом может быть человек, некоторый вычислительный комплекс, письмо, посылаемое по почте и т.д. Во всех подобных случаях атрибуты объекта представляются значениями различных типов и поэтому для их описания не могут быть использованы массивы. Для описания объекта “человек” могут понадобиться, например, следующие характеристики:
1) фамилия, имя и отчество (символьные массивы или строки);
2) пол (перечислимый тип из двух значений);
3) индекс специальности (целое), и т.д.
Для представления такой разнородной, но логически связанной информации удобно использовать комбинированный тип (запись). Необходимо отметить, что в данном случае определенные компоненты комбинированного типа, ввиду их различной природы, не могут идентифицироваться порядковыми номерами (индексами), как в массивах; поэтому для обозначения компонент используются идентификаторы (имена). Таким образом, описание комбинированного типа представляет собой список описаний его элементов (которые называются также полями записи); каждое описание похоже на описание простой переменной. Список полей начинается служебным словом record и должен завершаться служебным словом end. Для примера, приведенного выше, описание комбинированного типа TPerson (человек) может выглядеть следующим образом:
type
TPerson = record
Name, SecondName, SurName : string [20];
Sex : ( Male, Female );
Speciality : word;
end;
Последняя точка с запятой перед словом end может быть опущена.
Итак, структура записи состоит из фиксированного числа компонент (полей), каждое из которых имеет собственное (уникальное в пределах этой записи) имя и ПРОИЗВОЛЬНЫЙ тип.
Следует помнить, что в записи не может быть двух и более полей с одинаковыми именами.
Имея в программе вышеприведенное описание, можно определить переменные данного типа, например:
var
Sasha, Masha : TPerson;
Доступ к элементам (полям) записей производится с помощью конструкции, называемой селектор записи и имеющий общий вид:
R . F
где R – переменная комбинированного типа, F – имя поля. Для переменных, введенных выше, допустимы следующие конструкции:
Sasha.Name := ‘Александр’;
Masha.Name := ‘Мария’;
Sasha.Sex := ‘Male’;
Masha.Sex := ‘Female’;
Masha.Speciality := Sasha.Speciality;
Таким образом записи могут состоять из нескольких полей.
Комбинированные типы можно использовать для построения более сложных структур, например, массивов, состоящих из записей, или записей, в состав которых, в свою очередь, входят записи. Первый случай может выглядеть так:
var
Group : array [1..10] of TPerson;
DataBase : file of TPerson;
j : integer;
Для переменной Group доступ к полям записей, составляющих этот массив, производится следующим образом:
Group[ j ].Sex := Female;
If Group[ j ].Name = ‘Борис’ then
Writeln( Group[ j ].SurName );
Рассмотрим теперь случай, когда в составе записи содержатся поля, имеющие также тип записи. Пусть для комбинированного типа TPerson необходимо хранить информацию о дате рождения человека. Эту информацию можно представить в виде трех полей в составе типа TPerson. Однако, логичнее для этого определить отдельный тип, так как в этом случае он может использоваться в описании других типов и переменных:
type
TDate = record
Month : ( Jan, Feb, Mar, Apr, May, June, July, Aug, Sept, Oct, Nov, Decem);
Day : 1..31;
Year : 1900..2100;
end;
Теперь этот тип можно использовать в записи TPerson:
type
TPerson = record
Name, SecondName, SurName : string [20];
Sex : ( Male, Female );
Speciality : word;
BirthDay : TDate;
end;
Доступ к полям из элемента BirthDay производится по общим правилам, например:
Sasha.BirthDay.Year := 1980;
Masha.BirthDay.Month := Feb;
Таким образом, при написании селектора необходимо помнить, что слева от символа “точка” всегда должна находится переменная типа запись (в наших примерах такими переменными являются Group[ j ], Sasha.BirthDay и т.д.), а справа – имя поля этой записи.
Для более компактной записи селекторов Pascal имеет специальный оператор присоединения (см. главу “Операторы. Оператор над записями”), позволяющий в ряде случаев опускать части селекторов.
Если в программе определен некоторый тип-запись, то он может использоваться наравне со всеми другими типами. Такой тип может употребляться для передачи параметров подпрограммам. Например, можно определить специальный тип для представления комплексных чисел как пары вещественных переменных (действительную и мнимую части комплексного числа):
type
TComplex = record
Re, Im : real;
end;
Далее можно с помощью процедур определить операции над комплексными числами (сложение, умножение, деление):
Procedure AddC ( C1, C2 : TComplex; var R : TComplex);
…
Procedure MultC ( C1, C2 : TComplex; var R : TComplex);
…
Procedure DivC ( C1, C2 : TComplex; var R : TComplex);
…
Записи с вариантамиПонятие записи в языке Pascal предусматривает одну не вполне тривиальную возможность. Довольно часто бывает необходимо в пределах одной записи иметь различную информацию в зависимости от конкретного значения некоторого поля.
Рассмотрим опять тип TPerson, содержащий информацию о человеке. Если в этом типе поле Sex (пол) имеет значение Male (мужской), то пусть необходимо предусмотреть такие поля:
1) время прохождения очередных военных сборов;
2) курит человек или нет;
Если же это поле имеет значение Female (женский), то хотелось бы иметь информацию…например, о цвете глаз.
В принципе, можно было бы в таком случае определить два отдельных комбинированных типа TPersonMale и TPersonFemale, в которых и задать соответствующие поля. Однако это сильно затруднит программирование общих для этих типов действий, поэтому в таких случаях используют записи с вариантами.
Любой комбинированный тип, помимо фиксированного списка полей, может содержать так называемую вариантную часть, предполагающую определение нескольких вариантов структуры этого типа. Это означает, что разные переменные, хотя и относятся к одному и тому же типу, могут иметь отличающуюся структуру. Различие может касаться как числа полей, так и их типа.
Вариантная часть содержит несколько альтернатив, в каждой из которых в круглых скобках задается список полей, присущих данному варианту. Списку предшествует метка, являющаяся конкретным значением поля, которое является критерием выбора вариантов. Перечисление альтернатив начинается с определения этого поля.
Теперь, основываясь на вышесказанном, перепишем тип TPerson на новый лад:
type
TPersonSex = ( Male, Female );
TPerson = record
Name, SecondName, SurName : string [20];
Speciality : word;
BirthDay : TDate;
case Sex : TPersonSex of
Male: ( Army : TDate; Smoking : boolean );
Female: ( EyesColor : ( Blue, Brown, Gray, Green ) );
end;
Хочу обратить ваше внимание на следующие обстоятельства:
1) Начало вариантной части отмечается служебным словом case; после определения поля-признака выбора вариантов записывается служебное слово of. Вариантная часть завершается служебным словом end вместе с завершением всей записи. Таким образом, в описании комбинированного типа может быть ТОЛЬКО ОДНА вариантная часть и она должна быть задана в КОНЦЕ записи.
2) Альтернативы вариантной части помечаются допустимыми значениями поля Sex; определение этого типа вынесено из фиксированной части и помещено в заголовке вариантной части. Поле, значения которого задают варианты, иногда называют дискриминантом записи.
3) Для того, чтобы поле Sex могло служить дискриминантом, его тип должен задаваться именем уже описанного типа. Поэтому перечислимый тип для этого поля пришлось описать отдельно, а в заголовке вариантной части использовать идентификатор TPersonSex.
4) Имена полей во всех вариантах должны быть РАЗЛИЧНЫ и отличаться от имен полей фиксированной части.
5) Для некоторых значений поля-дискриминанта вариант может отсутствовать. Тогда после двоеточия может стоять пустой список вида ( ).
Записи с вариантами представляют собой гибкий инструмент для представления информации, частично различающейся по своей структуре. Имея в программе вышеприведенный тип TPerson, можно объединить в логически связанные фрагменты манипуляции со всеми вариантами записей, например:
if Group[ j ].Sex = Male then
Group[ j ].Smoking := true
else Group[ j ].EyesColor := Gray;
Хочу отметить, что любой вариант, в свою очередь, может иметь свою вариантную часть, которая также должна располагаться в конце списка полей данного варианта.
При использовании вариантных записей необходимо учитывать следующие особенности:
1) Для размещения переменной комбинированного типа всегда отводится фиксированный объем памяти, причем если в записи есть варианты, то этот объем определяется по самому большому варианту. Таким образом, различные варианты одной записи как бы “накладываются” друг на друга в памяти, т.е. занимают одну и ту же область памяти.
2) Pascal не содержит никаких средств контроля за правильностью работы с вариантами записей. Так, логически бессмысленная последовательность присваиваний
Masha.Sex := Female;
Masha.Smoking := true;
будет выполнена, хотя поле Smoking не предусмотрено для значения Female в поле-дискриминанте Sex. Иными словами, в любое время возможен доступ ко всем полям во всех вариантах независимо от значения дискриминанта. Считается, что за соответствием текущего значения дискриминанта и доступа к полям записи должен следить программист. Это, безусловно, может привести к различного рода логическим ошибкам и является одним из слабых мест языка.
В предыдущем рассмотрении полагалось, что конкретный вариант выбирается в зависимости от текущего значения поля-дискриминанта. Помимо такого механизма, возможен более простой случай, когда необходимо организовать доступ к различным полям вариантов независимо от какого-либо условия.
Примером может служить схема доступа к регистрам процессора Intel 80x86. Известно, что к шестнадцатиразрядным регистрам общего назначения, именуемым обычно как AX, BX, CX, DX, возможен доступ и как к единым словам, и к отдельным их байтам; в последнем случае младшие и старшие части регистров обозначаются как AL,AH для регистра AX; и BL,BH для регистра BX и т.д., причем можно произвольным образом чередовать обращение как к регистру в целом, так и к его частям.
Turbo Pascal имеет возможность непосредственного обращения к аппаратным регистрам посредством процедур специального вида (см. главу “Системно-зависимые расширения”). Для этих целей предусмотрено следующее программное представление регистров:
type
Registers = record
case integer of
0: ( AX, BX, CX, DX, BP, SI, DI, DS, ES, Flags : word );
1: ( AL, AH, BL, BH, CL, CH, DL, DH : byte );
end;
Здесь дискриминант представляет собой только идентификатор (дискретного) типа, который в данном случае определяет не специальное поле, а просто задает тип констант, которыми будут “пронумерованы” варианты. Имея в виду, что для всех вариантов записи отводится общая область памяти, легко видеть, что память, отведенная для поля AX, будет совмещена с памятью для полей AL,AH, и т.д.
Продолжение следует…
© Владислав Демьянишин Вы находитесь на официальном сайте Владислава Демьянишина - разработчика игры Dune IV (Dune 4). На нашем сайте Вы можете бесплатно скачать игры Dune IV (Dune 4), Battle City (Танчики с Dendy/Nintendo), читы к играм и многое другое. Также Вы можете скачать бесплатно программы и полезные утилиты. Все программы чистые, т.е. не содержат вирусов и иного вредоносного ПО.
Среди доступных программ есть мобильная читалка книг, менеджер переноса файлов с фото- и видеокамер на компьютер, текстовый редактор, WYSIWYG редактор, 3D аниматор, GIF аниматор, AVI аниматор, пакетный конвертор изображений, редактор электрических схем, программа для скриншотов, диспетчер тем рабочего стола и другие.
На нашем сайте можно не только бесплатно скачать игры, но и документацию и книги по программированию на MIDLetPascal, Turbo Pascal 6, Turbo Pascal 7, Borland Pascal, по программированию устройств Sound Blaster, Adlib, VESA BIOS, справочник Norton Guide и много другой полезной информации для программистов, включая примеры решения реальных задач по созданию резидентных программ.
Журнал > Программирование > Паскаль для новичков (Turbo Pascal, Assembler) > Паскаль для новичков (часть 7): Комбинированные типы (записи)
| |||||||||||||||||||
|
|||||||||||||||||||