Глава 5 Типы данных, определяемые пользователем 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Глава 5 Типы данных, определяемые пользователем



5.1 Пользовательский тип данных

Пользовательский тип данных - это тип данных, определяемый программистом в программе. Объявление пользовательских типов данных происходит в разделе объявления типов, который открывается зарезервирован­ным словом TYPE. За словом TYPE следуют разделенные знаком равенства имя нового пользовательского типа и конструкция, определяющая этот тип.

Рисунок 5.1 - Синтаксическая диаграмма для раздела определения типов

Type

day = (mon, tue, wed); color = (white, red, blue)

В данном случае слова day и color представляют собой имена новых типов, при этом пользовательский тип day определен тремя элементами: mon, tue, wed; пользовательский тип color элементами: white, red, blue.

К простым типам относятся порядковые и вещественные типы.

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

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

К порядковым типам относятся целые, логический, символьный, перечисляемый и тип-диапазон. К любому из них применима функция ORD(X), которая возвращает порядковый номер значения выражения X. Для целых типов функция ORD(X) возвращает само значение X. Для логического типа функция ORD(X) дает 0 для значения false и 1 для значения true. Для символьного типа функция ORD(X) дает значение в диапазоне от 0 до 255.

К порядковым типам можно также применить функции PRED(X) и SUCC(X). PRED(X) - возвращает предыдущее значение порядкового типа. SUCC(X) -возвращает следующее значение порядкового типа.

Типизированные константы

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

Объявления констант начинаются зарезервированным словом const. Затем следует имя константы, символ равенства (=) и значение этой константы. Например:

const m = 14.0.

В таком случае оператор присваивания m:= 1 недопустим, как недопустимо и действие 14.0:= 1.

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

<идентификатор>: <тип> = <значение>

Здесь <идентификатор> - идентификатор константы;<тип> - типконстанты; <значение> - значение константы. Например:

year: integer = 1995;

Имя константы - year, тип константы integer, значение константы 1995.

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

Типизированные константы не могут использоваться при описании других констант или типов.

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

Примеры правильного объявления констант:

const

year: word =1989;

x: real = 0.01;

min: integer = 0;

Примеры неправильного объявления констант:

const

mass: array [min..max] of real; {Нельзя использовать типизиро­ванные константы в качестве границ диапазона}

а, b, с: byte =0; {Нельзя использовать список иден­тификаторов}

х:real = pi; {Нельзя использовать в качестве значения вызов функции}

var namef: string [22] = ‘prog.pas’; {Нельзя объявлять типизированную константу в разделе переменных}

Перечисляемый тип

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

type color = (White, Red, Blue, Yellow, Purple, Green, Orange, Black);

sex = (male, female);

workday = (mon, tues, wed, thur, fri, sat);

Тип boolean, можно определить следующим образом:

type boolean = (false, true);

Рисунок 5.2 - Синтаксическая диаграмма для перечисляемого типа

Пример неверного определения:

type workday = (mon, tues, wed, thur, fri, sat);

free = (sat, sun);

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

Использование перечисляемых типов повышает надежность программ благодаря возможности контроля тех значений, которые получают соответствующие переменные. Эти значения могут быть использованы в качестве параметра в операторе цикла FOR, в качестве селектора в операторе CASE Константы, входящие в определение перечисляемого типа, считаются упорядоченными, т. е. им ставится в соответствие последовательность целых чисел начинающихся с нуля. Порядковые номера компилятор использует для представления констант в памяти ЭВМ. Перечисляемые типы имеют компактное машинное представление. Перечисляемые данные должны иметь синтаксис идентификатора, и поэтому не могут перечисляться цифры, символы, строки. Над перечисляемыми данными не производятся арифметические действия. Пусть, например, заданы такие перечисляемые типы:

type

colors = (black, red, white);

ordenal = (one, two, three);

days = (monday, tuesday);

и определены переменные

var

col: colors;

num: ordenal;

day: days;

Порядковые номера: ORD(black) = 0, ORD(white) = 2, ORD(one) = 0. Допустимы операторы:

col:= black; num:= succ(two); day:= pred(tuesday);

Недопустимыми являются операторы:

col:= one; day:= black;

Переменные любого перечисляемого типа можно объявлять без предварительного описания этого типа, например:

var col: (black, white, green);

