Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
пособие1.doc
Скачиваний:
2
Добавлен:
14.08.2019
Размер:
1.32 Mб
Скачать

Глава 6 статические структуры данных

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

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

6.1. Регулярный тип (Массив)

В математике, экономике, информатике, а также в других областях знаний часть приходится сталкиваться ситуацией, когда необходимо обработать большое количество переменных одного и того же типа. Например, подсчитать среднее количество осадков, выпавших в Крыму за последние 20 лет, если известно ежегодное количество осадков. В принципе мы можем обойтись понятием обычной переменной и объявить количество осадков за каждый год как VAR G1,G2,G3…..G20 : REAL; и посчитать среднее значение, но остается ощущение неудобства, особенно, если задача сопрежена с огромным количеством переменных. Для таких случаев Паскаль предоставляет введение большого числа переменных одного и того типа, используя понятие «массив» (ARRAY англ.).

6.1.1. Описание типа Массив

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

Так совокупность действительных чисел 1.6, 14.9, -5.0, 8.5, 0.46, 2.37, 0.53 можно считать массивом и обозначить именем, например А. Число элементов фиксируется и не может изменяться в процессе выполнения программы. В нашем примере количество элементов 7. Доступ к каждому элементу массива осуществляется путем индексирования элементов массива. Индекс – это величина, характеризующая положение объекта в массиве. Каждый элемент массива обозначается именем и индексом.

В математике, как правило, индекс либо заключается в скобки, либо указывается несколько ниже имени, например: А(1), А(2),…А(5) или в общем виде A{I}, где I=1,2…5.

В языке Паскаль индекс заключается в квадратные скобки. В нашем примере элементами массива являются: А[1] = 1.6, A[2] = 14.9, A[3] =-5.0, A[4]=8.5, A[5]=0.46.

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

В разделе типов

TYPE <имя типа>=array[тип индекса] of <тип компонента> ;

TYPE M : array[1..5] of real;

VAR A : M;

В разделе переменных

VAR A : array[тип индекса] of <тип компонента> ;

VAR A : array[1..5] of real;

Здесь А – имя массива, элементы которого имеют базовый тип REAL, Тип индекса ограниченный от 1 до 5.

Итак, VAR <имя массива> : array[t1] of [t2];

t1 – тип индекса, в качестве которого может быть любой простой тип, кроме REAL , INTEGER;

t2 – любой тип допустимый в Паскале.

Примеры :

1. TYPE Color = (red, blue, black);

mas1 = array[-5..15] of real;

mas2 = array[1..10,1..10] of integer;

mas3 = array[‘A’..’C’] of array[1..5] of boolean;

mas4 = array[boolean] of char;

VAR A:mas3; B:mas2; C:mas4; D:mas1; E:array[color] of real;

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

Следует отметить, что поскольку тип индекса не может быть стандартным целым или действительным типом, то нельзя делать следующее описание массива (часто встречающаяся ошибка)

VAR A: array[5] of real; или

VAR A: array[integer] of real;

Если несколько массивов имеют одинаковый тип индексов и одинаковый базовый тип, то допускается объединить массивы в список, например:

VAR A,B,C : array[1..50] of real;

Здесь объявлено списком три массива А,В,С действительных чисел каждый из которых содержит по 50 элементов ( от 1 до 50):

A[1], A[2],…,A[50], B[1], B[2],…,B[50], C[1], C[2],…,C[50].

Нельзя путать понятие «индекс» и «тип индекса». Тип индекса используется только в разделе описаний массива, а индекс указывается в разделе операторов для обозначения конкретных элементов массива. При этом индекс должен быть того же типа, что и описание типа индекса. Пример. B[5]:=B[3]+1; C[1]=3.4; Индекс может быть выражением, частным случаем которого является константа или переменная. Элемент массива иначе называется переменной с индексом. N[I+J]; MAS[2*I]; Некоторое неудобство состоит в том, что приходится сразу же жестко фиксировать число элементов массива.

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

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

Например.

TYPE Vector = array[1..4] of integer;

Massiv = array[1..4] of vector;

VAR Matr : Massiv;

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

VAR Matr : array[1..4,1..4] of integer;

Если в такой форме записи массива задан один индекс, массив назначается одномерным, если два индекса – двумерным, если N индексов, N – мерным.

Одномерные массивы обычно используются для представления векторов, а двумерные – для представления матриц. Элементы массива располагаются в памяти последовательно. Элементы с меньшими адресами – в более низких адресах памяти. Многомерные располагаются таким образом, что самый правый индекс возрастает самым первым.

Например, если имеется массив A:array[1..5,1..5] of integer;, то в памяти элементы будут размещены по возрастанию адресов. A[1,1]; A[1,2]; … A[1..5]; … A[2,1]; A[2,2]; … A[5,5]; т.о. матрицы размещаются по строкам.

Задав конкретные значения индексов можно выбрать определенную компоненту массива.Например. N:=A[1,2] занимает в N значение, стоящее в 1-й строке, 2-м столбце. Вместо записи A[1,2]; можно использовать эквивалентную запись A[1][2].

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

CONST N = 24;

TYPE Dauweek=(sun,mon,tue,wed,thn,fri,sat);

Workdau = mon..fr;

MAN = array[1..N,workdau] of integer;

VAR A:array[boolean] of array[1..N] of char;

B : MAN;

C : array[1..315] of man;

6.1.2. Действия над элементами массивов

