9789

Комбинированные типы (записи)

Контрольная

Информатика, кибернетика и программирование

Комбинированные типы (записи) Записи и селекторы Комбинированные типы, как и регулярные типы, представляют собой правило формирования составных типов. В отличие от массивов, записи позволяют объединять значения РАЗЛИЧНЫХ типов и поэтому являются, ви...

Русский

2013-03-17

79.5 KB

16 чел.

Комбинированные типы (записи)

Записи и селекторы

Комбинированные типы, как и регулярные типы, представляют собой правило формирования составных типов. В отличие от массивов, записи позволяют объединять значения РАЗЛИЧНЫХ типов и поэтому являются, видимо, наиболее гибким механизмом построения данных.

Распространенным случаем является необходимость описать атрибуты (характеристики) некоторого объекта, представляемого и обрабатываемого в программе. Таким объектом может быть человек, некоторый вычислительный комплекс, письмо, посылаемое по почте и т.д. Во всех подобных случаях атрибуты объекта представляются значениями различных типов и поэтому для их описания не могут быть использованы массивы. Для описания объекта "человек" могут понадобиться, например, следующие характеристики:

• фамилия, имя и отчество (символьные массивы или строки);

• пол (перечислимый тип из двух значений);

• индекс специальности (целое), и т.д.

Для представления такой разнородной, но логически связанной информации удобно использовать комбинированный тип. Необходимо отметить, что в данном случае отдельные компоненты комбинированного типа, ввиду их различной природы, не могут идентифицироваться порядковыми номерами (индексами), как в массивах; поэтому для обозначения компонент используются идентификаторы. Таким образом, описание комбинированного типа представляет собой список описаний его элементов (которые называются также полями записи); каждое описание похоже на описание простой переменной. Список полей начинается служебным словом record и должен завершаться служебным словом end. Для примера, приведенного выше, описание комбинированного типа Person (человек) может выглядеть следующим образом:

type

Person = record

   Name, SecondName, SurName : string[20];

Pol : ( Male, Female );

Speciality : word;

 end;

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

Итак, структура записи состоит из фиксированного числа компонент (полей), каждое из которых имеет собственное (уникальное в пределах записи) имя и ПРОИЗВОЛЬНЫЙ тип. Следует подчеркнуть, что уникальность имен полей требуется только внутри записи; идентификаторы полей могут совпадать с другими идентификаторами текущего блока, а также с идентификаторами полей в других записях. В данном случае конфликта имен не возникает, так как идентификатор поля всегда выступает в программе в паре с переменной-записью (см. далее).

Имея в программе вышеприведенное описание, можно определить переменные данного типа, например:

var Sasha, Masha : Person;

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

R . F

где R - переменная комбинированного типа, F - идентификатор поля. Для переменных, введенных выше, допустимы следующие конструкции:

Sasha.Name := 'Александр';

Masha.Name := 'Мария';

Sasha.Pol : = Male;

Masha.Pol := Female;

Masha.Speciality := Sasha.Speciality;

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

var Group : array[1..10] of Person;

DataBase : file of Person;

Для переменной Group доступ к полям записей, составляющих этот массив, производится следующим образом:

Group[i].Pol := Female;

if Group[j].Name='Борис'

then WriteLn(Group[j].SurName) ;

Рассмотрим теперь случай, когда в составе записи содержатся поля, имеющие также тип записи. Пусть для комбинированного типа Person необходимо хранить информацию о дате рождения человека. Эту информацию можно представить в виде трех полей в составе типа Person. Однако, логичнее для этого определить отдельный тип, так как в этом случае он может использоваться в описании других типов и переменных:

type

  Date = record

   Month : (Jan,Feb,Mar,Apr,May,June,July,

     Aug,Sept,Oct,Nov,Decem);

   Day : 1..31;

   Year : 1900..2100

  end;

Теперь введенный таким образом тип можно использовать в записи Person:

type

Person = record

   Name,SecondName,SurName : string[20];

   Pol : ( Male, Female );

    Speciality : word;

    BirthDay : Date

 end;

Доступ к полям из элемента BirthDay производится по общим правилам, например:

Sasha.BirthDay.Year := 1983;

Masha.BirthDay.Month := Feb;

Таким образом, при записи селектора необходимо помнить, что слева от символа "точка" всегда должна находиться переменная типа запись (в наших примерах переменными типа запись являются Group[i].Sasha.BirthDay и т.д.), а справа - идентификатор поля этой записи.