К сожалению, перечисляемые типы данных не лишены существенного недостатка, ограничивающего их применение в широких масштабах. Значения переменных этих типов не могут вводиться оператором read и выводиться оператором write. Бороться с этим недостатком можно, но посредством не очень красивых приемов. Обычно, чтобы все-таки иметь возможность вывода на экран, вводят проиндексированные массивы. Каждый их элемент есть строковое написание соответствующего перечисленного значения.

Пример 5.1 Составить программу, которая выводит все дни недели, оставшиеся до конца недели, и день, предшествующий заданному дню.

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

program zadacha1; {Заголовок программы}

uses crt; {uses - фраза}

type {Определение нового типа}

days = (mon, tue, wed, thu, fri, sat, sun);

Var

day, today: days; {Описание переменных}

begin {Начало исполняемой части программы}

clrscr; {Стандартная процедура гашения экрана}

today:=tue; {Ввод исходной информации}

writeln(‘Дo конца недели');

for day:= today to sun do {Цикл от заданного дня недели до }

begin {последнего дня недели - sun}

case day of {Оператор выбора}

mon: writelп('понедельник');

tue: writeln('вторник');

wed: writeln('среда');

thu: writeln('четверг');

fri: writeln('пятница');

sat: writ.eln('суббота');

Sun: writeln('воскресенье')

end;

end;

write('Вчерашний день - ');

if ord(today) = 0 then day:=sun {Расчет предыдущего дня}

else day:=pred(today);

Case day of

mon: writeln('понедельник');

tue: writeln('вторник');

wed: writeln('среда');

thu: writeln('четверг');

fri: writeln('пятница');

sat: writeln('суббота');

Sun: writeln('вoскресеньe')

end;

End.

За заголовком программы следует uses - фраза. Такая фраза указывает на используемые в программе, но описанные в другом месте объекты. Это связано с важнейшим понятием модуля, рассматриваемом в следующей юните. В данном примере uses crt; говорит о том, что в программе может использоваться процедура clrscr (очистить экран), описанная в модуле crt.

Оператор присваивания today:= tue заменяет оператор ввода, так как для read и write недопустимо использование переменных и значений перечисляемого типа.

Тип – диапазон

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

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

Тип-диапазон еще называют ограниченным типом или интервальным типом.

Для введения нового типа-диапазона - надо в блоке описания типов type указать имя этого типа и границы диапазона через две точки подряд (рис. 5.3).

Рисунок 5.3 - Синтаксическая диаграмма для типа-диапазона

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

tуре

digit = '0'.. '9';

dig2 = 48.. 57;

Такая декларация типа указывает компилятору, что для переменных этого типа (которые будут объявлены в программе далее) допустимы в качестве значений только числа из указанного интервала. При выполнении программы попытка присвоить такой переменной значение, не входящее в интервал допустимых значений, квалифицируется как ошибка и приводит к прекращению работы программы и выдаче соответствующего сообщения.

Тип-диапазон необязательно описывать в разделе TYPE, его можно указывать непосредственно при объявлении переменной:

vаr

date: 1..31;

month: 1.. 12;

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

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

tуре

days = (mо, tu,th, fr, sa, su);

weekend = sa.. su;

var

w: weekend;

……….

w:= sa;

 

то ord(w) вернет значение 5, в то время как pred(w) приведет к ошибке. Диапазонные типы позволяют формулировать проблему в более наглядной форме. Для реализаторов языка появляется возможность экономить память и проводить во время выполнения программы контроль присваиваний.

Пример 5.2 Используя диапазонный тип данных, написать программу генерирования чисел спортлото "6 из 49".

rogram sportlotto;

{Программа задания чисел для игры в лото "6 из 49"}

Tyре

num = 1.. 49;

Var

i:1..6; loto: num;

Begin

randomize;

for i:=1 to 6 do

Begin

loto:=random(49)+1;

Writeln('Nr.',i:2,loto:6)

End

End.

В программе объявлен новый тип данных num. Возможные значения переменной типа num ограничены и находятся в интервале от 1 до 49. Далее пeрeменная loto объявляется как переменная типа num. Переменная i также является переменной диапазонного типа. Как известно, переменные диапазонного типа могут задаваться в разделе описания переменных. Randomize - встроенная математическая функция инициации датчика псевдослучайных чисел.

Эта программа имеет тот недостаток, что не все шесть выпавших в лото чисел могут оказаться различными. В этой маленькой программе еще не совсем ясна необходимость в переменных ограниченного типа, хотя в больших программах такая необходимость есть. Когда мы имеем дело с программой в две дюжины строк, очень неудобно помнить, какие именно значения могут иметь отдельные переменные. Например, сообщение, что i имеет тип integer, мало что нам говорит, в то время как переменная, имеющая диапазонный тип 1.. 6, дает намного больше информации. Это не всегда удобно для пользователя, но зато делает программиста более уверенным в программе. Если только из-за ошибки в программе значение вычисленной переменной выйдет за допустимый интервал, то последует сообщение об ошибке. Таким способом можно получать дополнительный контроль. Переменные интервального типа в языке Паскаль используются, в частности, тогда, когда заранее известно, что значение переменной может находиться только в определенном интервале.

Пример 5.3 Рассчитать продолжительность рабочей недели в часах.

program rabweek;

Type

day = (mo,tu,we,th,fr,sa,su);

workday = mo..fr;

Var

den: workday;

time: integer;

Begin

time:= 0;

for den:= mo to fr do time:= time + 8;

Write (time)

End.

Тип day объявляется путем перечисления всех значений (здесь перечислены сокращенные английские названия всех дней недели). Новый тип workday является типом-диапазоном и все возможные значения переменной типа workday ограничены и находятся в интервале от mо до fr. Из предыдущей (базовой) строки ЭВМ может определить, что здесь возможными значениями будут mо, tu, we, th, fr. Переменная den имеет тип workday. Если этой переменной захотят присвоить значение, отличающееся от перечисленных в списке от то до fr включительно, например su, то в этом случае появится сообщение об ошибке. Целая переменная time с каждым рабочим днем недели увеличивается на 8. Таким образом, мы найдем продолжительность рабочей недели, равную 40 часам.

Массивы

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

Массивовый тип - это одномерная или многомерная совокупность фиксированного числа однотипных элементов.

Массивы (регулярные типы данных) представляют собой упорядоченную последовательность переменных одного типа. Элементы массива являются его компонентами. Все компоненты относятся к одному типу, его называют типом компонент. Каждая компонента может быть явно обозначена с помощью имени переменной массива, за которым в квадратных скобках следует индекс. Индекс - это величина, характеризующая положение элемента относительно начала массива. Индексом может быть произвольное выражение порядкового типа, заключенное в квадратные скобки. Время, требуемое для доступа к любой компоненте, не зависит от значения индекса. Поэтому о массивах можно говорить как об объектах, структура которых допускает прямой доступ.

Переменные b[1], b[2],..., b[40] являются элементами массива b; с[1], с[2],..., с[40] - элементы массива с. b[12] - двенадцатый элемент массива b, c[39] - тридцать девятый элемент массива с. Если массив состоит только из 40 элементов, то нельзя использовать переменную b[41], так как такой переменной нет в массиве. В качестве индекса может использоваться выражение, например:

a[i + 2 ], b [2 * (i + 1) + 1].

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

Массивы, как и простые переменные, подлежат описанию в разделе переменных. Например,

var

а: array [1.. 40] of real;

b,c: array [1.. n] of real;

d: array [5.. 20] of integer;

p: real;

В приведенном примере описаны четыре массива: а, b, с, d и простая переменная р. Ключевое слово array означает, что описываемый объект является массивом. В описании массива содержатся следующие сведения:

1) сведения о типе элементов массива (элементы массивов а, b, с - вещественные, массива d - целые);