Для работы с массивом как единым целым используется идентификатор массива без указания индекса в квадратных скобках, (так называемая полная переменная). Массив может участвовать только в операциях отношения «равно», «неравно» и в операторе присваивания. Массивы, участвующие в этих действиях, должны быть идентичны по структуре, т.е. иметь одинаковые типы индексов и одинаковые типы компонентов.

Например, если массивы А и В описаны, как VAR A,B : array[1..20] of real; то применение к ним допустимых операций даст следующий результат.

А = В TRUE, если значение каждого элемента массива А равно соответствующему значению элемента массива В.

A <> B TRUE, если хотя бы одно значение элемента массива А не равно значению соответствующего элемента массива В.

А: = В; Все значения элементов массива В присваиваются соответствующим элементам массива А. Значения элементов массива В остаются неизменны.

Для этих операций тип, имеющий ту же спецификацию, но другое имя, не подходит.

Пример:

TYPE AT=array[1..3] of real;

VAR A,B : AT; C:array[1..3] of real;

…………………………………………

A := B; - возможно,

A := C; - невозможно.

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

Например.

VAR V : real;

Y : array[1..1] of real;

………………………………..

X:=Y; Y:=X; X:=Y+0.5; Y=3.14 – недопустимо.

После объявления массива, каждый его элемент можно обработать, указав имя массива и индекс элемента в квадратных скобках. Например, запись MAS[2], VEG[10] позволяет обратиться ко второму элементу массива MAS и к десятому элементу массива VEG.

При работе с двумерными массивами указывается два индекса, с N-мерными, N индексов. Например, запись MATR[2,3] делает доступным для обработки значение элемента находящегося во 2-й строке 3 столбца массива MATR.

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

B[10]: = B[3] + 1;

Sum: = Sum – C[K];

P1: = A[2*I + 1];

Рассмотрим типичные ситуации, возникающие при работе с данными типа ARRAY. Для этого опишем три массива и четыре вспомогательные переменные.

Пример:

VAR A,D: array[1..4] of real;

B : array[1..10,1..15] of integer;

I,J : integer; K : integer; S : real;

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

A[1]:=0; A[2]:=0; A[3]:=0; A[4]:=0;

Однако, при большом количестве элементов такой способ нерационален. Гораздо удобнее получить тот же результат, используя оператор FOR.

FOR I:=1 TO 4 DO A[I]:=0;

Для инициализации двумерного массива, обычно используют вложенный оператор FOR:

FOR I := 1 TO 10 DO

FOR I:=1 TO 15 DO B[I,J]:=0;

Паскаль не имеет средств ввода – вывода элементов массива сразу, поэтому ввод – вывод производится поэлементно.

Значения элементам массива можно присвоить с помощью оператора присвивани, однако чаще всего они вводятся с экрана с помощью оператора READ (READLN).

FOR I:=1 TO 4 DO READLN(A[I]); для двумерного

FOR I:=1 TO 10 DO

FOR J:=1 TO 15 DO READLN(B[I,J]);

Можно ввести и значения отдельных элементов, а не всего массива. Например. Read(A[3]); Read(B[6,9]);

Вывод значения элементов массива выполняется аналогичным образом с помощью оператора WRITE или WRITELN

FOR I:=1 TO 4 DO WRITELN(A[I]); или

FOR I:=1 TO 10 DO

FOR J:=1 TO 15 DO WRITELN(B[I,J]);

Копированием массивов называется присваивание всех элементов одного массива всем соответствующим элементам другого массива. Копирование можно выполнить одним оператором присваивания. A:=D; или с помощью оператора FOR:

FOR I:=1 TO 4 DO A[I]:=D[I];

Оба массива должны быть идентичны по структуре.

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

K := 0; FOR I:=1 TO 4 DO

If A[I]=0 then K := K + 1;

После выполнения цикла переменная К будет содержать количество элементов массива А равно 0.

Перестановка значений элементов массива осуществляется с помощью дополнительной переменной того же типа, что и базовый тип массива. Например, требуется поменять значение первого и пятого элементов массива А. S:=A[5]; A[5]:=A[1]; A[1]:=S;

Нахождение суммы элементов массива :

S := 0; FOR I:=1 TO 4 DO begin

Read(A[I]); S:=S + A[I]; end.;

Упакованные массивы. Если перед названием типа стоит ключевое слово PACKED, то при трансляции генерируется программа, плотно упаковывающая данные в ячейки памяти. Дело в том, что единица хранения в компьютере – это слово. В то же время для изображения символа достаточно иметь один байт памяти. С целью экономии памяти машины и введено понятие упакованного массива. Цена за (упаковку) сэкономленную память – понижение скорости отражения в памяти во время выполнения (так как для работы с элементами массива требуется распаковка). Например:

VAR AP:packed array[1..3] of boolean;

ANP : array[1..3] of boolean;

идентичны в списке объема и характера хранимой информации, но различными способами представления в памяти.

К упакованным символьным массивам относятся строки символов, которые задаются либо в разделе операторов, либо в разделе констант. Упакованный массив символьных данных имеет следующее описание

VAR < имя массива> : packed array [тип индекса] of char;

Пусть, например, имеется строка «Савельева Лена». Эту строку символов можно считать массивом из 14 символов, включая пробел. Обозначим имя массива через FAM. Описание массива будет выглядеть следующим образом:

VAR FAM : packed array[1..14] of char;

Один элемент массива принимает значение одного символа, например,

