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

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

Чтобы упростить доступ к полям записи, используется оператор присоединения With:

with <переменная> do <оператор>

Здесь with, do – ключевые слова (с, делать); <переменная> – имя переменной типа запись, за которым, возможно, следует список вложенных полей; <оператор> – любой оператор Турбо Паскаля.

Оператор присоединения with ... do открывает запись. В поле его действия имена полей записи сокращаются. Например:

with c.bd do month := 9;

Это эквивалентно

with c do with bd do month := 9;

или

c.bd.month := 9.

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

Задача 18.Составить программу формирования архива данных по изданным книгам. Данные включают: автора, название, год издания, город, где издана, и цену книги.

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

1) фамилии И. О. автора (author);

2) названия книги (title);

3) названия города, в котором книга выпущена, (city);

3) года издания (year);

4) цены (cost).

Данные author, title, city – символьного типа. Year – может быть переменной интервального типа. Цена (cost) должна быть переменной вещественного типа. Объявление нового типа данных entry как записного будет выглядеть следующим образом:

entry = record

author, title, city : string;

year : 1..9999;

cost : real;

end;

Далее следует объявить массив из 50 элементов, имеющих тип entry. Ввод элементов записи (рис. 16) организуем в цикле, причем окончание цикла зафиксируем вспомогательной переменной ch. Перед вводом содержимого очередной записи сделаем запрос на продолжение пополнения архива. Для ввода компонентов записи используем оператор readln. Компоненты записи в программе имеют составные имена: m[i].author, m[i].title, m[i].city, m[i].year, m[i].cost.

Программа:

program archives;

uses crt;

label 10;

type

entry = record {Выходные данные по книге}

author, title, city : string;

year : 1..9999;

cost : real;

end;

var

m : array[1..50] of entry;

{Архив не превышает 50 книг}

{Массив, элементами которого являются записи}

i : integer;

ch : char;

begin

i := 0;

{Блок формирования архива данных по книгам}

writeln (‘Пополняешь архив? – Да – [Y]’);

ch := readkey;

if upcase(ch) = ‘Y’ then

repeat

i := i+1;

writeln(‘Автор книги ‘); readln(m[i].author);

writeln(‘Название книги ‘); readln(m[i].title);

writeln(‘Город издания ‘); readln(m[i].city);

writeln(‘Год издания ‘); readln(m[i].year);

writeln(‘Цена книги ‘); readln(m[i].cost);

writeln (‘Пополняешь архив? – Да – [Y]’);

ch := readkey

until upcase(ch) <> ‘Y’

else

begin

write (‘Вы передумали? До свидания!’);

goto 10

end;

repeat until keypressed;

10:end.

Задача 19. Усложним предыдущую задачу. Составить программу подборки книг по указанному автору из сформированного массива записей.

Для формирования архива используем предыдущую программу. Введем переменную символьного типа ss – фамилию автора, список книг которого необходимо вывести (рис. 17). Размер архива запомним в переменной k. Для более компактного представления используемых переменных, воспользуемся опера­тором присоединения with ... do. При этом имена полей записи могут фигури­ровать как имена обычных переменных. Для возможности вывода нескольких списков организуем внешний цикл с признаком окончания ch = ‘Y’.

Программа:

program archives2;

uses crt;

label 10;

type

entry = record {Выходные данные по книге}

author, title, city : string;

year : 1..9999;

cost : real;

end;

var

m : array[1..50] of entry;

{Архив не превышает 50 книг}

{Массив, элементами которого

являются записи}

i, j, k : integer;

ss : string; {Фамилия для поиска}

ch : char;

begin

i := 0;

{Блок формирования архива

данных по книгам}

writeln (‘Пополняешь архив? – Да – [Y]’);

ch := readkey;

if upcase(ch) = ‘Y’ then

repeat

i := i+1;

with m[i] do

begin

writeln(‘Автор книги ‘); readln(author);

writeln(‘Название книги ‘); readln(title);

writeln(‘Город издания ‘); readln(city);

