Содержание     Символьные строки Множества Записи Совместимость типов Типизированные константы  
 

 

Простые и структурные типы данных

 

1. Перечисляемый и ограниченный типы

Ранее рассматривались простые стандартные типы данных (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 ('Весенний месяц');

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

Пример:
процедура, в которой переменной перечисляемого типа присваивается значение, в зависимости от введенного дня недели; если введённые символы ошибочны, возвращается соответствующее сообщение.

Program DAY (Input, Output);
Type
  DayOfWeek = (Sun, Mon, Tue, Wen, Thu, Fri, Sat);
Var
  D: DayOfWeek;
  Well: Boolean;

Procedure Read_WD (Var I: DayOfWeek;Well: Boolean;);
Var
  C: Char;
Begin
  Read(C);
  Well:= False;
  Case C Of
    "S": Begin
    Readln(C);
    Case C Of
      "U": Begin
      I:= Sun;
      Well:= True;
    End;
    "A": Begin
    I:= Sat;
    Well:= True;
    End;
  End;{Of Case}
  "M": Begin
    Well:= True;
     I:= Mon;
      End;
  "T": Begin Readln(C);
  Case C Of
   . . . . . . . . .
  End;
  "W": Begin
    Well:= True;
    I:= Wen;
  End;
  "F": Begin
    Well:= True;
    I:= Fri;
  End;
 End;
End;
Begin
  Read_WD(D, Well);
  If Not Well Then
  Writeln ('Ошибка');
End.

Кроме перечисленного типа можно вводить ограниченные или интервальные типы.

Пример:
Type
Year = 1900..2000;
Letter = "A".."Z";

Левая и правая константы задают диапазон значений и их называют соответственно верхней и нижней границей ограниченного типа.

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

Пример:
Type
  Days = (Mo, Tu, We, Th, Fr, Sa, Su);
  WeekEnd = Sa..Su;
Var
  W: WeekEnd;
. . . . . . . . . . . .
Begin
. . . . . . . . . . . .
  W:= Sa;
. . . . . . . . . . . ,

Так как тип-диапазон наследует все свойства базового типа, но с ограничениями, связанными с его меньшей мощностью, то Ord(W) вернёт значения S , в то время как Pred(W) приведёт к ошибке.

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

Описание массивов:
Var
  Mas: Array [1..15] Of Real.
  Work: Array [(Mon, Tue, Wed)] Of Integer.
  B: Array ['A'..'Z'] Of Boolean.
  C: Array [1..3, 1..5] Of Real.
  D: Array [(Black, White)] Of 11..20.

В Паскале многомерный массив можно описать как одномерный:
Type
   Mas = Array [1..3] Of Array [1..5] Of Integer;
Var
   A, B: Mas;
   C: Array [1..3, 1..5] Of Integer;
{такая же структура но определена как двумерный массив}

Ссылка на элемент матрицы А, лежащий на пересечении I-той строки и J-ого столбца выглядит следующим образом A[I][J]; законно и такое обращение A[2]:= B[1], для массива такая запись не верна. Все элементы структурированных типов допускают A:= B (исключение - переменные файлового типа).

Можно использовать комформант - массивы. Массивы с переменными границами в Турбо-Паскале использовать нельзя. Нельзя, также и сравнивать массивы:
If A = B Then ...
В Турбо-Паскале предварительно определены два массива Mem и Port.

2. Символьные строки

Переменную типа Packed Array [0..N] of Char принято называть символьной строкой.

Строка - это упакованный массив, компоненты которого имеют тип Char и тип индекса имеет нижнюю границу равную одному. К строкам применимы все 6 операций отношений, но строки при этом должны иметь равную длину.

В Турбо-Паскале введён тип данных String вместо описанного Packed Array of Char.

Операции с Char:
'5' < '25' {ошибка, так как разные длины строк}
'Var' = 'Var' {верно}
Var
Age: String [3];
Begin
Age:="тринадцать"; {Лишние символы после "и" усекаются}

3. Множества

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

Пример:
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];

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