FAM [1] = ‘C’, FAM[2] = ‘A’…

К упакованному массиву Z можно применить стандартные процедуры PACK and UNPACK

Pack (B,I,Z) означает “упаковку” элементов массива В, начиная с I элемента в массив Z. UNPACKED (Z,B,I) означает «распаковку» массива Z в массив В, начиная с I элемента массива В.

VAR prolix:array[1..1000] of char;

Pitn : packed array[1..1000] of char;

Pack (prolix,1,pitn); unpack(pitn,prolix,1);

Строковая константа состоит из букв, заключенных в апострофы. Если в строку нужно включить апостроф, то он должен быть записан в виде пары апострофов: WRITE(' под"езд');

К строкам и упакованным символьным векторам применимы операции отношения, но при этом аргументы обязательно содержат одинаковое количество символов. Строковые константы можно присвоить строковым переменным, но присваивание допустимо, если количество литер константы совпадает с размером упакованного массива. Во многих современных компиляторах не требуется совпадения длин.

VAR yon:packed array[]1..10 of char;

Begin yon:= ‘IT’’S cold’;

6.1.3. Составление программ с массивами

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

Действия над матрицами.

1. Сумма (разность) матриц.

a11+b11 a12+b12 ... a1n+b1n

C[m..n]= A[m..n]+B[m..n]= a21+b21 a22+b22 ... a2n+b2n

............................

am1+bm1 am2+bm2 ... amn+bmn

2. Произведение матриц. Под произведением матрицы A[m..p] на матрицу B[p..n] 0понимают матрицу С[m..n], элементы которой вычисляются по формуле

p

c[i,j] = a[i,k] * b[k,j]

k=1

Иначе говоря, элемент C[i,j] равен сумме попарных произведений элементов i-й строки матрицы А на соответствующие элементы j-го столбца матрицы В.

3. Транспонирование матриц (m*n). Транспонированной по отношению к матрице А называется матрица А1, в которой строки матрицы А становятся соответствующими столбцами матрицы А1.

При программировании действий с матрицами, матрицы отображаются на паскалевский двумерный массив. Оформим программу в виде основной программы и трех процедур Summa, Proizv, Transp соответственно для вычисления суммы матриц А и В, произведения матриц А1 и В1 и транспонирования матрицы А.

Пример:

Program Ex8;

Const m=2; n=3;

m1=2; n1=2; p=3;

Type abc = array[1..m,1..n] of real;

a1t = array[1..m1,1..p] of real;

b1t = array[1..p,1..n1] of real;

at = array[1..n,1..n] of real;

Var a,b,c:abc; a1:a1t; b1:b1t; i,j :integer; aa,aa1:at;

Procedure Summa(a,b:abc; var c:abc);

begin

For i:=1 to m do For j:=1 to n do c[i,j]:=a[i,j]+b[i,j]

end;

Procedure Proizv(a:a1t; b:b1t; var c:abc);

Var k:integer; s:real;

Begin

For i:=1 to m do For j:=1 to n do

begin s:=0;

For k:=1 to p do s:=s+a[i,k]*b[k,j];

c[i,j]:=s end;

end;

Procedure Transp(aa:at; var aa1:at);

begin

For i:=1 to n do For j:=1 to n do

aa1[i,j]:=aa[j,i]

end;

Begin

Writeln('Задайте матpицу А');

For i:=1 to m do

For j:=1 to n do read(a[i,j]);

Writeln('Задайте матpицу B');

For i:=1 to m do

For j:=1 to n do read(b[i,j]);

Summa(a,b,c);

Writeln('Сумма матpиц');

For i:=1 to m do begin

For j:=1 to n do

write(c[i,j],' ');

writeln

end;

Writeln('Задайте матpицу А1');

For i:=1 to m1 do

For j:=1 to p do read(a1[i,j]);

Writeln('Задайте матpицу B1');

For i:=1 to p do

For j:=1 to n1 do

read(b1[i,j]);

proizv(a1,b1,c);

Writeln('Пpоизведение матpиц');

For i:=1 to m1 do begin

For j:=1 to n1 do

write(c[i,j],' ');

writeln

end;

Writeln('Задайте матpицу для тpанспониpования');

For i:=1 to n do

For j:=1 to n do

read(aa[i,j]);

Transp(aa,aa1);

Writeln('Тpанспониpованная матpица');

For i:=1 to n do begin

For j:=1 to n do

write(aa1[i,j],' ');

writeln

end;

end.

6.2. Строковый тип

Строка – это последовательность символов, количество которых колеблется от 0 до 255. Используется для обработки текстовой информации. Строка сравнима с одномерным массивом символов, но имеет существенное отличие. Массив символов имеет фиксированную длину (количество элементов), которое определяется при описании.

Строка имеет две разновидности длины:

  • Общую длину строки, которая характеризует размер памяти, выделяемый строке при описании;

  • Текущую длину строки (всегда меньшую или равную общей длине) которая показывает количество смысловых символов строки в каждый конкретный момент времени и указывается в нулевом элементе строки;

Формат:

Const <идентификатор> = ‘<Текст>’;

Var <список идентификаторов> : string[n];

Type <имя типа> = string[n];

где n – количество символов в строке (если не указываются, то 255 символов длина строки по умолчанию).

Пример:

Const C1=’Pascal’;

Var C2,C3,C4: string[20];

Type C=string[50];

Var a,b : C;