Для более компактной записи селекторов Pascal имеет специальный оператор присоединения, позволяющий в ряде случаев опускать левые части селекторов. Этот оператор будет подробно описан далее.

Будучи определенным в программе, некоторый комбинированный тип может использоваться наравне со всеми другими типами. Кроме образования с его участием других типов, комбинированный тип может употребляться для спецификации параметров подпрограмм (см. лекцию «Подпрограммы»). Например, можно определить специальный тип для представления комплексных чисел как пары вещественных переменных (действительную и мнимую части комплексного числа):

type

Complex = record

Re, Im : real

end;

Далее можно с помощью процедур определить операции над комплексными числами (сложение, умножение, деление):

procedure AddC ( C1, C2 : Complex, var R : Complex );

procedure MultC ( C1, C2 : Complex, var R : Complex );

procedure DivC ( C1, C2 : Complex; var R : Complex );

Записи с вариантами

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

Рассмотрим опять тип Person, содержащий информацию о человеке. Если в этом типе поле Pol (пол) имеет значение Male (мужской), то пусть необходимо предусмотреть такие поля:

• время прохождения очередных военных сборов;

• курит человек или нет.

Если же это поле имеет значение Female (женский), то хотелось бы иметь информацию... например, о цвете глаз.

В принципе, можно было бы в таком случае определить два отдельных комбинированных типа PersonMale и PersonFemale, в которых и задать соответствующие поля.

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

Любой комбинированный тип, помимо фиксированного списка полей, может содержать так называемую вариантную часть, предполагающую определение нескольких вариантов структуры этого типа. Это означает, что разные переменные, хотя и относятся к одному и тому же типу, могут иметь отличающуюся структуру. Различие может касаться как числа компонент, так и их типа.

Вариантная часть содержит несколько альтернатив, в каждой из которых в круглых скобках задается список полей, присущих данному варианту. Списку предшествует метка, являющаяся конкретным значением поля, которое является критерием выбора вариантов. Перечисление альтернатив начинается с определения этого поля.

В приведенной выше ситуации с типом Person запись с вариантами может иметь следующий вид:

type

 PersonPol = ( Male, Female ) ;

 Person = record

   Name, SecondName, SurName : string[20];

   Speciality : word;

   BirthDay : Date;

     case Pol : PersonPol of

   Male : ( Army : Date;

     Smoking : boolean );

   Female : ( EyesColor: (Blue, Brown, Gray,

      Green) )

     end;

Обратите внимание на следующие обстоятельства:

  1.  Начало вариантной части отмечается служебным словом сазе; после определения поля-признака выбора вариантов записывается служебное слово of. Вариантная часть завершается служебным словом end вместе с завершением всей записи. Таким образом, в определении комбинированного типа может быть ТОЛЬКО ОДНА вариантная часть и она должна быть задана В КОНЦЕ записи.
  2.  Альтернативы вариантной части помечаются допустимыми значениями поля Pol; определение этого поля вынесено из фиксированной части и помещено в заголовке вариантной части. Поле, значения которого задают варианты, иногда называют дискриминантом записи.
  3.  Для того, чтобы поле Pol могло служить дискриминантом, его тип должен задаваться идентификатором. Поэтому перечислимый тип для этого поля пришлось определить отдельно, а в заголовке вариантной части использовать идентификатор PersonPol.
  4.  Идентификаторы полей во всех вариантах должны быть РАЗЛИЧНЫ и отличаться от идентификаторов полей фиксированной части.
  5.  Для некоторых значений поля-дискриминанта вариант может отсутствовать. Тогда после двоеточия может стоять пустой список вида ( ).

Записи с вариантами представляют собой гибкий инструмент для представления информации, частично различающейся по своей структуре. Имея в программе вышеприведенный тип Person, можно объединить в логически связанные фрагменты манипуляции со всеми вариантами записей, например:

if Group[i].Pol = Male then

 Group[i].Smoking := true

else

 Group[i].EyesColor := Gray;

