Перечисляемый и ограниченный типы
Ранее рассматривались простые стандартные типы данных (Integer, Boolean,Char...) - порядковые типы, то есть к переменным этих типов применимы Succ и Pred. Real - не порядковый тип.
В Паскале разрешено введение новых типов. Секция Type располагается между секцией констант и секцией переменных. Введение своих типов повышает "читабельность" программ.
Например: Месяцы.
Type
Month = (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec);
Var
M: Month;
Максимальная мощность перечисляемого типа - 256 значений, поэтому перечисляемый тип фактически задаёт подмножество типа Byte.
В Паскале отсутствуют средства, которые бы позволяли осуществить непосредственный ввод - вывод переменных перечисляемого типа, однако можно вывести код: Write(Ord(M)).
Кроме того применимы операции сравнения:
If (M > FEB) And (M < JUN) Then
Write ('Весенний месяц');
Следует иметь ввиду, что упорядоченность элементов перечисляемого типа определяется порядком их следования. Самый левый элемент имеет минимальное значение, правый - максимальное.
И перечисляемый и ограниченный типы относят к простому типу.
Простой тип - это такой тип, который в некоторый момент времени хранит только одно значение.
Структурированные типы данных - совокупность связанных данных и множество правил, определяющих, как их организацию так и способ доступа к элементам данных.
Массив - это упорядоченный набор переменных одного типа.
Массив содержит фиксированное число компонент, которое задаётся при определении переменных типа массива. Тип компоненты массива может быть любым. Каждый элемент масива имеет свой индекс. Тип индекса - простой, поэтому все элементы массива могут быть перебраны при помощи операторов цикла.
В Паскале многомерный массив можно описать как одномерный:
Type
Mas = Array [1..3] Of Array [1..5] Of Integer;
Var
A, B: Mas;
C: Array [1..3, 1..5] Of Integer;
{такая же структура но определена как двумерный массив}
Символьные строки
Переменную типа Packed Array [0..N] of Char принято называть символьной строкой.
Строка - это упакованный массив, компоненты которого имеют тип Char и тип индекса имеет нижнюю границу равную одному. К строкам применимы все 6 операций отношений, но строки при этом должны иметь равную длину.
В Турбо-Паскале введён тип данных String вместо описанного Packed Array of Char.
Операции с Char:
'5' < '25' {ошибка, так как разные длины строк}
'Var' = 'Var' {верно}
Var
Age: String [3];
Begin
Age:="тринадцать"; {Лишние символы после "и" усекаются}
Множества
Паскаль позволяет оперировать с множествами как с типами данных.
Пример:
Type
Symbolset = Set Of ' ' .. '_';
Color = (White, Blue, Red);
Colorset = Set Of Color;
T1= Set Of 0..9;
Var
C: Color;
Colset: Colorset;
T: Integer;
Tset: T1;
Множества- наборы однотипных объектов, каким-либо образом связанных между собой. Характер связей лишь подразумевается программистом и никак не контролируется Турбо-Паскалем. Максимальное количество элементов множества - 256.
Два множества считаются эквивалентными тогда и только тогда, когда все элементы их одинаковы, причём порядок следования элементов безразличен.
Описание:
<имя типа> = Set Of <базовый тип>, где <базовый тип> есть любой порядковый тип кроме Word, Integer, Longint. Для задания множества используется конструктор множества (((: : =))). Список спецификаций элементов множества, отделяемых друг от друга запятыми; список обрамляется [ ]. Спецификациями элементов могут быть константы или выражения базового типа, а так же тип - диапазон того же базового типа:
Type
Digitchar = Set Of '0'..'9';
Digit =Set Of 0..9;
Var
S1, S2, S3: Digitchar;
S4, S5, S6: Digit;
begin
. . . . . . . . . . . . . . . .
S1 : = ['1', '2', '3'];
S2 : = ['3', '2', '1'];
S3 : = ['2', '3'];
S4 : = [0..3, 6];
S5 : = [4, 5];
S6 : = [3..9];
Итак, над множествами допустимы четыре операции:
• объединение (+)
• пересечение (*)
• разность (-) (содержит элементы из 1-го, которых нет во 2-ом).
• операция in - позволяет определить, принадлежит элемент множеству или нет.
Записи
Запись - наиболее общий и гибкий структурированный тип в Паскале.
Запись состоит из фиксированного числа компонентов, называемых полями, которые могут быть различных типов. Этим запись существенно отличается от массива, все компоненты которого должны быть одного и того же типа и доступ к компонентам осуществляется не по индексам (номерам), а по именам.
Пример:
Type
Date = Record
Year: Integer;
Month: 1..12;
Day: 1..31;
End;
Book = Record
Title: String [40];
Author: String [50];
Entry: Date;
End;
Var
D1: Date;
B: Book;
54. Типизированные константы.
Типизированные константы
Описываются в разделе констант: <идентификатор> : <тип> = < значение >
В ходе выполнения программы можно присваивать другие значения. При повторном входе в блок (процедуру или функцию), в котором объявлена типизированная константа, переинициализации не происходит и она сохраняет то значение, которое имела при выходе из блока. Могут быть любого типа, кроме файлов. Нельзя так же объявить типизированную константу-запись, если хотя бы одно её поле файлового типа. Нельзя использовать в качестве значения при объявлении других констант или границ типа-диапазона.
Примеры:
1. Типизированные константы простых типов и типа String:
Type
Colors = (White, Red, Black);
Const
{Правильные объявления}
Cyrrcol: Colrs = Red;
Name: String = 'Ку-Ку';
Year: Word = 1989;
X: Real = 0.1;
Min: Integer = 0;
Max: Integer = 10;
Days: 1..31 = 1;
Answer: Char = 'Y';
2. Типизированные константы-массивы
В качестве начального значения используется список констант, отделённых друг от друга запятыми, список заключается в круглые скобки:
Type
Colors = (White, Red, Black);
Const
Colstr: Arrray [Colors] Of String [5] = ('White', 'Red', 'Black');
Vector: Array [1..5] Of Byte = (0, 0, 0, 0, 0);
При объявлении массива символов можно использовать то обстоятельство, что все символьные массивы и строки в Турбо- Паскале хранятся в упакованном формате,.поэтому в качестве значения массива-константы типа Char допускается указывать символьную строку:
Const
Digit: Array [0..9] Of Char = ('0','1','2','3','4','5','6','7','8','9');
Digchr: Aray [0..9] Of Char = ('0123456789');
3. Типизированные константы-записи.
<идентификатор>:<тип> = (<список значений полей>)
<тип> - предварительно объявленный тип записи.
<список значений полей > - список из последовательностей следующего вида: имя поля, двоеточие и константа; элементы списка отделятся друг от друга точкой с запятой.
Пример:
Type
Point = Record
X,Y: Real;
End;
Vect = Array [0..1] Of Point;
Month = (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec);
Date = Record
D: 1..31;
M: Month;
Y: 1900..1999;
End;
Const
Orign: Point = (X: 0; Y: -1);
Line: Vector = ((X: -3.1; Y: 1.5), (X: 5.9; Y: 3.0));
Someday: Date = (D: 16; M: Mar; Y: 1989);
4. Типизированные константы множества.
Значение типизированной константы множества задаётся в виде правильного конструктора множества:
Type
Days = Set Of 1..31;
Dige = Set Of '0'..'9';
Error = Set Of 1..24;
Const
Workdays: Days = [1..5, 8..12, 15..19, 22..26, 29, 30];
Evendigits: Dige = ['0', '2', '4', '6', '8'];
Errorflag: Error = [ ];
5. Типизированные константы указатели.
Единственным значением типизированной константы указателя может быть только Nil:
Const
Pr: ^Real = Nil;
P: POINTER = Nil;
55. Совместимость и преобразование типов.
Два типа считаются совместимыми, если
• оба они есть один и тотже тип.
• один тип есть тип-диапазон второго типа.
• оба они являются типами-диапазонами одного и того же базового типа.
• один тип есть строка, а другой - строка или символ.
• оба они есть процедурные типы с одинаковым типом результата (для типа-функции), одинаковым количеством параметров и одинаковым типом взаимно соответствующих параметров.
В Турбо-Паскалевской программе данные одного типа могут преобразовываться в данные другого, явным или неявным образом.
При явном преобразовании используются специальные функции Ord, Trunc, Round, Chr, Ptr (преобразует четырёхбайтный целочисленный аргумент к типу-указателю).
Преобразование может достигаться применением идентификатора (имени) стандартного типа, или определённого пользователем типа, в качестве идентификатора функции преобразования к выражению преобразуемого типа (так называемое автоопределённое преобразование типов). Например, допустимы следующие вызовы функций:
Type Mytype = (A, B, C, D);
. . . . . . . . . . . . . . . . .
Mytype (2);
Integer (D);
Pointer (Longint (A) + $FF);
Char (127 Mod C);
Byte (K);
При автоопределённом преобразовании типа выражения может произойти изменение длины его внутреннего представления (уменьшение или увеличение).
В Турбо-Паскале есть ещё один явный способ: в ту область памяти, которую занимает переменная некоторого типа, можно поместить значение выражения другого типа, если только длина внутреннего представления вновь размещаемого значения в точности равна длине внутреннего представления переменной. С этой целью вновь используется автоопределённая функция преобразования типов, но уже в левой части оператора присваивания:
Type
Byt = Array [1..2] Of Byte;
Int = Array [1..2] Of Integer;
Rec = Record
X: Integer;
Y: Integer;
End;
Var
VByt: Byt;
VInt: Int;
VRec: Rec;
Begin
Byt (VInt[1])[2]:= 0;
Int (VRec)[1]:= 256;
End.
Неявное преобразование типов возможно только в двух случаях:
• выражение из целых и вещественных приводится к вещественным
• одна и та же область памяти трактуется попеременно как содержащая данные то одного, то другого типа.
Совмещение данных может произойти при использовании записей с вариантами, типизированных указателей, содержащих одинаковый адрес, а также при явном размещении данных разного типа в одной области памяти (используется Absolute - за ним помещается либо абсолютный адрес, либо идентификатор ранее определённой переменной).
Абсолютный адрес- пара чисел, разделённых двоеточием - первое - сегмент, второе - смещение.
Пример:
B: Byte Absolute $0000:$0055;
W: Longint Absolute 128:0;
Если за Absolute указан идентификатор переменной, то происходит совмещение в памяти данных разного типа, причём первые байты внутреннего представления данных будут располагаться по одному и тому же абсолютному адресу:
Var
X: Real;
Y: Array [1..3] Of Integer Absolute X;
56. Общая структура подпрограммы. Механизм параметров.
Параметры-значения и параметры-переменные, безтиповые параметры.
В заголовке подпрограммы может быть задан список формальных параметров. Каждый параметр, заданный в заголовке, считается локальным в данной подпрограмме. Идентификаторы формальных параметров можно считать условными обозначениями реальных (фактических) параметров, которые будут переданы в подпрограмму при её вызове.
Внимание: Типы формальных параметров должны обязательно обозначаться идентификаторами.
Недопустимо:
Procedure InCorrect (Var A: Array [1..10] of Byte);
Нужно:
Type
MyArray = Array [1..10] of Byte;
Procedure Correct (Var A: MyArray);
Допустимы по крайней мере три способа задания формальных параметров:
a. параметры, перед которыми отсутствует служебное слово Var и за которыми следует идентификатор типа;
b. параметр, перед которым Var и далее тип;
c. параметр со словом Var и не имеющие типа.
Эти три способа задания формальных параметров отражают три различных способа передачи параметров a - по значению; b - по ссылке; c - передача нетипизированных параметров по ссылке (b, c - параметры-переменные).
Параметры - значения.
Наиболее распространенный и простой способ. Параметр - обычная локальная переменная. Может использовать выражение. Любые действия внутри подпрограммы никак не отражаются на значениях переменной вне подпрограммы.
Параметры - переменные.
Передаются по ссылке. Способ используется, когда необходимо передать некоторое значение в точку вызова подпрограммы. В случае Var - формальные параметры считаются синонимами соответствующих фактических параметров. При этом фактические параметры должны быть переменными (не выражениями) того же типа, что и формальные параметры:
Procedure Swap (Var X,Y: Real);
Var
T: Real;
Begin
T:= X;
X:= Y;
Y:= T;
End;
Переменные файловых типов могут передаваться в подпрограмму только как параметры - переменные.
Безтиповые параметры.
Var Ident, где Ident - идентификатор формального параметра.
Фактический параметр, соответствующий формальному нетипизированному, должен представлять собой переменную любого типа (но не выражение).
Единственным способом использования таких параметров является “наделение” их определённым типом.
57. Процедурные типы.
Процедурные типы
Турбо-Паскаль позволяет вводить переменные специального типа, значениями которых могут служить подпрограммы. Можно интерпретировать подпрограмму как значения, которые можно присваивать переменным и передавать их в качестве параметров (речь идёт о подпрограммах как о целостных объектах, а не о значениях, возникающих в процессе их выполнения).
{$F+}
Var
P: Procedure;
Значениями Р могут быть любые процедуры без параметров. В более общем случае:
Type
Func = Function(X,Y: Integer): Integer;
Var
F1,F2: Func;
Например, если есть функция:
Function Add(A,B: Integer): Integer;
Begin
Add:= A + B;
End;
то допустимо F1:= Add, в этом случае переменной F1 присваивается функция Add как таковая, но её исполнения не происходит.Теперь можно:
Write (Add (1,2)) или Write (F1 (1,2));.
Следует обратить внимание на строку {$F+} – она существенна, это ключ компилятора, и если он выключен, при присвоении переменным процедурного типа значений конкретных подпрограмм, возникнет ошибка присвоения типа.
Имена формальных параметров, указываемые в процедурных типах, играют часто иллюстративную роль и на смысл определений никакого влияния не оказывают. Необходимыми являются только идентификаторы типов параметров и результатов (для функций).
Процедурные типы допускают также присвоение вида F1:= F2;
Такие переменные можно использовать для вызова подпрограмм, которые присвоены этим переменным.
Пример:
Var
Oper: Function(X, Y: Real): Real;
Function Add(A,B: Real): Real;
Begin
Add:= A + B;
End;
Function Sub (A,B: Real): Real;
Begin
Sub:= A - B;
End;
Процедурные типы, чтоб они были совместимыми по присваиванию, должны иметь одинаковое количество формальных параметров, а параметры на соответствующих позициях должны быть одного типа. Также, должны совпадать типы возвращаемых значений у функций.
Использование процедурных типов не ограничиваются простыми процедурными переменными. Как и любой другой тип, процедурные типы могут участвовать в построении структурированных типов:
Type
Proc = Procedure(T: Real);
Notice = Record
Next: Integer;
Time: Real;
Action: Proc;
End;
Var
New_Notices: Array[1..10] of Proc;
Notices: Notice;
Правила корректной работы с процедурными типами.
- Подпрограмма, присваиваемая процедурной переменной должна быть странслирована в режиме “дальнего вызова”.
· Подпрограмма, присваиваемая процедурной переменной, не должна быть стандартной процедурой или функцией. Это ограничение легко обойти:
Подпрограмма, присваиваемая процедурной переменной, не может быть вложенной в другие подпрограммы.
- Подпрограмма, присваиваемая процедурной переменной, не может быть подпрограммой специального вида (interrupt или inline).
Можно описывать процедуры и функции, параметрами которых являются процедурные переменные. Таким образом, можно организовать подпрограмму, которая будет выполнять некоторое общее действие для различных подпрограмм - параметров. В общем случае использование процедурных переменных в операторе или выражении означает вызов присвоенной данной переменной процедуры или функции.
Необходимо помнить, что если в левой части оператора стоит процедурная переменная, правая часть его должна представлять идентификатор другой процедурной переменной или идентификатор подпрограммы.
Чтобы сравнить значение переменной F со значением (адресом) подпрограммы FFF нужно использовать следующую конструкцию:
If @F = @FFF then . . . .
Чтобы получить адрес самой процедурной переменной нужно написать:
@@F
Приведение типов переменных для процедурных типов.
Определены следующие типы и переменные:
Type
Func:= Function(X: Integer): Integer;
Function MyFunc(X: Integer): Integer;
Begin
MyFunc:= X;
End;
Var
F: Func;
P: Pointer;
N: Integer;
Можно построить следующие присваивания:
F:= MyFunc | {переменной F присваивается функция MyFunc} |
N:= F(N) | {функция MyFunc вызывается через переменную F} |
P:= @F | {P получает указатель на функцию MyFunc} |
N:= Func (P)(N) | {функция MyFunc вызывается через указатель P} |
F:= Func (P) | {присвоить значение подпрограммы в P переменной F} |
Func(P):= F | {присвоить значение подпрограммы в F указателю P} |
@F:= P | {присвоить значение указателя в P переменной F} |
58. Модули.
Структура модулей
Модуль имеет следующую структуру:
Unit < имя >;
Interface
< интерфейсная часть >
Implementation
< исполняемая часть >
[ Begin < инициирующая часть > ]
End.
Здесь:
Unit - кодовое слово (англ. модуль); начинающее заголовок модуля;
<имя> - имя модуля (правильный идентификатор);
Interface - кодовое слово, начинающее интерфейсную часть модуля;
Implementation - кодовое слово (англ. реализация); начинает исполняемую часть;
Begin - кодовое слово, начинающее инициирующую часть;
(часть модуля Begin < инициирующая часть > необязательна);
End. - признак конца модуля.