Задать значения строке можно двумя способами

  1. Оператором ввода – причем для строк применяется только Readln()

  2. Присвоением последовательности символов строковым переменным.

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

Пример:

Readln(C2);

C3:=’Borland’+C1;

Произвольные пары строк могут сравниваться с помощью операторов отношений. Операторы отношений это =, <>, <, >, <=, >=.

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

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

Расширение совокупности строковых операций являются процедуры и функции работы со строками.

Функции и процедуры для работы со строками:

Copy(s1, pos, kol):string – функция копирует из строки S1 количество kol символов, начиная с символа с номером pos.

Concat(s1,s2,..,sn):string – функция возвращает строку, представ-ляющую собой сцепление строк-параметров s1, s2, ... ,sn.

Insert(s1, s2, pos) – процедура вставляет подстроку s1 в строку s2 начиная с позиции pos.

Delete(s, pos, kol) – процедура удаляет количество символов kol из строки s, начиная с позиции pos.

Length(s):word - функция возвращает текущую длину строки s.

Val(s, arg, cod) – процедура преобразует строку символов s, в целое или вещественное значение arg , определяемое типом переменной, при этом позицию непреобразованного символа возвращает переменная cod.

Pos(s, text):word – функция отыскивает в строке text первое вхождение подстроки s и возвращает номер позиции, с которой она начинается.

Str(i,s) – процедура преобразует число i с заданным форматом в строку s.

6.3. Множественный тип

В математике множеством называют такую совокупность каких-либо объектов, называемых элементами, в которой никакие два элемента не совпадают (то есть среди них нет повторяющихся), и их порядок не имеет значения. Математическое множество может содержать любое число элементов, какой угодно природы. Для каждого множества должно существовать некое универсальное множество, в котором содержатся все элементы, представимые данным множеством. Например, про множество чисел от 1 до 10 можно было бы сказать, что оно выбрано из универсального множества "все числа от 1 до 100". Одним из способов математического обозначения множеств служит список элементов, заключенный в фигурные скобки {1,3,6}.

Множество в Паскале - это структура данных, сохраняющая некоторые (не все!) черты математических множеств. Как и в математике, повторяющиеся элементы во множествах Паскаля игнорируются.

Не имеет значения и порядок их следования. Универсальному множеству в Паскале соответствует понятие базового типа, для которого установлены определенные ограничения. Базовым может быть только простой порядковый тип, например, integer, char, (включая перечисление) или отрезок такого типа. Следует особо отметить, что элементами множеств Паскаля не могут быть ни вещественные числа (поскольку real не относится к классу порядковых типов), ни строки (потому что это не простой тип, а тем более не порядковый).

Размер множеств Паскаля всегда ограничен предельно допустимым количеством элементов, тогда как для математических множеств таких ограничений нет. Порядковое значение (даваемое функцией ord) каждого элемента базового типа должно лежать в диапазоне от 0 до 255. Список элементов, входящих в множество, записывают заключенным не в фигурные, а в квадратные скобки, например, [1,3,6]. Одно и то же множество можно записать не единственным способом, поскольку порядок элементов в множестве не имеет значения. Записав [4,2,6] или [6,2,4], мы фактически будем иметь дело с одним и тем же множеством. Более того, многократное повторение какого-либо элемента никак не влияет на "состав" множества, на основании чего мы могли бы даже записать [2,2,4,6], и речь шла все о том же множестве из трех чисел 2,4,6. Множество, не содержащее ни одного элемента, называется пустым или нульмножеством и обозначается просто парой скобок [] или [ ].

Объявление и построение множества.

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

Формат: Const <идентификатор> = [<эл-т1>, <эл-т2>,…,<эл-тN>];

Type <идентификатор> = SET OF <базовый тип>;

Var <список идентификаторов> : SET OF <базовый тип>;

Описывая какое-то множество, иногда бывает удобно сразу показать, какие элементы оно может содержать. Сделать это также можно двояко: как в определении типа, так и при объявлении переменной. Список элементов может быть задан либо упоминанием всех до одного возможных значений (как в определении типа перечисления), либо указанием пары граничных значений (т.е. в виде отрезка значений какого-либо порядкового ипа). На практике именно перечисления особенно часто используются в качестве базовых типов множеств. Проиллюстрируем сказанное несколькими примерами.

Type

Weekdays = (Mon, Tue, Wed, Thu, Fri);

Digits = set of 0..9;

Letters = set of 'a'..'z';

Var

Days:set of Weekdays;

Symbols: digits;

Initial: letters;

Colors: set of (black, white, gray);

Number1:0..9;

Number2:0..9;

По отношению к множеству Days множество Weekdays выступает в роли универсального множества. Digits - множество целочисленных объектов со значениями из диапазона 0..9. Объявление множества Colors непосредственно сообщает, какие именно элементы могут быть в нем представлены.

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

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

Например:

Colors:=[white,gray];

Initial:=['k'..'p'];

Symbols:=[9,4..6];

Days:=[Tue..Thu];

Days:=[Fri..Tue];

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

Что можно сказать по поводу таких предложений?

Days:=[9];

Colors:=[Mon];

Это ошибки, потому что в обоих случаях множества, состоящие слева и справа от символа :=, имеют совершенно разные базовые группы.

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

Number1:=5;

Number2:=9;

Symbols:=[Number1, 7, Number2];

В правой части последнего выражения получаем [5,7,9], что и определяет результирующее значение множества Symbols.

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

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