2) диапазон изменения индексов, определяемый граничной парой, например: 1.. 40, 1.. n, 5.. 20. Нижняя граница отделяется от верхней двумя точками. Нижняя граница показывает наименьшее возможное значение индекса, верхняя - наибольшее. Очевидно, что нижняя граница не может превосходить верхнюю.

В описании массивов df и cf

df: array [1.. 10] of real;

cf: array [1.. 10] of real

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

df, cf: array [1.. 10] of real.

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

Каждому из массивов df и cf выделяется по 10 последовательно расположенных друг за другом ячеек памяти. О том, какое количество ячеек памяти нужно выделить массиву, машина "узнает" из описания.

Пусть массив K описан следующим образом:

vаr К: array [n.. m] of integer.

Какое количество ячеек должно быть выделено для хранения элементов массива К? Это зависит от значений n и m. Выделение памяти для переменных и массивов производится раньше, чем выполняется какой-либо оператор программы, n и m должны получить значение прежде, чем начнется процесс выделения памяти для переменных. Определить значения n и m можно в разделе констант, который помещается в программе между разделом меток и переменных.

Пример 5.4 Программа чтения элементов массива и вывода элементов этого массива, помноженных на число p.

program pri;

const n = 1; m = 10;

Var

i: integer;

k: array [n.. m] of integer;