Дополнительно следует отметить, что любой вариант, в свою очередь, может иметь свою вариантную часть, которая также должна располагаться в конце списка полей данного варианта.

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

  1.  Для размещения переменной комбинированного типа всегда отводится фиксированный объем памяти, причем если в записи есть варианты, то этот объем определяется по самому большому варианту. Таким образом, различные варианты одной записи как бы "накладываются" друг на друга в памяти, то есть занимают одну и ту же область.
  2.  Pascal не содержит никаких средств контроля за правильностью работы с вариантами записей. Так, логически бессмысленная последовательность присваиваний

Masha.Pol := Female;

Masha.Smoking := true;

будет выполнена, хотя поле Smoking не предусмотрено для значения Female в поле-дискриминанте Pol. Иными словами, в любое время возможен доступ ко всем полям во всех вариантах безотносительно значения дискриминанта. Считается, что за соответствием текущего значения дискриминанта и доступа к полям записи должен следить программист. Это, безусловно, может привести к различного рода логическим ошибкам и является одним из слабых мест языка.

В предыдущем рассмотрении полагалось, что конкретный вариант выбирается в зависимости от текущего значения поля-дискриминанта. Помимо такого механизма, возможен более простой случай, когда необходимо организовать доступ к различным полям вариантов безотносительно какого-либо условия.

Примером может служить схема доступа к регистрам процессора Intel 80x86. Известно, что к шестнадцатиразрядным регистрам общего назначения, именуемым обычно как АХ, ВХ, СХ, DX, возможен доступ и как к единым словам, и к отдельным их байтам; в последнем случае младшие и старшие части регистров обозначаются как АL,АН для регистра AX; BL,BH для регистра ВХ и т.д., причем можно произвольным образом чередовать обращение как к регистру в целом, так и к его частям.

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

type

 Registers = record

  case integer of

 0:(AX,HX,CX,DX,HP,SI,DI,DS,ES,Flags:word) ;

  1:(AL,AH,BL,BH,CL,CH,DL,DH :byte)

   end;

Здесь дискриминант представляет собой только идентификатор (дискретного) типа, который в данном случае определяет не специальное поле, а просто задает тип констант, которыми будут "пронумерованы" варианты. Имея в виду, что для всех вариантов записи отводится общая область, легко видеть, что память, отведенная для поля АХ, будет совмещена с памятью для полей AL, АН, и т.д.

Оператор над записями

Этот оператор предназначен для более наглядной и эффективной организации работы с значениями комбинированных типов. Если в некотором месте программы сосредоточено несколько операторов, манипулирующих с полями определенной записи, то эта часть программы будет выглядеть достаточно громоздко из-за необходимости обозначать каждое обращение к полю записи составным именем. Например, если необходимо произвести несколько операций над записью MyDate (см. ранее), то соответствующий фрагмент программы будет выглядеть следующим образом:

if MyDate.Month=12

then

 begin

   MyDate.Month := 1;

   MyDate.Year := MyDate.Year+1

 end

else MyDate.Month := MyDate.Month+1;

Существует возможность "вынести" общий для всех составных имен идентификатор записи в отдельный заголовок, после которого указывать поля записи посредством только их идентификаторов. Соответствующая конструкция называется оператором над записями (или оператором присоединения). Приведенный выше фрагмент программы можно переписать, "добавив" к условному оператору заголовок, состоящий из служебного слова with, идентификатора переменной комбинированного типа и служебного слова do:

with MyDate do

 if Month=12 then

   begin

     Month := 1;

     Year := Year+1

   end

 else

   Month := Month+1;

В последнем примере манипуляции с полями записи MyDate выглядят значительно компактнее и нагляднее, чем в первоначальном варианте. Более того, следует иметь в виду, что второй фрагмент будет выполняться быстрее, так как адрес записи Date в памяти будет вычислен только один раз при обработке конструкции with MyDate do. Еще большей эффективности можно достичь, если запись является, например, элементом массива:

var

 DB : array[1..Max] of DateRec;

begin

 with DB[i] do

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

with V1, V2, V3 do S;

где V1, V2, V3 - переменные комбинированных типов, S - некоторый оператор.

Такая форма записи считается эквивалентной следующей:

with V1 do with V2 do with V3 do S;

В случае задания списка переменных-записей нужно иметь в виду, что если некоторый идентификатор F является полем, например, и V1, и V2, то он интерпретируется как V2.F, а не как V1.F, то есть идентификатор поля связывается с последней переменной-записью в списке with.

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

В заключение приведем синтаксическую диаграмму для оператора над записями:

Оператор присоединения

Константы типа запись