Объединение.двух множеств А и В, записываемое как А+В, есть новое множество, состоящее из элементов, принадлежащих множеству А или В, или тому и другому одновременно.

Пример:

Type Ch = set of char;

Var Ch1, Ch2, Ch3:Ch;

...

Ch1:=['a','x','e'];

Ch2:=['o','x'];

Ch3:=Ch1+Ch2;

В результате объединения Ch3 будет содержать 4 элемента ['a','x','e','o'].

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

Ch3:=Ch1*Ch2;

Ch2:=Ch1*['n','o'];

В результате пересечения Ch3 будет содержать только один элемент [x]. В следующем предложении утверждается, что множество Ch2 должно быть образовано из элементов 'n' и 'o' при условии, что они есть во множестве Ch1. Если же ни того, ни другого там нет, множество Ch2 будет пустым.

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

Пример:

Сh1:=['a','e','t'];

Ch2:=Ch1-['e']; {'a','t'}

Ch3:=['s','e','t']-Ch1; {'s'}

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

Необходимо отметить, что символы +, *, -, используемые для обозначения основных множественных операций, имеют совсем иные значения, будучи употреблены с числовыми величинами, а знак +, кроме того, выступает еще и как оператор конкатенации строк. Программист должен очень внимательно следить за тем, с какими смысловыми значениями появляются указанные знаки в том или ином контексте. В частности, заведомо ошибочной будет всякая попытка соединить одним из перечисленных операторов множество и число. Однако, ничто не мешает какой-то целочисленной переменной, скажем х, фигурировать в качестве элемента множества, например, так [x].

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

Ch1:=Ch1+['k'];

Ch2:=Ch2-['m'];

Если 'k' уже был в Ch1 или 'm' не было в Ch2, то ничего не изменится.

Сравнение множеств в Паскале осуществляется при помощи различных операторов отношений.

Два множества А и В равны, если каждый элемент из А является также элементом В и наоборот. (А=В)

Множество А есть подмножество множества В, если каждый элемент А присутствует и в В. (А<=В)

Кроме того, имеется возможность выяснить, принадлежит ли данный элемент некоторому множеству. Для этой цели предусмотрен специальный оператор in. (x in A)

Результат выполнения операций сравнения, подмножества и принадлежности имеет булевский тип (True или False).

Таблица 6.1. Старшинство множественных операторов

Приоритетный

уровень

Операторы

Операции

1(высший)

*

Пересечение

2

+ -

Объединение, разность

3(низший)

= <> >= <= in

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

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

6.4. Комбинированный тип (Запись)

Пусть необходимо разработать программу, которую нам предстоит разработать, должна ввести исходные данные, содержащие сведения о студентах класса (например, фамилию, имя, пол (М или Ж), возраст, образование. Уровень образования задается целочисленным кодом: 0 - средняя школа, 1 - ПТУ, 2 - техникум, 3 - ВУЗ, 4 – лицей, 5 - гимназия), а затем по запросам выдавать различные справки по поводу тех или иных студентов. Выражаясь профессионально, суть программы можно определить иначе: она должна создавать базу данных класса и обеспечивать пользователя сведениями относительно ее содержимого. База данных - это некоторая совокупность взаимосвязанных данных, определенным образом организованных для обеспечения легкого доступа к ним. Программируя подобные задачи на Паскале, обычно применяют такие организационные формы, как записи, ряды, состоящие из записей, и другие более сложные структуры и механизмы, в основе которых лежит идея записи.

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

6.4.1. Формат описания. Фиксированные записи

Описать в программе запись можно двумя способами: построив определение соответствующего типа или задав такой тип непосредственно в объявлении некоторой переменной. Допустим, мы хотим определить тип данных record с именем adres. Наша запись должна иметь два элемента - номер дома (типа integer) и название улицы (типа string); их описания, обрамленные синтаксическими ограничителями record и end, и составят определение типа записи.

Пример:

Type adres = record

number:integer;

name: string [20];

end;

Здесь имя adres выступает как обозначение построенного нами типа данных, включающего две компоненты: number и name. Отдельные элементы в типе record описываются как переменные.

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

Var home:adres;

family: array[1..4] of adres;

Запись home можно было объявить и напрямую, не заботясь о предварительном определении типа:

Var home: record

number:integer;

name: string [20];

end;

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

Структура вложенной записи

Teacher

Soname Birthday Adress first last

'Mary' 'Smith' '26.06.68' street city state tel

numb name 'Sevastopol' 'Ukr' '442211'

37 'Big Sea'

Построить такое описание можно различными способами.

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

Пример:

Type

{ Имя и фамилия }

NameRec = record

first: string [10];

last : string [10];

end;

{ Номер дома и улица }

StrRec = record

numb:integer;

name: string [20];

{ Полный адрес }

AdrRec = record

street : StrRec;

city : string [15];

state : string [3];

tel : string [6]

end;

{ Анкетные данные преподавателя }

TeacherRec = record

Soname : NameRec;

Birthday : string [8];

Adres : AdrRec;

end;

Var Teacher:TeacherRec;

Для описания сразу всех преподавателей кафедры (в предположении, что их будет не больше 20) воспользуемся объявлением массива записей:

Var Teacher: array [1..20] of TeacherRec;

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

Var Teacher:

record

Soname : record

first: string [10];

last : string [10];

end;

Birthday : string [8];

Adres : record

Street: record

numb:integer;

name: string [20];

city : string [15];

state : string [3];

tel : string [6]

end;

end;