Begin

for i:= n to m do read (k[i]);

for i:= n to m do write (k[i] * pi)

End.

Использование раздела констант позволяет сгруппировать в начале программы величины, характерные для конкретного примера. Здесь их легче изменить. Например, если программу pri нужно выполнить для массива, состоящего из сорока элементов, то достаточно изменить лишь раздел констант. В случае когда константы записаны в программе явно, изменения приходится вносить в различные части программы, при этом некоторые части, требующие изменения, могут остаться не замеченными. Особенно часто это бывает, если программа достаточно велика. Использование констант не только облегчает процесс изменения программы, но и делает его более надежным.

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

type

аr = array [n.. m] of integer.

Тогда в разделе переменных необходимо указать

k: аr.

Синтаксис описания типа массива:

<имя типа> = array [<сп. инд. типов>] of < тип>

Здесь <имя типа> - правильный идентификатор; array, of - зарезервированные слова (массив, из); <сп. инд. типов> - список из одного или нескольких индексных (порядковых) типов, разделенных запятыми; квадратные скобки, обрамляющие список, - требование синтаксиса; < тип> - любой тип Турбо Паскаля.

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

Так как тип <тип>, идущий за словом of, - любой тип Турбо, Паскаля, то он может быть и другим массивом, например:

type

mat = array [0.. 5] of array [-2.. 2] of real,

или более компактно:

type

mat = array [0.. 5, -2.. 2] of real.

Еще пример описания:

type

color = (red, green, blue);

truthtable = array [boolean] of boolean;

height = 0..200;

var

square: array [color] of height;

matrix: array [2..8] of array [2..8] of integer;

table: truthtable;

Тип truthtable связан с набором массивов с индексами и элементами типа boolean. Переменная square является массивом с индексами типа color и элементами типа heigth. Переменная matrix является массивом с индексами в диапазоне 2.. 8 и элементами, являющимися, в свою очередь, массивами с индексами 2.. 8 и элементами целого типа. Переменная table является массивом типа truthtable, то есть с индексами и элементами типа boolean.

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

Глубина вложенности структурированных типов вообще, а следовательно, и массивов - произвольная, поэтому количество элементов в списке индексных типов (размерность массива) не ограничено, однако суммарная длина внутреннего представления любого массива не может быть больше 65520 байт.

Рисунок 5.4 - Синтаксическая диаграмма для массивового типа

В целях совместимости со стандартным Паскалем в Турбо Паскале разрешаемся перед описанием структурированного типа ставить зарезервированное» слово packed, предписывающее компилятору, по возможности, экономить память, отводимую под объекты структурированного типа; но компилятор фактически игнорирует это указание: "упаковка" данных в Турбо Паскале осуществляется автоматически везде, где это возможно.

В приведенном выше примере через mat [i][j] обозначается j-я компонента i-й компоненты массива mat. Обычно для многомерных массивов удобнее пользоваться такой сокращенной формой как mat [i,j]. Массив mat можно рассматривать как матрицу и говорить, что mat [i,j] относится к компоненте, находящейся в j-ом столбце i-й строки этой матрицы. Дело не ограничивается двумерными массивами. Если задано n типов индексов, то массив называется n-мерным, а его компоненты обозначаются с помощью n индексных выражений.

Если есть переменные - массивы А и В одного типа, то присваивание:

А:= В

возможно, если массивы допускают покомпонентное присваивание

А [ i ]:= В [ i ]

(для всех i, относящихся ктипу индекса), и представляет собою сокращенную запись такого покомпонентного присваивания.

Однако над массивами не определены операции отношения. Нельзя, например, записать

if a = b then...

Сравнить два массива можно поэлементно, например:

for i:= 1 to 5 do

if a[i] <> b[i] then...

При работе с массивами часто используется поэлементная обработка массива в рамках цикла for... to... do. Так, с помощью фрагмента программы

for i:= 2 to 7 do index[i]:= 0;

всем элементам массива index присваивается значений 0.

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

type

colors = (white, red, black);

const

colst: array [colors] of string[5] = ('white', 'red', 'black');

vector: array [1..5] of byte = (0, 0, 0, 0, 0);

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

сonst

matr: array [1..3, 1..5] of byte = ((0, 1, 2, 3, 4),

(5, 6, 7, 8, 9),

(10,11,12,13,14))



Поделиться:


Последнее изменение этой страницы: 2017-02-17; просмотров: 854; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.17.150.89 (0.117 с.)