Начальные значения для типизированных констант комбинированных типов задаются в виде списка пар вида "идентификатор поля записи - значение поля записи". Элементы пар разделяются двоеточием, пары отделяются друг от друга точной с запятой, а весь список пар заключается в круглые скобки:

1) type

 Point = record

  X, Y : real

 end;

const

 Center : Point = (X:10.0; Y:10.0);

2) type

 Line = array[1..2] of Point;

const

 MyLine : Line = ((X:1;У:2), (X:10;Y:10));

3) type

 Day = record

  Name : (Mon,Tue,Wed,Thu,Fri,Sat,Sun);

 Num : 1..31;

  Month : 1..12

 end;

const

 SomeDay : Day = (Name:Mon; Num:11; Month:3);

Поля должны указываться в том же порядке, как они следуют в определении типа записи. Должны быть проинициализированы все поля. Синтаксическая диаграмма для изображения записи показана ниже.

Синтаксические диаграммы

В заключение данной главы приведем синтаксические диаграммы для комбинированных типов:

Комбинированный тип

 

Список полей

Фиксированная часть

 

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

Дискриминант

Альтернатива

 


 

А также другие работы, которые могут Вас заинтересовать

10151. Соотношение эмпирического т теоретического уровней научного знания. Изменение представлений о взаимосвязи теории и эмпирии в философии науки ХХ в. 27.5 KB
  Соотношение эмпирического т теоретического уровней научного знания. Изменение представлений о взаимосвязи теории и эмпирии в философии науки ХХ в. Внутренняя структура науки определяется в п.о. через выделение в ее составе теоретического и эмпирического познания. Т.
10152. Формы систематизации знания на эмпирическом уровне 38.5 KB
  Формы систематизации знания на эмпирическом уровне. Основными методами эмпирического познания являются наблюдение и эксперимент. Наблюдение это целенаправленное восприятие явлений действительности в ходе которого фиксируются данные об их свойствах и отноше
10153. Наблюдение и эксперимент как эмпирические методы исследования, специфика их реализации в современной науке 34.5 KB
  Наблюдение и эксперимент как эмпирические методы исследования специфика их реализации в современной науке Общенаучные эмпирические методы. Наблюдение это преднамеренное целенаправленное и планомерное восприятие выделенного для изучения фрагмента реальности. Осо
10154. Научное знание: структура и методы теоретического знания. Абстрагирование и идеализация - начало теоретического познания 42 KB
  Научное знание: структура и методы теоретического знания. Абстрагирование и идеализация – начало теоретического познания. Абстракции возникают на аналитической стадии исследования когда начинают рассматривать отдельные стороны свойства и элементы единого процесс...
10155. Научная картина мира как форма систематизации научного знания, ее виды и функции. 82.5 KB
  Научная картина мира как форма систематизации научного знания ее виды и функции. Как особый структурный феномен не входящий полностью в теоретическое знание в настоящее время выделяется еще научная картина мира. НКМ – целостная система представлений об общих ...
10156. Научные революции и типы научной рациональности 62.5 KB
  Научные революции и типы научной рациональности. Типология традиций и новаций в науке. Глобальные научные революции. Изменение научной рациональности. В предыдущей лекции речь шла о соотношении традиций и новаций в развитии науки. Выделим теперь типы...
10157. Глобальные научные революции в истории культуры. Классическая, неклассическая и постнеклассическая наука: временные рамки и специфика 49 KB
  Глобальные научные революции в истории культуры. Классическая неклассическая и постнеклассическая наука: временные рамки и специфика. В истории европейской науки традиционно принято выделять две глобальные научные революции, более дискуссионными являются вопро
10158. Этика науки и проблема социальной ответственности ученого и проектировщика. Формы реализации ответственности ученых за использование достижений науки 44 KB
  Этика науки и проблема социальной ответственности ученого и проектировщика. Формы реализации ответственности ученых за использование достижений науки. Проблема этической размерности научной деятельности и технического творчества обозначилась в ХХ в.: достаточ...
10159. Различие внутренней и внешней этики науки. Этические нормы в профессиональной работе ученого, проектировщика 43 KB
  Различие внутренней и внешней этики науки. Этические нормы в профессиональной работе ученого проектировщика С т.з. адресата этика науки и техники подразделяется на внешнюю по отношению к обществу в целом и внутреннюю но отношению к коллегам в рамках совместного тр