Следует признать, что предыдущий вариант описания записи обеспечивает более отчетливое ее понимание.

6.4.2. Поля записи. Предложение with

Еще одна особенность, присущая записям, состоит в том, что далеко не все составляющие структуры должны быть "носителями" конкретной информации. Так, в нашей записи Teacher на уровнях first и last содержатся вполне определенные данные, тогда как на уровне Name их нет. Имя Name играет здесь особую роль: оно указывает на те места записи, где находятся значения first (имя преподавателя) и last (его фамилия). Записи, предназначенные для непосредственного размещения информации, называются полями. Для каждого поля должно быть указано некоторое имя и тип представляемых этим полем данных (в нашем примере: first, last, birthday, numb, name city, state, tel). Те имена, которые предполагают дальнейшую детализацию, должны быть определены как записи (в нашем примере: soname, adres, street).

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

Как получать доступ к отдельным полям записи? Допустим, что текущее значение номера телефона некоторого преподавателя нужно заменить значением 123456. Чтобы обратиться к полю номера телефона (tel), мы должны иметь возможность сообщить, что речь идет о части полного адреса (adres), который в свою очередь является частью записи teacher. На Паскале это выражается в так называемой точечной нотации, позволяющей построить список имен структурных уровней записи, разделяя их одиночными точками. Каждая точка символизирует определенный уровень вложенности.

Teacher.adres.tel:='123456';

Приведем еще один пример, в котором фамилия преподавателя передается в переменную v, после чего печатается его день рождения:

v:=teacher.soname.first;

writeln(teacher.birthday);

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

В каждом из только что показанных примеров мы тщательно выписывали всю цепочку имен, начиная с наивысшего уровня Teacher, вплоть до имени конкретного объекта, на который нам нужно сослаться. Такой способ довольно обременителен. В качестве альтернативы в Паскале предусмотрено специальное средство - оператор With (присоединение). Оператор With позволяет задать некоторый префикс, представляющий собой обозначение одного или нескольких уровней записи. Этот префикс будет затем автоматически присоединен ко всем именам - компонентам соответствующей записи, которые присутствуют в теле предложения With. Формально предложение With строится по следующей схеме:

With <префикс> do

<оператор>

Здесь слово префикс обозначает имя одного или нескольких уровней записи. За заголовком with...do следует любой оператор Паскаля или группа операторов, обрамленная символами begin и end

Предположим, что нам требуется отпечатать значения двух полей: first и last. Соответствующее предложение With будет таким:

With Teacher.Soname do

writeln(first,' ',last);

В точечной нотации это равносильно предложению