writeln(‘Год издания ‘); readln(year);

writeln(‘Цена книги ‘); readln(cost);

end;

writeln (‘Пополняешь архив? – Да – [Y]’)

ch := readkey

until upcase(ch) <> ‘Y’

else

begin

write (‘Вы передумали? До свидания!’);

goto 10

end;

k := i;

{Блок подборки всех книг по указанному автору}

repeat

writeln(‘Укажите фамилию автора’); readln(ss);

writeln(‘Список книг, автор которых ‘, ss : 15);

for i := 1 to k do

with m[i] do

begin

if ss = author then

begin

writeln(title);

writeln(‘Город ‘,city);

writeln(‘Год издания ‘,year);

writeln(‘Цена ‘,cost:8:2);

writeln

end

end;

writeln(‘Нужно еще выдавать авторский список? – Да –[Y]’);

ch := readkey;

until upcase(ch) <> ‘Y’;

repeat until keypressed;

10:end.

Вариантные записи

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

Вариантный записной тип – это записной тип, содержащий несколько вариантов структуры записи.Различие может касаться как числа компонент, так и их типов.

Предположим, что есть, например, такое описание:

type status = (married, widowed, divorced, single),

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

type person = record

{здесь поля общие для всех person}

case status of

married: ( { поля только для семейных });

single: ({ поля только для одиноких });

. . .

end;

Каждому значению, относящемуся к типу, на основании которого идет различение вариантов (типу признака), должен соответствовать один из вариантов. Это означает, что перед вариантами должны появляться все значения типа признака. В нашем примере, кроме констант married и single, должны появиться и константы widowed и divorced.

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

case ms : status of

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

1. Имя (name) – первое, последнее (first, last).

2. Рост (height) – целое число.

3. Пол (sex) – муж., жен. (male, fеmale).

4. Дата рождения (date) – год, месяц, день (year, month, day).

5. Число иждивенцев (depds) – целое число.

6. Семейное положение (status):

Если в браке (married) или вдов (widowed):

а) дата свадьбы (mdate) – год, месяц, день (year, month, day).

Если разведен (divorced):

а) дата развода (ddate) – год, месяц, день (year, month, day),

б) первый развод (firstd) – нет, да (false, true).

Если одинокий (single):

информации нет.

Определение записного типа person можно сформулировать так:

type

status = (married, widowed, divorced, single);

date = record

year : 1900..2100;

mo : ( jan, feb, mar, apr, may, jun,

jul, aug, sep, oct, nov, dec);

day : 1..31;

end;

natural = 0..max;

person = record

name : record first, last : string[15] end;

height : natural;

sex : (male, female);

birth : date;

depdts : natural

case ms : status of

married, widowed : (mdate : date);

divorced : (ddate : date; firstd : boolean);

single : ()

end {person};

Синтаксическая диаграмма для вариантной части представлена на рис. 18.

Рис. 18

Синтаксическая диаграмма для варианта (рис. 19):

Рис. 19

Задача 20.Составить программу формирования перечня сведений по данным архива книг и журналов.

Данная задача отличается от задачи 19 тем, что состав данных в записи различается для книги и для журнала. Введем перечисляемый тип данных entrytype, определяющий варианты. type entrytype = (book, magazine).

Данные по каждому наименованию архива включают:

1) автора книги или статьи (author) – переменная типа string;

2) наименование книги или статьи (title) – string;

3) год издания книги (журнала) – интервальный тип 1 ... 1999;

4) если книга (book):

а) издательство (publisher) – string;

б) город (city) – string.

Если журнал (magazine):

а) наименование журнала (magname) – string;

б) номер журнала (vol) – integer;

в) количество страниц (page) – integer.

Программа:

program archives3;

uses crt;

label 10;

type

entrytype = (book,magazine);

{Вводится специальный тип данных, определяющий варианты}

entry = record

author, title : string;

year : 1..9999;

case tag:entrytype of

{Поле tag определяет ветвь варианта}

book : (publisher,city : string);

magazine : (magname : string; vol, page : integer)

end;

