Довольно часто вполне оправданным является представление некоторых элементов данных в качестве составных частей другой, более крупной логической единицы. Представляется естественным сгруппировать информацию о номере дома, названии улицы и городе в единое целое и назвать адресом, а объединенную информацию о дне, месяце и годе рождения назвать датой. В языке Паскаль для представления совокупности разнородных данных служит комбинированный тип запись.
Запись и массив схожи в том, что обе эти структуры составлены из ряда отдельных компонентов. В то же время, если компоненты массива должны быть одного типа, записи могут содержать компоненты разных типов.
Приведем пример описания переменной, имеющей структуру записи:
Var
|
Отметим, что поля StreetName и CityName имеют одинаковый тип: String[20]. Поскольку в описании эти поля могут располагаться в любом порядке, то можно сократить описание записи с полями одинакового типа. Сокращенное описание записи Address выглядит следующим образом:
Var
|
Каждый компонент записи называется полем. В переменной записи Address поле с именем HouseNumber является переменной типа Integer, поле StreetName - двадцатисимвольной строкой и т.д.
Для того чтобы обратиться к некоторому полю записи, следует написать имя записи и имя поля. Эти два идентификатора должны разделяться точкой.
Оператор, который присваивает полю HouseNumber значение 45, выглядит так:
Address.HouseNumber := 45;
|
Таким же образом присваиваются значения другим полям записи Address :
Address.StreetName := 'Профсоюзная';
|
Каждое поле записи Address можно рассматривать как обычную переменную, которую можно напечатать или использовать в расчетах. Вместе с тем, запись может использоваться как единое целое. В этом случае надо ввести тип записи.
Предположим, имеется следующее описание:
Type
|
После приведенного описания переменные HisBirth и MyBirth имеют тип записи Date. Помимо действий над отдельными полями записей HisBirth и MyBirth можно выполнять операции над всей записью. Следующий оператор присваивания устанавливает равенство значений записей HisBirth и MyBirth :
HisBirth := MyBirth;
|
Это присваивание эквивалентно следующей последовательности операторов:
HisBirth.Day := MyBirth.Day;
|
Для переменных одного типа можно проверить выполнение отношения равенства или неравенства ("=", "<>"). После выполнения приведенных выше присваиваний следующее булево выражение будет иметь значение True:
HisBirth = MyBirth;
|
Рассмотрите пример описания процедуры, которая получает запись в качестве параметра-значения и печатает дату в сокращенной стандартной форме, используя формат (MM-DD-YYYY).
Procedure WriteDate(OneDate : Date);
|
Так как на тип компонентов массива не накладывается ограничений, то можно использовать массив, компонентами которого являются записи. Посмотрите описание такого массива:
Var
|
Чтобы обратиться к некоторому полю определенной записи массива, следует указать имя массива, индекс интересующей записи и имя необходимого поля.
Например, следующий оператор печатает содержимое поля Year записи Birthdays[3]:
Write(Birthdays[3].Year);
|
Примечание. Поля записи, в свою очередь, тоже могут быть массивами, множествами, записями.
Задание. Рассмотрите следующие описания:
Type
|
Ответьте, какой тип, если он определен, имеют следующие идентификаторы:
а) Today.Year
б) Memos [2]
в) Memos [4].Month
г) Calendar [200]
д) Memos [16].Message[2]
е) Memos [16].Message[1],[2]
ж) Calendar[1].Date
з) Memos [10].Event
Задание. Составьте программу, организующую ввод наиболее полной информации о людях и вывод интересующей информации на экран.
Приведем описание массива, компоненты которого являются записями:
Var
|
Отметим, что два поля: Residence и Phone являются записями. Как выполнить обращение к полям этих записей? Как распечатать почтовый индекс рабочего № 7? Поскольку это поле располагается во вложенной записи, то следует указать как имя самой записи, так и имя записи, в которую данная запись входит.
write (Payroll[7].Residence.ZipCode);
|
Аналогично, приведенное присваивание корректирует региональный код рабочего № 23:
Payroll[23].Phone.AreaCode :=804;
|
Оператор if, представленный ниже, выполняет проверку инициала рабочего № 58:
if Payroll[58].LastName[1] in ['T'..'Z'] Then ...
|
Соблюдение всех правил перечисления индексов и имен полей при составлении ссылок является довольно утомительным занятием, часто приводящим к ошибкам. В некоторых программах, содержащих большое количество обращений к одному и тому же полю, такое положение приводит к однообразному повторению. Чтобы облегчить выполнение многократных ссылок на поля структур, вводится оператор With (в переводе с английского - предлог "с").
Общая форма записи:
with <имя переменной> do <оператор>
|
В рамках оператора, расположенного внутри оператора With, к полям указанной переменной можно обращаться просто по имени. Например,
with Payroll[7].Residence do
|
Оператор with позволяет более компактно представлять часто используемые переменные. Посмотрите это на примере фрагмента программы, печатающего адрес рабочего № 14:
with Payroll[14].Residence do
|
В рамках составного оператора, следующего за with, каждое обращение к имени поля автоматически связывается с записью Payroll[14].Residence.
Печать адресов всех рабочих выполняется при помощи следующего оператора цикла:
for i := 1 to Workers do
|
Операторы with могут быть вложенными. Приведенные ниже три оператора эквивалентны друг другу:
Однако, недопустимым является использование вложенных операторов With, в которых возникает неоднозначность конструкции. Например:
with Payroll[5] do
|
Следует очень внимательно подходить к использованию вложенных операторов With, применение которых может привести не только к ошибкам, но также и к потере наглядности структуры программы. Хотя оператор With является стандартным средством сокращения, его полезность должна еще проявиться. Конечной целью всякого хорошего программиста является написание не только короткой, но и понятной программы.
Рассмотрите решение задачи.
Задача. В массиве хранятся данные об учащихся: школа, фамилия, класс. Вывести список учеников, которые учатся в восьмом классе.
Program LipovsevM;
|
В файл записать информацию о сотрудниках некоторого предприятия: фамилия, домашний адрес, телефон, образование, оклад. Напечатать список сотрудников, имеющих высшее образование.
Решение
Программа для записи информации в файл
type z=record
f:string[20];
adres:string[30];
tel:string[15];
obraz:string[20];
oklad:real;
end;
var F:file of z;
sotr:array [1..3] of z;
i,n:integer;
begin
writeln;
write('Vvedite kol-vo zapisej o sotrudnikakh=');
readln(n);
assign(F,'c:\sotrudniki');
rewrite(f);
writeln('Vvedite svedeniya o sotrudnikakh');
for i:=1 to n do begin
write('Familija:');
readln(sotr[i].f);
write('Adres:');
readln(sotr[i].adres);
write('Telefon:');
readln(sotr[i].tel);
write('Obrazovanie:');
readln(sotr[i].obraz);
write('Oklad:');
readln(sotr[i].oklad);
write(F,sotr[i]);
writeln('----------------');
end;
Close(F);
end.
Программа для
печати списка
type z=record
f:string[20];
adres:string[30];
tel:string[15];
obraz:string[20];
oklad:real;
end;
var F:file of z;
sotr:z;
i:integer;
s:integer;
begin
assign(F,'c:\sotrudniki');
reset(f);
writeln;
writeln;
writeln('Spisok sotrudnikov s vishim obrazovaniem ');
while not Eof(f) do
begin
read(F,sotr);
if sotr.obraz='vishee' then
writeln(sotr.f);
end;
Close(F);
readln;
end.