writeln (Teacher.Soname.First,' ', (Teacher.Soname.Last);

Таким образом, все то, что стоит между With и Do, рассматривается как некий префикс, который компилятор присоединяет слева ко всем компонентам записи, упоминаемым в теле предложения With.

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

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

Например,

With Teacher, Soname do

writeln (First,' ', Last);

Показанная форма эквивалента следующим:

With Teacher, Soname do With Teacher do

writeln (First,' ', Last); With Soname do

writeln (First,' ', Last);

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

With Teacher do

Begin

With Soname do

writeln (First,' ',Last);

With Adres do

writeln (city)

End;

В списковой форме синтаксически правильной и вполне работоспособной будет следующая конструкция

With Teacher, Soname, Adres do writeln (First,' ',Last,' ',City);

6.4.3. Операции над записями

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

Так, в случае объявления

Var Teacher: array [1..20] of TeacherRec;

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

Teacher[2]:=Teacher[1];

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

6.4.4. Составление программ с записями.

Перейдем непосредственно к программированию поставленной задачи. Определим внутреннюю структуру базы данных. Наиболее логичным представляется применение массива записей. Назовем его student. Разберем "устройство" отдельного элемента этого массива.

Будет разумно рассматривать его состояние из двух основных частей - Name (имя и фамилия) и pers (персональные характеристики). Дальнейшее дробление структуры будет таким: Name распадается на две составляющие - last (фамилия) и first (имя), а Pers - на три индивидуальные характеристики конкретного лица - sex (пол), age (возраст), educ (образование).

Program Ex9;

Type

UrEduc = 0..5;

NameRec = record

last : string [10];

first: string [10]

end;

PersRec = record

Sex:char;

Age:integer;

Educ:UrEduc;

end;

StudRec = record

Name:NameRec;

Pers:PersRec;

end;

Klass = array [1..30] of StudRec;

Numb = 1..30;

Var

Student:Klass; n:numb; j:integer;

Procedure ReadData (Var Student:Klass; Var n :Numb);

{Данные об n студентах класса считываются из файла StudFile в pяд записей Student}

Var i:Numb;

StudFile:text;

Begin

Assign(StudFile,'a:\prog\StudFile.txt');

Reset(StudFile); Readln(StudFile,n);

For i:=1 to n do

with Student[i] do

begin

with name do { фамилия и имя }

begin

read(StudFile,last); read(StudFile, first)

end;

with pers do { пеpсональные сведения}

readln(StudFile,sex,age,educ);

end;{Student[i]}

Close(StudFile);

end;

Procedure FindAge(Student:klass; n: numb; j: integer);

{Эта пpоцедуpа пpосматpивает pяд Student и находит в нем всех, чей возpаст больше или pавен j}

Var i:numb; none:boolean;

Begin

none:=true;

Write('Студентынты, возpаст котоpых больше или pавен ');readln(j);

for i:=1 to n do

begin

with Student[i] do

if pers.age >=j then begin

with name do

writeln (last, ' ', first);

none:=false

end {then}

end; {for}

if none then write ('Таких студентов нет');

end; {FindAge}

begin

readdata (Student,n);

FindAge(Student,n,j);

end.

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

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

6.4.5. Записи с вариантами

До сих пор, говоря о записях, мы имели дело только с такими, в которых структура полей неизменна. Располагая, например, десятью переменными типа StudRec, мы можем быть уверены, что в любой из них содержатся одни и те же поля: Name и Pers, а также все поля следующего уровня вложенности: first, last, sex, age, educ. Однако для многих приложений столь простой механизм хранения разнородной информации оказывается недостаточным. Для этих случаев Паскаль предлагает еще один способ организации данных - это вариантные записи (записи с вариантами).

Основная идея вариантной записи состоит в том, чтобы находясь в рамках единой структуры, определить в ней сразу несколько различных (альтернативных) записей. В самом общем случае такая запись может состоять из двух частей - фиксированной и вариантной. Фиксированная часть - это обычная совокупность полей; ее структура остается постоянной для всех экземпляров записи данного типа. Структура вариантной части записи не постоянна: она изменяется в зависимости от значения особого поля, называемого полем тега (от англ. tag - ярлык, этикетка, бирка). Применяется также термин поле признака. В качестве примера рассмотрим запись типа StudRec, и на ее основе построим новую, многовариантную версию. Определения типов для фиксированной части оставим те же:

Type

{*Внимание! Дополнительные описания для записей с вариантами!*}

Year = (fut,pres,past);

str6 = string [6];

str9 = string [9];

{ *** }

StudRec = record

Name:NameRec;

Pers:PersRec;

{ Внимание! Здесь начинается запись с вариантами ! }

Case status: year of

fut: (datafut : array[1..10] of str6);

pres:(datapres: str6);

past:(datapas : array[1..10] of str6; a1 : real; b1 : str9)

end; {record}

Klass = array [1..30] of StudRec;

Var Student:Klass;

В каждом конкретном экземпляре записи в ее вариантной части всегда содержится один из возможных наборов полей.

Собственно вариантная часть записи начинается с заголовка внешне очень напоминающего предложение Case :

Case status: year of

Сам заголовок служит определением особого поля записи, называемого полем тега. В данном примере поле тега носит имя status, а его тип year. В зависимости от значения тега вариантная часть записи будет иметь различные поля. Если status равен fut, вариантная часть будет представлена только 10-элементным рядом datafut; при значении status, равном pres, в вариантной части будет содержаться лишь одна переменная datapas; наконец, когда status равен past, мы обнаруживаем в вариантной записи сразу три поля:

datapas, a1, b1.

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

6.5. Файловый тип

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

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

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

Создание внешних файлов данных для постоянного хранения на внешнем носителе и возможность обрабатывать эти файлы в программе являются эффективным средством программирования.

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

6.5.1. Определение типа. Классификация файлов

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

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

Пример:

Type

T = file of char;

P = packed file of char;

Var

Finp:file of real; {файл действительных данных}

M:file of integer; {файл целых данных}

Ft:T; {файл символьных данных}

Файлы различаются:

1) по типу компонент файла:

- текстовые файлы предназначены для хранения текстовой информации. Компонентами файла являются литеры или строки, имеющие переменную длину; описание текстового файла File of char эквивалентно описанию text (тип text является стандартным). Поэтому в предыдущем примере текстовый файл Ft можно объявить

Var Ft:text;

- типированные (типизированные) - это дисковые файлы, состоящие из нумерованной последовательности компонент некоторого конкретного типа, причем длина каждой компоненты определена и постоянна;

- нетипированные (нетипизированные) файлы - при описании не указывается тип компонент, в этом случае в объявлении слово of и тип компоненты отсутствует

Type a = file;

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

2) по методу доступа к его компонентам:

- файлы с последовательным доступом - каждый элемент становится доступным только после перебора всех предыдущих элементов;

- файлы с произвольным (прямым) доступом - возможно обращение к компоненту по его порядковому номеру в файле;

3) по времени своего существования:

- внутренние файлы (рабочие) существуют только во время исполнения программы; они носят вспомогательный характер;

- внешние файлы - существуют и вне программы. Они могут быть подготовлены автономно и сохраняются после работы программы;

4) по авторству создателя:

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

- файлы пользователя.

6.5.2. Действия с файлами

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

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

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

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

Например:

Write ('Киев'); {выводит слово 'Киев' на экран}

Write (File1, 'Киев'); {заносит слово 'Киев' в конец файла с именем File1}

Кроме того, необходимо сообщить компилятору о местонахождении внешнего файла, что выражается в имени внешнего файла, под которым он зарегистрирован вне программы. (Например, f:\klass\k111\prog7.dat)

Для установления связи между файловой переменной и "внешним" именем файла в Паскале применяется предложение assign. После его выполнения файл необходимо открыть посредством предложения reset (для ввода информации) или rewrite (для вывода). Обращение собственно к содержимому файла осуществляется предложениями read или readln (считывание данных) или write или writeln (запись в файл); первым параметром указанных процедур ввода-вывода должно быть имя файловой переменной. Для прекращения дальнейших действий с файлом его следует закрыть предложением close.

Пример:

Program Ex10;

Var File1:text;

Begin

Assign (File1,'a:\file1.txt');{назначает файлу имя}