var

m : array[1..50] of entry;

i, j, k : integer;

ss : string;

ch : char;

begin

i := 0;

{Блок формирования архива данных по книгам}

writeln (‘Пополняешь архив? – Да – [Y]’);

ch := readkey;

if upcase(ch) = ‘Y’ then

repeat

i := i+1;

writeln(‘Если вводите данные по книге, нажмите Y ‘);

ch := readkey;

if upcase(ch) = ‘Y’ then

m[i].tag := book

{Переменной варианта присваивается признак книги – book}

else

m[i].tag := magazine;

writeln(‘Автор ‘); readln(m[i].author);

writeln(‘Название ‘); readln(m[i].title);

writeln(‘Год издания ‘); readln(m[i].year);

{Проверка условия принадлежности объекта к книге}

if m[i].tag = book then

{Ввод данных в поля, специфические для книги}

begin

writeln(‘Город ‘); readln(m[i].city);

writeln(‘Издательство’); readln(m[i].publisher);

end

else

{Ввод данных в поля, специфические для журнала}

begin

write (‘Название журнала’); readln(m[i].magname);

writeln(‘Номер ‘); readln(m[i].vol);

writeln(‘Страница ‘); readln(m[i].page);

end;

writeln (‘Пополняешь архив? – Да – [Y]’);

ch := readkey;

until upcase(ch) <> ‘Y’

else

begin

write (‘Вы передумали? До свидания!’);

goto 10

end;

k := i;

{Блок подборки списка трудов указанного автора}

repeat

writeln(‘Укажите фамилию автора’); readln(ss);

writeln(‘Список трудов ‘, ss : 15);

for i := 1 to k do

begin

if ss = m[i].author then

begin

writeln(m[i].title);

writeln(‘Год издания ‘,m[i].year);

if m[i].tag = book then

begin

writeln(‘Город ‘,m[i].city);

writeln(‘Издательство ‘,m[i].publisher);

writeln

end

else

begin

writeln(‘Название журнала ‘,m[i].magname);

writeln(‘Номер ‘,m[i].vol);

writeln(‘Страница ‘,m[i].page);

writeln

end

end

end;

writeln(‘Нужно еще выдавать авторский список? – Да –[Y]’);

ch := readkey;

until upcase(ch) <> ‘Y’;

repeat until keypressed;

10:end.

Множественные типы

Множество– это некоторый ограниченный неупорядоченный набор различных элементов одинакового типа. Можно говорить, например, о множест­ве фигур на плоскости (прямоугольник, круг, ромб, квадрат), о множестве радиодеталей, транспортных средств, станков и т. д.

В Турбо Паскале существует множественный тип для ввода множеств и организации операций над множествами. Множественный типпредставляет собой некоторую совокупность элементов, которая является подмножеством допустимых значений определенного порядкового типа, именуемого базовым. Множественный тип описывает наборы однотипных логически связанных друг с другом объектов. Характер связей между объектами лишь подразумевается программистом и никак не контролируется Турбо Паскалем. Количество элементов, входящих в множество, может меняться в пределах от 0 до 256. Множество, не содержащее элементов, называется пустым. Именно непостоянством количества своих элементов множества отличаются от массивов и записей.

Множества должны быть объявлены либо в разделе переменных var, либо с использованием раздела типов type. Описание типа множества имеет вид:

<имя типа> = set of <базовый тип>

Здесь <имя типа> – правильный идентификатор; set, of – зарезервирован­ные слова (множество, из); <базовый тип> – базовый тип элементов множества, в качестве которого может использоваться любой порядковый тип, кроме word, integer, longint.

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

Рис. 20

Пример:

var

year : set of 198..200;

c : set of char;

Year – множество, которое может состоять из элементов диапазона 198 ... 200, с – множество всех символов.

Или:

type

digitchar = set of ‘0’..’9';

digit = set of 0..9;

color = (red, blue, green, white, black, orange);

brush = set of color;

var

s1, s2, s3 : digitchar;

s4, s5, s6 : digit;

a : brush;