* пересечение (S4*S6 = [3,6]; S4*S5 = [4])
+ объединение (S4+S5 = [0, 1, 2, 3, 4, 5, 6])
- разность, содержит элементы из 1-го, которые не принадлежат второму (S6-S5 = [3, 6, 7, 8, 9])
= проверка эквивалентности (S4=S4 = true; S5=S4 = false)
<> проверка неэквивалентности (S4<&gtS4 = false; S5<&gtS4 = true)
<= проверка вхождения (True если 1-е содержится во втором).
>= (наоборот).
in проверка принадлежности.

Пример:
Алгоритм получение простых чисел.
Const
  N = 100;
Type
  Set_Of_Num = Set Of 1..N;
Var
  N1, Next, I: Word;
  Begset, Primerset: Set_Of_Num;
Begin
  Begset:= [2..N];
  Primerset:= [1];
  Next:=2;
  While Begset <> [ ] Do
   Begin
   N1:= Next;
     While N1 <= N Do
      Begin
      Begset:= Begset - [N1];
      N1:= N1 + Next;
      End;
   Primerset:= Primerset + [Next];
  Repeat
    Inc(Next);
  Until (Next In Begset) Or (Next > N);
  End;
  For I:=1 To N Do
    If I In Primerset Then
  Write(I: 8);
  Writeln;
End.

Итак, над множествами допустимы четыре операции:

• объединение (+)
• пересечение (*)
• разность (-) (содержит элементы из 1-го, которых нет во 2-ом).
• операция in - позволяет определить, принадлежит элемент множеству или нет.

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

Colset:= [White, Red];
Colset:= [ ];
Tset:= [1, 7, 5];
Tset:= [0 ... 3, 6, 9];
Tset:= [8 Mod4, 15 Div 5];

Можно использовать операции сравнения.

Пример: из файла вводится текст, содержащий символы от "+" до "[". Требуется рассчитать символы текста в порядке кода ASCII (из повторно встречающихся выводить только один):

Program Sort
Var
  S: Char;
  Sets: Set Of '+'..'[';
  I: '+'..'[';
Begin
  Sets:= [ ];
  Read(S);
  While Not Eof Do
  Begin
     While Not Eof Do
     Begin
       Sets: = Seets + [S];
       Read(S);
     End;
  End;
  Writeln;
  For I: ='+' To '[' Do
   If I In Sets Then
  Write (I);
  Writeln;
End.

4. Записи

Запись - наиболее общий и гибкий структурированный тип в Паскале.

Запись состоит из фиксированного числа компонентов, называемых полями, которые могут быть различных типов. Этим запись существенно отличается от массива, все компоненты которого должны быть одного и того же типа и доступ к компонентам осуществляется не по индексам (номерам), а по именам.

Пример:
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;

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

Пример1:
D1.Day:=25;
B.Author:= "Levy";
B.Entry.Year:= 1980;

а можно и

B. Entry: = 1980; так как Year первое поле Date.

Пример2: В памяти находится массив из 1000 элементов, каждый из которых имеет тип записи Book. Определить количество книг, год издания которых меньше или равен 1600 году. Для каждого из таких элементов массива распечатать название книги, имя автора, год издания:

Program Rarity;
Type
Date = Record
. . . . . . . . . . .
End;
Book = Record
. . . . . . . . . . .
End;
Var
  S, I: Integer;
  Mas: Array[1..1000] Of Book;
Begin
  S:= 0;
  For I:= 1 To 1000 Do
    If Mas[I].Entry.Year <= 1600 Then
    Begin
      Write (Mas[I].Title,}' , ',Mas[I].Author,',' , ',Mas[I].Entry.Year: 6);
      S:= S+1;
    End;
   Writeln ('Число Книг' , S: 4);
End.

Оператор присоединения With.
Можно сократить длинные обозначения элементов записи:

With имя записи Do оператор.

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

Пример:
With B Do
Begin
  Title: = ' ... ';
  Author:= ' ... ';