Rewrite(File1);{создает пустой файл и открывает его по записи}

Writeln(File1,'Очень полезно изучать');

Writeln(File1,'Паскаль');

Writeln(File1,'в ИСР Borland Pascal 7.0');

Close(File1);

End.

Пример:

Program Ex11;

Var File1:text; St:string;

Begin

Assign (File1,'a:\file1.txt');

Append(File1);{Добавляет текст к концу файла}

Writeln(File1,'А теперь закончим');

Reset (File1); {Открытие файла по чтению}

While not EOF(File1) do

begin

Readln(File1,st);{чтение из файла}

Writeln(St); {и вывод на экpан}

end;

Close(File1);

End.

Если требуется осуществить произвольный доступ к большой группе данных, то типизированные файлы значительно эффективнее текстовых, так как длина каждой компоненты постоянна и легко вычислить позицию каждой компоненты в файле и напрямую считать или записать этот элемент. Компоненты типизированного файла нумеруются по порядку, начиная с нуля, то есть первая компонента имеет номер 0, вторая - 1, третья - 3 и т.д.

Пример:

Program Ex12;

{Создает файл, содержащий квадраты 10 чисел типа Real}

Var File1:file of real;

R:real; N:integer;

Begin

Assign (File1,'a:\fi2.dat');

Rewrite (File1); {Создает новый пустой файл и готовит его к записи}

For N:=1 to 10 do

begin

R:=sqr(N);

Write (File1,R);

{Записывает числа в файл в двоичном внутреннем формате}

end;

Close(File1);

end.

Пример:

Program Ex13;

{Считывает с экpана числа в диапазоне от 1 до 10 и выдает их квадpаты, записанные в файле, созданном предыдущей программой}

Var

File1:file of real;

R:real; N:integer;

Begin

Assign (File1,'a:\fi2.dat');

Reset (File1);

Write ('Введите число (1-10):');

Readln(N);

Seek (File1,N-1);

{текущая позиция файла передвигается в заданную позицию}

Read(File1,R);

Writeln('Квадpат ',n,' pавен ',r:4:1);

End.

6.5.3. Процедуры и функции для работы с файлами

Итак, мы использовали несколько процедур и функций. Уточним их определение.

Assign(имя файла, внешнее имя) - процедура назначает имя внешнего файла файловой переменной. С момента выполнения этой процедуры все действия над файловой переменной будут эквивалентны действиям над внешним файлом.

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

Writeln (имя файла, список параметров для записи) - запись в файл.

Append (имя файла) - процедура открывает существующий текстовый файл для присоединения.

Close (имя файла) - закрывает открытый файл. Если файл был открыт, никогда не следует выходить из программы, предварительно не закрыв его.

Reset (имя файла) - процедура открывает существующий файл для чтения. Если эта процедура применена к несуществующему файлу, возникает ошибка ввода-вывода.

Readln (имя файла, список параметров для чтения) - чтение из файла;

Eof (имя файла) - функция проверяет метку "конец файла". Значение функции равно true, если указатель находится сразу за последней компонентой файла и false в любом другом случае.

Seek(имя файла, номер компоненты) - устанавливает указатель на компоненту с указанным порядковым номером. Наличие этой процедуры придает работе с файлами "привкус работы с одномерным массивом".

Существует и ряд других процедур и функций для работы с файлами:

Flush (имя файла) - очистить буфер файла. К закрытому файлу не применяется.

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

Rename (имя файла, новое имя файла) - переименовать файл.

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

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

6.5.4. Стандартные файлы

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

Допустимо использование следующих логических устройств:

con: - пульт управления (для ввода - клавиатура, для вывода - дисплей). Вводимая информация отображается на экране и может редактироваться.

trm: - терминал (для ввода - клавиатура, для вывода - экран).

Вводимая информация отображается на экране, но редактироваться не может.

kbd: - клавиатура. Используется для ввода с клавиатуры. Вводимая информация на экране не отображается.

lst: - принтер. Используется только для вывода.

Для организации работы с логическими устройствами используются стандартные файлы. Система сама открывает и закрывает эти файлы, поэтому к ним не применяются процедуры Assign, Reset, Rewrite, Close.

Имена логических устройств и соответствующих им стандартных файлов, за исключением имен файлов ввода (input) и вывода (output), совпадают.

Например, чтобы направить выходные данные программы прямо на экран, достаточно в качестве имени внешнего файла указать 'con:'. Хотя программировать ввод-вывод с использованием стандартных файлов проще, употребление файловых переменных позволяет делать программу более гибкой.

Вопросы для самоконтроля:

  1. Что такое «массив»?

  2. Что такое индекс?

  3. Где и как может быть объявлен массив?

  4. Как ввести матрицу?

  5. Как осуществить перестановку?

  6. Что такое строка в в Паскале?

  7. Чем отличается строка от массива?

  8. Какие строки называются равными?

  9. Что называется множеством в Паскале?

  10. Какие операции допустимы в Паскале?

  11. Назовите порядок операций со множествами по старшинству?

  12. Как объявляются объекты типа «запись»?

  13. Для каких целей используется оператор присоединения?

  14. Что такое поле записи?

  15. Какие операции допустимы с записями?

  16. В чем состоит идея вариантной записи?

  17. Дать определение файла.

  18. Какие вы знаете типы файлов?

  19. Как объявляется переменная файлового типа?

  20. Какие вы знаете процедуры работы с файлами?

  21. Как организовать проверку конца файла?