Скалярные, пользовательские типы данных
Перечисляемый тип является скалярным, порядковым типом, но не является стандартным типом и определяется набором идентификаторов, с которыми будут совпадать значения переменной этого типа. Перечисляемый тип определяется в разделе Type следующим образом:
Type <имя типа>=(< идентификатор 1 >, < идентификатор 2>, …, < идентификатор n>);
Например, Type Week= (mon, twe, wen, tru, fri, sut, sun);
Интервальный тип в языке Паскаль определяется следующим образом. В любом порядковом типе можно выделить подмножество значений, определяемое минимальным и максимальным значением. Интервальный тип называется типом-диапазоном и определяется в разделе Type следующим образом:
Type <имя типа> = <мин. значение>..<макс. значение>;
Например,
Type A=1..100;
Структурные типы данных
Структурные или составные типы данных определяют наборы однотипных или разнотипных компонент. Типы компонент могут быть как скалярными, так и составными.
В языке Паскаль существуют следующие составные типы данных:
· тип-массив;
· строковый тип;
· тип-запись;
· тип-запись-с-вариантами;
· тип-множество;
· тип-файл.
Массивы
Данными типа «массив» являются массивы. Массив представляет собой фиксированное количество компонент одного и того же типа. Массив определяется именем, количеством размерностей (координат), необходимых для указания месторасположения элемента в массиве, типом элементов и типами индексов.
Массивы могут быть одномерными и многомерными. Для объявления типа-массива в разделе Type используется ключевое слово array:
Type
<имя типа-массив>=array[<тип индекса1>,<тип индекса2>, …] of <тип элементов>;
Тип индекса обычно задается интервальным типом или типом-диапазоном порядкового типа:
<номер первого элемента>.. <номер последнего элемента>.
Например, объявление типа:
Type V=array[1..10] of integer;
определяет тип-массив из 10 элементов целого типа integer.
Массивы в программах могут быть константами или переменными.
Переменные типа-массив объявляются в разделе Var с помощью ключевого слова array следующим образом:
Var
<имя массива>:array[<тип индекса(ов)] of <тип элементов>;
Например,
Var M1: array[1..10] of real;
Mt: array[1..5,1..5] of real;
Границы изменения индексов можно задать в разделе Const; например,
Const k=10;
m=4;
n=5;
Var A: array[1..k] of integer;
B: array [1..m,1..n] of real;
Массивы- константы объявляются в разделе Const следующим образом:
Const <имя массива>: <описание массива>=(<список значений элементов>);
Например,
Const A: array[1..5] of integer=(1,2,3,4,5);
Const B: array[1..3,1..2] of integer=((1,2),(2,3),(3,4));
Значения элементов массивов-констант не изменяются в программе.
Доступ к элементам массивов осуществляется с помощью индексированных переменных, которые записываются с помощью имени массива и списка индексов в квадратных скобках:
<имя массива >[< индекс 1 >,< индекс 2>, …< индекс n>]
На практике обычно используются одномерные и двумерные массивы.
В случае одномерного массива в списке индексов указывается только один индекс, который может быть константой, переменной или арифметическим выражением целого типа. Элементы массива размещаются в памяти ЭВМ в непрерывном участке памяти один за другим.
Одномерный массив – аналог понятия «вектор» в математике.
Двумерный массив можно представить в виде прямоугольной таблицы из m строк и n столбцов.
A[1,1]
| A[1,2]
| …
| A[1,n]
| A[2,1]
| A[2,2]
| …
| A[2,n]
| …
| …
| …
| …
| A[m,1]
| A[m,2]
| …
| A[m,n]
|
Двумерный массив объявляется в разделе VAR следующим образом:
<имя массива>: array[<тип индекса1>,< тип индекса2>] of <тип элементов >;
где тип индекса 1 определяет тип индекса для строк; тип индекса 2 определяет тип индекса для столбцов.
Например, объявление Var M: array[1..10,1..8] of real; определяет двумерный массив из 10 строк и 8 столбцов.
Двумерные массивы размещаются в памяти ЭВМ по строкам:
A[1,1]
| A[1,2]
| …
| A[1,n]
| …
| A[m,1]
| A[m,2]
| …
| A[m,n]
| 1-я строка m-я строка
Строки
Данные строкового типа, или строки, представляют собой последовательности символов произвольной длины. Строку можно рассматривать как одномерный массив символов. В языке Borland Pascal 7.0 используются две разновидности строкового типа:
§ тип string;
§ тип Pchar.
Строка типа string объявляется в разделе описаний переменных следующим образом:
Var
<имя переменной строкового типа>: string[<максимальная длина строки>];
Максимальная длина строки может быть не задана, тогда она равна 255 символам. Строка отличается от массива тем, что первый элемент строки имеет индекс 0 и служит для хранения текущей длины строки. Символы в строке нумеруются с единицы. Каждый символ занимает один байт. Таким образом, индекс элементов строки изменяется от нуля до максимальной длины строки.
Объявление строки вида
Var S1: string[10];
эквивалентно объявлению массива символов
Var S1: array [0..10] of char;
Если символьный массив объявлен как строка типа string, то нулевой символ будет заполняться автоматически Паскаль - системой. Если символьный массив объявлен как массив типа char, то нулевой символ не будет заполняться автоматически.
Символьная строка размещается в памяти ЭВМ следующим образом:
0 1 2 L N
где N – максимальная длина строки, L – текущая длина строки.
Для работы со строками в Паскале используется операция сцепления строк, которая добавляет в конец первой строки вторую строку. Например,
Program Stroki;
Var Str1, Str2, Str: string[80];
Begin
Str1:=’Turbo ’;
Str2:=’Pascal’;
Str:=Str1+Str2;
Writeln(‘Str=’,Str);
end.
В результате работы этой программы на экране будет отображено:
Str=Turbo Pascal
Следующие процедуры и функции модуля System используются для обработки символьных строк типа string:
ü Функция Concat(S1,S2,…,Sn) выполняет объединение нескольких строк S1,S2,…,Sn, где n>=2, возвращает объединенную строку. Если длина результирующей строки больше 255, она усекается до 255 символов.
ü Функция Copy(S1, Ind, Count) создает и возвращает подстроку строки S1, которая начинается с символа с номером Ind и имеет длину, равную Count.
ü Процедура Delete(S1, Ind, Count) удаляет подстроку из строки S1, которая начинается с символа с номером Ind и имеет длину, равную Count.
ü Функция Length(S1) определяет текущую длину строки S1.
ü Процедура Str(X,S) преобразует значение арифметического выражения X в строку S.
ü Процедура Insert(S1, S2, Ind) вставляет строку S2 в строку S1 после символа с номером Ind-1 строки S1.
ü Процедура Val(S, V, C) преобразует строку S в целое или вещественное число и присваивает его переменной V . Если строка S содержит символы, отличающиеся от цифр и других допустимых в числовых константах символов, то преобразования не выполняется а в переменную C помещается номер неправильного символа; С=0, если все символы правильные.
Записи
Запись – это составная структура данных, объединяющая в единое целое фиксированное количество компонент различных типов. Компоненты записи называются полями.
Переменная типа «запись» объявляется в разделе Var с помощью ключевого слова record следующим образом:
Var <имя переменной>: record
<поле 1>: <тип 1>;
<поле 2>: <тип 2>;
……
<поле n>: <тип n>;
end;
Ключевое слово «end» завершает объявление переменной типа «запись».
Количество полей записи может быть любым. Поля записи могут быть простыми переменными любого типа, массивами и другими записями. В разделе описания типов можно объявить имя типа «запись»:
Type <имя типа> = record
<поле 1>: <тип 1>;
<поле 2>: <тип 2>;
……
<поле n>: <тип n>;
end;
Тогда объявление переменной типа «запись» будет иметь следующий вид:
Var <имя переменной>: <имя типа «запись»>;
Например,
Type Tstudent = record
FAM: string[20]; {фамилия}
IM: string[20]; {имя}
OT: string[30]; {отчество}
GR: integer; {год рождения}
NZACH: integer; {номер зачетки}
NGR: string[30]; {номер группы}
end;
Var Zap_St: Tstudent;
Доступ к элементам (полям) записи производится с помощью составного имени:
<имя переменной типа «запись»>.<имя поля>.
Например,
Zap_St.FAM:=’Иванов’; или
Readln(Zap_St.FAM);
Для того, чтобы не писать имя переменной типа «запись» при каждом обращении к ее полям, можно использовать оператор with, называемый оператором присоединения, который имеет следующий синтаксис:
with <список ссылок на переменную> do <оператор>; или
with <список ссылок на переменную> do begin
<операторы>
end;
Например,
Type T_Rec = record
A:integer ;
B: byte;
C: char;
end;
Var Rec: T_Rec;
……….
begin
……….
with Rec do begin
A:=10;
B:=1;
C:=’*’;
End;
Данный оператор with эквивалентен следующей последовательности операторов:
Rec.A:=10; Rec.B:=1; Rec.C:=’*’;
Оператор with используется для того, чтобы не писать полные, составные имена элементов записей.
Константы типа «запись» определяются в разделе Const следующим образом:
Const <имя константы>: <имя типа «запись»>=
(<имя поля 1>:<значение поля 1>;
<имя поля 2>:<значение поля 2>;
…………………………………..
<имя поля n>:<значение поля n >) ;
Например,
Type Data= record
Y: integer;
M: 1..12;
D: 1..31;
End;
Const DR: Data=(Y:1984;
M: 4;
D: 12);
5.4. Записи с вариантами
Записи, рассмотренные выше, относятся к данным постоянной структуры. В языке Паскаль имеется возможность работы с записями переменной структуры, которые называются записями с вариантами. Запись с вариантами включает две части:
· фиксированную часть;
· вариантную часть.
Вариантные компоненты включаются в зависимости от признака. Тип записи с вариантами объявляется следующим образом:
Type <имя типа> = record
Case <признак варианта>: <тип признака> of
<константа 1>: (<описание поля 11>;
< описание поля 12>;
< описание поля 1n1>);
<константа 2>: (<описание поля 21>;
< описание поля 22>;
< описание поля 2n2>);
……
<константа k>: (<описание поля k1>;
< описание поля k2>;
< описание поля knk>);
End;
Например,
Type Coordinates = record
case kind: (dekart,polar) of
dekart: (x, y: real);
polar: (r, fi: real)
End;
В данном примере определено объединение двух взаимно исключающих вариантов. Однако на практике приходится объединять два типа с частично совпадающими компонентами. Для такой ситуации применяется тип «запись с вариантами», который объявляется следующим образом типа:
Type <имя типа> = record
<поле 1>: <тип 1>;
<поле 2>: <тип 2>;
……
<поле n>: <тип n>;
Case <признак варианта>: <тип признака> of
<константа 1>: (<описание поля 11>;
< описание поля 12>;
< описание поля 1n1>);
<константа 2>: (<описание поля 21>;
< описание поля 22>;
< описание поля 2n2>);
……
<константа k>: (<описание поля k1>;
< описание поля k2>;
< описание поля knk>);
End;
Примером записи с вариантами является карточка отдела кадров, которая различается для дипломированных специалистов и работающих студентов:
Type Zap_OK = record
Fio: string[80]; {Фамилия, имя, отчество }
TabN: integer; {}
Otdel: integer; {}
Gpr: integer; {}
Case prizn: byte of
1: (spec_dipl: string[80]; {специальность по диплому}
nom_dipl: string[10]; {номер диплома}
stag: integer); {стаж работы по специальности}
2: (Nmvuz:string[80]; {наименование вуза, где учится сотрудник}
Nk: byte; { номер курса}
P_I_O: byte) {признак использования учебного отпуска}
End;
Множества
Тип-множество, используемый в языке Паскаль, соответствует понятию множества в математике, и создается с помощью следующего конструктора типа:
Type T = set of T0;
где T0 – базовый тип или тип элементов множества.
Значением переменной X типа T являются множества элементов типа T0. Например, тип-множество целых чисел от 1 до 31 может быть описан следующим образом:
Type intset = set of 1..31;
Переменной X типа intset можно присвоить значения с помощью оператора присваивания, например:
Var X: intset;
………………..
X:=[1,4,9,16,25];
Элементы множества записываются в квадратных скобках. Оператор
X;=[]; присваивает переменной Х значение пустого множества.
Операции над переменными типа-множества выполняются по правилам теории множеств.
Операция
| Действие
| Тип операндов
| Тип результата
| +
| Объединение
множеств
| Множество
| Множество
| -
| Разность
множеств
| Множество
| Множество
| *
| Пересечение
множеств
| Множество
| Множество
| =
| Сравнение на
равенство
| Множество
| Булевский тип
| <>
| Сравнение на
неравенство
| Множество
| Булевский тип
| A>=B
| B – подмножество A
| Множество
| Булевский тип
| in
| Определение
принадлежности
множеству
| Левый операнд – базовый
тип; правый – множество
элементов базового типа
| Булевский тип
|
Файлы
Любая программа должна взаимодействовать с внешней средой, выдавая (сохраняя) результаты своей работы и, возможно, получая исходные данные для работы. Под внешней средой понимаются любые устройства, позволяющие осуществлять ввод, вывод и запоминание информации. Взаимодействие с внешней средой, или ввод-вывод данных, в программе выполняется посредством обработки специальных объектов данных – файлов, а точнее, переменных типа «файл».
Файлом называется конечное множество компонент одного и того же типа, расположенных во внешней памяти. Компоненты файла могут быть любого типа. Число компонент не объявляется заранее и может изменяться. Новая компонента добавляется только в конец файла. У понятия файл есть две стороны. С одной стороны , файл – это именованная область внешней памяти, содержащая некоторую информацию. Файл в таком понимании называется физическим файлом. Физический файл имеет имя файла во внешней памяти, которое регистрируется в некотором каталоге (папке) на диске средствами операционной системы.
С другой стороны, файл – это тип данных, определенный в программе как последовательность компонент заданного типа. Файл в таком понимании называется логическим файлом. Тип «файл» в Паскаль – программе можно объявить в разделе TYPE следующим образом:
TYPE <имя типа «файл»>= file of <тип компонент файла>;
Например,
TYPE NumberFL = file of integer;
Объявив тип «файл», можно описывать файловые переменные заданного типа в разделе VAR:
VAR F1: NumberFL;
Тип «файл» можно определять непосредственно при описании файловой переменной, тогда ее объявление имеет следующий вид:
VAR F1: file of integer;
В программе на Паскале все действия с конкретным физическим файлом производятся с использованием файловой переменной с помощью стандартных процедур и функций из библиотеки системы программирования на Паскале (модуль System).
С файлами выполняются следующие операции:
· связывание файловой переменной с конкретным физическим файлом на внешнем устройстве;
· открытие файла для работы в заданном режиме: для чтения, для записи или для добавления;
· чтение информации из файла;
· запись информации в файл;
· закрытие файла.
Кроме того, в модуле System содержатся процедуры и функции, позволяющие работать с папками: создавать, удалять и переименовывать папки, а также удалять и переименовывать файлы.
Способ объявления файловой переменной определяет вид файла, способ хранения информации в файле и стандартные процедуры и функции, используемые для обработки файла. Файловую переменную можно задать одним из трех способов:
VAR F1: file of <тип компонент>;
F2: text;
F3: file;
где F1 – типизированный файл; каждая его компонента имеет заданный тип;
F2 – текстовый файл; его компоненты – строки символов;
F3 – нетипизированный файл; тип его компонент не указан, что делает его совместимым с любыми файлами.
Доступ к компонентам файлов.
Любой программе на Паскале[5] доступны без каких-либо предварительных объявлений два файла со стандартными файловыми переменными:
Input – для чтения данных со стандартного устройства ввода (клавиатуры);
Output – для вывода на стандартное устройство вывода (видеомонитор).
Все другие файлы становятся доступными программе после объявления файловой переменной и ее связывания с физическим файлом.
Процесс обработки файла можно представить в виде блок-схемы, показанной на рис. 5.1.
Связывание файловой переменной с физическим файлом выполняет процедура Assign, обращение к которой имеет вид:
Assign(<имя файловой переменной>,<имя файла на внешнем устройстве>);
где <имя файловой переменной> - это переменная типа «файл», объявленная в программе;
<имя файла на внешнем устройстве> - это строка символов, содержащая полное имя файла на диске и, возможно, путь к этому файлу.
Например,
Assign(F1,’c:\prog1.txt’);
Assign(F2,’a:\c1\data1.txt’);
Имя физического файла может вводиться пользователем с клавиатуры. Например,
VAR Name: string;
F2: file of integer;
………………………..
write(‘Введите имя файла: ’);
readln(Name);
assign (F2,Name);
…………………………
В этом фрагменте программы в качестве второго аргумента процедуры assign используется переменная Name, значение которой - строка, содержащая имя физического файла.
После связывания файловой переменной с файлом на внешнем устройстве его необходимо открыть для обработки в режиме чтения или записи. Для любых типов файлов для открытия в режиме чтения используется стандартная процедура reset, обращение к которой имеет вид:
reset(<имя файловой переменной>).
Процедура reset предполагает, что открываемый файл существует. В противном случае, возникает ошибка. При открытии файла создается указатель текущей позиции файла и устанавливается на первую компоненту файла. Указатель текущей позиции файла отмечает ту компоненту файла, которая доступна для чтения в текущий момент во время выполнения программы. Компоненты файла нумеруются с нуля.
Для открытия файла в режиме записи используется стандартная процедура rewrite, обращение к которой имеет вид:
rewrite (<имя файловой переменной>).
Процедура rewrite допускает, что открываемый файл существует. Если открываемый файл отсутствует, то он будет сначала создан на внешнем устройстве, а затем открыт. При открытии файла создается указатель текущей позиции файла и устанавливается на первую компоненту файла. Если файл уже существовал, то после выполнения процедуры rewrite все данные этого файла стираются, и запись информации производится в начало файла.
Процедура открытия существующего файла в режиме добавления append применима только к файлам типа text. Обращение к процедуре append имеет следующий вид:
append(<имя файловой переменной типа text>). Если открываемый файл отсутствует, то при выполнении процедуры append возникает ошибка ввода-вывода. При открытии файла в режиме добавления новые данные записываются в конец файла.
Завершение действий с любым файлом выполняется процедурой close (<имя файловой переменной>). Работа с файлами осуществляется с использованием буферов в оперативной памяти. Одним из действий процедуры close является очистка буферов ввода-вывода. Без выполнения этой процедуры часть информации, предназначенная для записи в файл, может быть потеряна.
При работе с файлами автоматически проверяются ошибки ввода-вывода. Если проверка включена по умолчанию или с помощью директивы компилятора{$I+}, то при возникновении ошибки выполнение программы автоматически завершается. Если проверка выключена с помощью директивы{$I-}, то программа продолжает работу и проверить результат можно с помощью стандартной функции IOResult. Функция IOResult возвращает код завершения последней операции ввода-вывода. Если IOResult равно нулю, то завершение операции – успешно. Например, в записанном ниже фрагменте программы проверяется корректность открытия существующего файла:
VAR
F1: text;
Fn: string;
……………..
begin
……………….
write(‘Введите имя файла: ’);
readln(Fn);
assign (F2,Fn);
{$I-}
reset(F1);
{$I+}
If IOResult<>0 then begin
Writeln(‘файл не найден!’); Halt;
end;
……………………………..
Процедура Halt производит немедленное завершение выполнения программы.
Процедуры ввода-вывода для текстовых файлов.
Текстовый файл в программе объявляется через файловую переменную типа text и представляет собой последовательность символьных строк переменной длины, разделенных специальным символом«конец строки». В конце текстового файла размещается признак «конец файла».
Эти признаки проверяются соответствующими стандартными функциями, возвращающими логическое значение:
q Eoln(<имя файловой переменной типа text >) – возвращает значение true, если достигнут конец строки;
q Eof(<имя файловой переменной типа text >) – возвращает значение true, если достигнут конец файла.
Текстовый файл содержит символьную информацию, которая считывается из файла с помощью стандартных процедур:
q Read(<имя файловой переменной >,< список ввода >) ;
q Readln (<имя файловой переменной >,< список ввода >).
Процедура Readln в отличие от процедуры Read после ввода всех переменных в списке игнорирует непрочитанные данные до конца текущей строки, и последующее чтение осуществляется с новой строки. Процедура Readln<имя файловой переменной > (без списка ввода) производит переход к следующей строке файла.
Запись данных в текстовый файл осуществляется с помощью стандартных процедур:
q write(<имя файловой переменной >,< список вывода >) ;
q writeln(<имя файловой переменной >,< список вывода >).
Процедура writeln в отличие от процедура write выполняет запись символа «конец строки» и может вызывать без списка вывода: writeln<имя файловой переменной >. Пример программы ввода элементов матрицы из текстового файла приведен в разделе 8.6 данного учебного пособия.
Процедуры ввода-вывода для типизированных файлов
Чтение из типизированных файлов выполняется только с помощью стандартной процедуры
Read(<имя файловой переменной >,< список ввода >).
В списке ввода содержатся переменные того же типа, что и тип файла. При считывании в каждую переменную данных из файла указатель текущей позиции перемещается на следующую компоненту файла. Если указатель текущей позиции файла находится за последним компонентом файла, то достигнут конец файла, и стандартная функция Eof(<имя файловой переменной >) возвратит значение True.
Запись данных в типизированный файл осуществляется с помощью стандартной процедуры:
write(<имя файловой переменной >,< список вывода >) ;
Типизированные файлы заполняются данными последовательно. Доступ по чтению может быть как последовательный , так и прямой. При последовательном чтении все компоненты, начиная с нулевой компоненты, считываются одна за другой до конца файла.
Для работы с файлом в режиме прямого доступа предназначены следующие стандартные процедуры и функции:
FilePos – функция, возвращающая номер текущей позиции указателя в файле;
FileSize – функция, возвращающая текущий размер файла;
Seek – процедура, перемещающая указатель файла на заданную позицию;
Truncate – процедура, которая усекает размер файла до текущей позиции.
Процедуры ввода-вывода для нетипизированных файлов.
При объявлении нетипизированного файловой переменной указывается только ключевое слово file. С помощью файловых переменных без типа можно обращаться к файлам любого типа и логической структуры. В нетипизированных файлах нет жестко установленной единицы чтения/записи, в отличие от типизированных файлов. При работе с файлами без типа для ввода-вывода используются стандартные процедуры BlockRead и BlockWrite, соответственно.
Чтение компонент из файла производится процедурой: BlockRead(F,Buf,N,Result),
где F – имя файловой переменной;
Buf – переменная любого типа, являющаяся буфером для размещения вводимой информации;
N – число компонент, которое нужно прочитать;
Result – переменная, в которую помещается фактическое число прочитанных компонент.
Запись компонент в файл производится процедурой: BlockWrite(F,Buf,N,Result),
где F – имя файловой переменной;
Buf – переменная любого типа, являющаяся буфером для размещения выводимой информации;
N – число компонент, которое нужно записать;
Result – переменная, в которую помещается фактическое число записанных компонент.
|