End;

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

B.Title: = ' ... ';
B.Author:= ' ... ';

5. Запись с вариантами

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

Пример:
Type
  N = String [20];
  Status = (Женат, Вдов, Разведён, Холост);
  Date = Record
     Mo: 1..12;
     Day: 1..31;
     Year: Integer;
  End;
  Person = Record
    Name: N;
    Sex: (Муж, Жена);
    Birth: Date;
    Case Ms: Status Of
    Женат, Вдов: (MDate: Date);
    Разведён: (Date: Date; First: Boolean);
    Холост: (Indept: Boolean);
  End.

Замечательная особенность - наложение в памяти вариантных полей, то есть дополнительная возможность преобразования типов:

Var
  M = Record
  Case Byte Of
    0: (By: Array[0..3] Of Byte);
    1: (Wo: Array[0..3] Of Word);
    2: (Lo: Longint);
  End;
. . . . . . . . . . . . . .
With M Do
Begin
  Lo: . . . . . .;
  If By [3] = 2 Then ... ;

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

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

Пример:
Type
  Rec1 = Record
    A: Byte;
    B: Word;
  End;
  Rec2 = Record
    C: Longint;
    Case X: Byte Of
      1: (D: Word);
      2: (E: Record);
      Case Boolean Of
        3: (F: Rec1);
        3: (G: Single);
        '3': (C: Word);
      End;
    End;

Var
  2: Rec2
   . . . . . . . . . .
R.X: = 255;
If R.E.G = 0 Then
  Writeln (0K)
Else
  Writeln (R.E.G);
Имена полей должны быть уникальными в пределах той записи, где они объявлены, однако если записи содержат поля-записи то есть вложены одна в другую, имена могут повторяться на разных условиях вложенности.

6 Совместимость и преобразования типов

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

Два типа считаются совместимыми, если

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

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

При явном преобразовании используются специальные функции 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;

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

Описываются в разделе констант: <идентификатор> : <тип> = < значение >
В ходе выполнения программы можно присваивать другие значения. При повторном входе в блок (процедуру или функцию), в котором объявлена типизированная константа, переинициализации не происходит и она сохраняет то значение, которое имела при выходе из блока. Могут быть любого типа, кроме файлов. Нельзя так же объявить типизированную константу-запись, если хотя бы одно её поле файлового типа. Нельзя использовать в качестве значения при объявлении других констант или границ типа-диапазона.

Примеры:
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';
 
{Неправильные объявления}
Mars: Arrray [Min..Max] Of Real;
A,B,C: Byte = 0;
X: Real = Pi;
 
Var
Namef: String [22] = 'Prog.Pas';

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');

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

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

Пример - вывести на экран три строки с монотонно увеличивающимися целыми числами:

Var
  I, J, K, L: Integer;
Const
  Matr: Array [1..3, 1..5] Of Byte = ((0, 1, 2, 3, 4), (5, 6, 7, 8, 9), (10, 11, 12, 13, 14));
  Cube: Array [0..1, 0..1. 0..2] Of Integer = (((0, 1, 2),(3, 4, 5)), ((6, 7, 8),(9, 10, 11)));
  Mas4: Array [0..1, 0..1, 0..1, 0..1] Of Word = ((((0, 1), (2, 3)), ((4, 5), (6, 7))), (((8, 9),
  (10, 11)), ((12, 13), (14, 15))));
Begin
  {Циклы и Writeln}
End.

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

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);

Для записей с вариантными полями указывается только один из возможных вариантов констант:

Type
  Forma = Record
    Case Boolean Of
    True:
    (Place: String [40]);
    False:
    (Country: String [20];
    Port: String [20];
    Date: Array[1..3] Of Word;
    Count: Word)
  End;
Const
  Con1: Forma = (Country: 'Россия';
  Port: 'Москва';
  Date: (16,3,89);
  Count: 10);
  Con2: Forma = (Place: 'Петрозаводск');

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;