Тип digitchar описывает набор символов ‘0’, ‘1’, ‘2’, ‘3’, ‘4’, ‘5’, ‘6’, ‘7’, ‘8’, ‘9’. Тип digit состоит из чисел 1, 2, 3, 4, 5, 6, 7, 8, 9. Тип brush состоит из набора шести идентификаторов. Переменные s1, s2, s3 имеют тип digitchar, то есть могут включать только перечисленные элементы от ‘0’ до ‘9’. Множества s4, s5, s6 могут состоять из чисел от 1 до 9 в том виде, в котором они перечислены в типе digit. Переменная а может содержать от одного до шести значений перечисляемого типа color. Напомним, что элементы множества не упорядочены.

Конструкторы множеств

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

Описанием элемента могут быть константы или выражения базового типа, а также – тип–диапазон того же базового типа вида min..max, где значения выражений min и max представляют собой нижнюю и верхнюю границы группы элементов. Если нижняя граница больше верхней границы (т. е. min > max), то никакой элемент не описывается, то есть описывается пустое множество.

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

Рис. 21

Примеры конструкторов множеств:

[13]

[ i + j , i – j ]

[ ‘0’..’9']

Следующие записи не верны:

[true, 2] – разные базовые типы;

[200 .. 300] – ord(300) > 255;

[4.0, 5.0] – базовый тип не является порядковым.

Операции над множествами

Если Х – переменная–множество, а Е – множественное выражение, то присваивание:

Х := Е

допустимо только в том случае, если все элементы Е относятся к базовому типу Х.

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

А + В – множество из элементов А и В (объединение);

А * В – множество общих для А и В элементов (пересечение);

А – В – множество элементов А, не входящих в В (разность).

К множественным операндам применимы пять операций отношения. Предположим, А и В – множественные выражения одного типа, а е – порядковое выражение базового типа.

е in A – вхождение в множество; результат true, если е элемент А, иначе – false;

А = В – равенство множеств;

А <>В – неравенство множеств;

А <= В – включение; результат true, если А подмножество В;

А >= В – включение; результат true, если В подмножество А.

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

Пусть

s1 := [‘1’, ‘2’, ‘3’];

s2 := [‘3’, ‘2’, ‘1’];

s3 := [‘2’, ‘3’];

s4 := [0..3, 6];

s5 := [4, 5];

s6 := [3..9];

Множества s1 и s2 эквивалентны, множество s3 включено в s2, но не эквивалентно ему.

s4 + s5 содержит [0, 1, 2, 3, 4, 5, 6].

s5 + s6 содержит [3, 4, 5, 6, 7, 8, 9].

s6 – s5 содержит [3, 6, 7, 8, 9].

s4 – s5 содержит [0, 1, 2, 3, 6].

3 in s6 возвращает true.

2 * 2 in s1 возвращает false.

Действия с множествами относительно быстрые, и их можно использо­вать для исключения более сложных проверок. Например, вместо проверки

if (ch = ‘a’) or (ch = ‘e’) or (ch = ‘i’) or (ch = ‘o’) or (ch = ‘u’) then . . .

можно написать более простую

if ch in [‘a’, ‘e’, ‘i’, ‘o’, ‘u’] then . . . .

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

type

days = set of 1..31;

digc = set of ‘0’ .. ‘9’;

error = set of 1..24;

const

workDays : days = [1..5, 8..12, 15..19, 22..26, 29,30];

evendigits : digc = [‘0’, ‘2’, ‘4’, ‘6’, ‘8’];

err : error = [ ];

Механизм работы с множествами Турбо Паскаля соответствует базовым математическим действиям с конечными множествами. Множества хорошо работают там, где нужно проводить анализ однотипных выборок значений или накапливать произвольно поступающие значения. Значения типа “множество” компактно кодируются: один элемент расходует 1 бит. Множество из 256 элементов займет всего 32 байта. Недостатком является невозможность вывода множеств. Не существует механизма изъятия элемента из множества, но и в математике такое действие не определено.

Наши рекомендации