Для оформления подпрограммы в виде модуля нужно в меню среды Турбо Паскаль в пункте Compile/Destinationустановить значение Diskи оттранслировать ее (Ctrl + F9). На диске получим файл с тем же именем, но с расширением .tpu. Модуль создан.
Пример. Вычислим tg(x) и 1.35, используя модуль Mymodul.
programUseModul;
usesMymodul;
var x, y, a, b, с : real;
Begin
a := 1.3;
b :=5;
writeln('Введите х:');
readln(x);
У := tg(x);
writeln('tg(', x:5:2,') = ', y:6:2);
с := step(a, b);
writeln(' 1.3^5 = ', c:5:2);
readln
End.
Задание 6. Модифицируйте модуль и программу так, чтобы можно было вычислить значение функции ctg(3x) - 4tg(x).
Отдельные модули пользователь может объединять в личную библиотеку (например, Mybibl.tpl) с помощью команды
tpuMover <полный путь к файлу>\Mybibl.tpl /+ Mymodul
Замечание. Файл Mybibl.tpl необходимо разместить в каталоге, где нет файла с системной библиотекой turbo.tpl.
Задание 7.Решите задачу № 17 своего варианта.
ЗАПИСИ
1. Запись (record) - это структура (тип данных), предназначенная для хранения в оперативной памяти компьютера сложных данных, состоящих из отдельных компонент различных типов, которые называются полями. Запись описывают в разделе type или в разделе var с помощью такой конструкции:
<имя записи>=rесоrd
<имя поля 1> : <тип поля 1>;
…
<имя поля n> : <тип поля п>;
end;
Пример. Информацию об анкетных данных студентов можно представить с помощью таких полей: фамилия, имя, дата рождения и средний балл. Созданную структуру опишем как тип записи gruppa.
type gruppa = record{Описываем тип записи gruppa}
name, surname : string[20]; {Описываем соответствующие поля}
birthday : record
year : 1975..1985;
month : 1..12;
day : 1..31;
end;
sball : real
end;
Доступ к полю конкретной записи обеспечивает составное имя
<имя записи>.<имя поля>
Переменные-записи типа gruppa объявляют в разделе varтак: studentl, student2 : gruppa. В программе этим переменным можно присвоить, например, такие значения:
Составными именами пользоваться неудобно. Они ведут к громоздким выражениям. Для их упрощения служит команда присоединения with.
2. Команда присоединения (with).Команда присоединения даёт возможность записывать в программе только имена полей. Общий вид команды withтакой:
with<имя переменной типа запись> do<команда>;
После служебного слова withуказывают имя переменной типа запись, а в команде используют только имена полей соответствующей записи.
К переменным из предыдущего примера можно обратиться так:
withstudentl do
Begin
name := 'Тудимов';
surname := 'Андрей';
withbirthday do
Begin
year := 1980;
month := 12;
day := 28;
end;
sball := 4.9
end;
Задача 1. Используя тип массив записей, составить программу для учета и обработки данных о наличии на складе автомашин. Вывести на экран информацию о моделях и годах выпуска машин, цена которых меньше, чем 3000 у.е.
Пусть запись содержит такие поля: модель (marka), год выпуска (year) и цена машины (price).
Задание 1. Дополните описания типа полем цвет (color) и выведите на экран информацию о машинах красного цвета, выпущенных за последние семь лет.
Задание 2. Решите задачу № 18 своего варианта.
ФАЙЛЫ
1. Описание типов и объявление файлов.Практическое значение имеют задачи обработки информации, находящейся на внешних носителях (дисках). Примерами соответствующих данных могут быть сведения об успеваемости студентов, расписание движения транспорта, наличие товаров в магазинах, адресные книги. Для решения таких задач используют файлы данных.
Файл — это совокупность данных, размещенных на внешнем носителе. Данные в файле называются элементами. Количество данных в файле, в отличие от массива, в описании файла не указывают. Элемент файла не имеет индекса. Тип элементов может быть как простым, так и сложным, но не может быть файлом.
Файловый тип данных описывают в разделе описания типов так:
type<имя типа> = file of<базовый тип>;
или непосредственно в разделе объявления переменных
var<список переменных> : file of<базовый тип>;
Пример.
typemyfile = file ofinteger;
list = file ofstring[20];
varfilel, file2: myfile;
druzia: list;
komanda: file ofboolean;
2. Действия с файлами.Чтобы найти нужный элемент файла, необходимо последовательно просмотреть все предыдущие элементы. Это называется последовательным доступом к файлу.
Для обработки файла его необходимо открыть, выполнить нужные действия и закрыть.
Для определения конца файла существует стандартная логическая функция
eof (<имя файла>);
Значение этой функции будет true,если достигнут конец файла.
Файл можно открывать только для чтения или для записи в него информации.
Для работы с файлами существуют такие команды (процедуры модуля System):
assign(<имяфайла>, <внешнее имя>) - обеспечивает связь между файловой переменной и файлом на внешнем носителе;
reset(<имя файла>) — открывает файл для чтения из него данных;
rеаd<1(<имя файла>, <имя переменной>) - читает (вводит) данные из файла в оперативную память;
close(<имя файла>) - закрывает файл;
rewrite(<имяфайла>) — открывает файл для записи в него данных;
write(<имя файла>, <имя переменной>) - записывает (выводит) данные в файл.
Здесь <имя файла> — имя, заданное в разделе объявления переменных, <внешнее имя> - имя файла данных на внешнем носителе, взятое в кавычки, например, 'd:\gruppal\labl.pas'.
Задача 1. Создать файл записей с информацией о компьютерах: марка (marka), объём винчестера (hdd), объём оперативной памяти (ram) и быстродействие (speed). Вывести содержимое файла на экран.
programComputer1;
usesCrt;
typecomp = record{Описываем тип — запись с }
marka : string[15]; {характеристиками}
hdd, ram : real; {компьютера}
speed : integer;
end;
myfile = file ofcomp;
var fl : myfile;
i, n : integer;
cl : comp;
Begin
clrscr;
writeln ('Введите количество компьютеров');
readln(n);
assign(fl,'d:\computer');
{Открываем файл fl для записи в него данных]
rewrite(fl);
fori:=l ton do
Begin
writeln ('Введите марку компьютера:');
readln(cl .marka);
writeln('Введите объёмы его HDD и RAM:');
readln(cl.hdd, cl.ram);
writeln(' Введите быстродействие:');
readln(cl .speed);
{Записываем введённые данные в файл fl}
write(fl, cl);
end;
close(fl); {Закрываем файл fl}
writeln(' Марка Объём винчестера RAM Быстродействие');
Задание 1. Пусть количество данных заранее неизвестно. Модифицируйте программу, используя при вводе данных команду whileс условием конца ввода. При считывании данных из файла употребите функцию eof.
Задание 2. Решите задачу № 19 своего варианта.
Задача 2. Используя файл записей, созданный предыдущей программой, вывести на экран информацию о компьютерах, быстродействие которых больше 166 Мг.
programComputer;
usesCrt;
typecomp = record
marka : string[15];
hdd, ram : real;
speed : integer;
end;
myfile = file ofcomp;
var f1 : myfile;
i, n : integer;
cl : comp;
Begin
clrscr;
assign(fl, 'd:\computer');
{Открываем файл для считывания данных}
reset(fl);
while not eof(f 1) do{Выполняем цикл, пока не }
begin{достигнут конец файла}
read(fl, cl); {Считываем данные с файла}
if cl.speed > 166 then
writeln(cl.marka:15, cl.hdd:8:2, cl.ram:8:2);
end;
readln
end.
Задание З. Решите задачу № 20 своего варианта.
Замечание. Кроме файлов последовательного доступа можно создавать и обрабатывать файлы прямого доступа. Отличие следующее: перед выполнением команд read или write следует обеспечить доступ к k-му элементу файла (нумерация элементов начинается с нуля) с помощью команды
seek(<имя файла>, k);
3. Текстовые файлы. Данные в типизированных файлах, описанных выше, определенным образом кодируются компьютером. Поэтому эти файлы нельзя редактировать или пересматривать с помощью обычного текстового редактора. Кроме типизированных файлов можно использовать текстовые файлы, не имеющие такого недостатка.
Элементами текстовых файлов являются строки (последовательности символов: букв, цифр, знаков и пропусков). Такой файл можно создавать и править текстовым редактором. Разделителем между данными является пропуск. Ввод каждой строки заканчивается нажатием клавиши Enter. Для проверки наличия символов в строке используют функцию
еоln(<имя файла>);
которая принимает значения true, если достигнут конец строки.
Текстовые файлы описывают в разделе объявления переменных так:
var<список имен переменных> : text;
Данные из текстового файла можно считывать с помощью команд
геаd(<имя файла>, <список параметров>);
readln(<имя файла>, <список параметров>);
действие которых было описано выше. Различие между этими командами такое: во время выполнения команды readln лишние данные в строке игнорируются и следующая команда read или readln будет считывать данные со следующей строки.
Данные в текстовый файл можно записать с помощью обычного текстового редактора или программным способом, используя команды
write(<имя файла>, <список выражений>);
writeln(<имя файла>, <список выражений>);
В текстовый файл в отличие от обычных можно добавлять (дописывать) данные. Для этого вместо процедуры rewrite используют процедуру
append(<имя файла>);
Задача 3. Пусть некоторым текстовым редактором создан файл reki.txt, в котором содержится информация о длинах рек в километрах и площадях их бассейнов в квадратных километрах:
Нил
Миссисипи
Амазонка
Обь
Амур
Лена
Конго
Нигер
Волга
Выведите все данные с файла на экран, определите названия самой длинной реки и реки с самым большим бассейном.
programTextfile;
usesCrt;
typereka = record
name : string[10];
dl : integer;
pi : longint
end;
varmyfile : text;
myzap : reka;
namemax, nameplmax : stringfll];
dlmax : integer;
plmax : longint;
Begin
clrscr;
dlmax := 0;
plmax := 0;
writeln('Название реки, Длина (км), Бассейн (кв.км)');
assign(myfile,'d: \reki. txt');
reset(myfile);
while noteof(myfile) do
withmyzap do
Begin
readln(myfile, name, dl, pi);
writeln(name:10, dl:10, pl:15);
ifdl > dlmax then
Begin
dlmax := dl;
namemax := name
end;
ifplmax <pi then
Begin
plmax := pi;
nameplmax := name
end;
end;
writeln('Самая длинная река - ', namemax);
writeln('Самый большой бассейн реки ', nameplmax);
readln
end.
Задание 3. Решите задачу № 21 своего варианта.
4. Сортировка данных.Задачи сортировки и поиска нужной информации в файлах или массивах имеют важное значение. Рассмотрим алгоритм сортировки элементов по возрастанию методом обмена. Этот метод заключается в следующем: рассматривают набор данных и первую пару элементов. Если первый элемент больше второго, то их меняют местами. Второй элемент сравнивают с третьим и, если нужно, меняют их местами и т.д. Максимальный элемент окажется в конце набора, то есть там, где необходимо. Теперь рассматриваем снова набор данных, но уже без последнего элемента, и применяем к нему метод обмена — второй по величине элемент окажется в конце набора на предпоследнем месте и т.д. Если в наборе п элементов, то метод необходимо применить n—1 раз, каждый раз всё к меньшему количеству элементов. Отсортированные элементы будут в конце набора.
Задача 4. Пусть некоторым текстовым редактором создан файл reki.txt, в котором содержится информация о длинах 9 рек в километрах и площадях их бассейнов в квадратных километрах (см. задачу 3). Вывести данные из файла на экран. Занести файл в оперативную память в структуру данных массив. Отсортировать данные по алфавиту и вывести их на экран.
programTextfile1;
usesCrt;
typereka = record
name : stringflO];
dl : integer;
pi : longint
end;
constk=9;
varmyfile : text;
myzap : reka;
i, j : integer;
mas:array[1 .. k] ofreka;
Begin
clrscr;
assign(myfile,'d:\reki.txt');
reset(myfile);
writeln(' Данный файл');
writeln('Название реки, Длина (км), Бассейн (кв.км)');
while noteof(myfile) do
Begin
readln(myfile,myzap.name, myzap.dl, myzap.pl);
writeln(myzap.name:10, myzap.dl:10, myzap.pl:15);
mas[k]:=myzap;
end;
close(myfile);
fori:=l tok-1 do
forj:=l tok-i do
Begin
ifmas[j].name > mas[j+l].name then
Begin
myzap:=mas[j];
mas[ j ]: =mas[ j+1 ];
mas[j+l]:=myzap;
end;
end;
writeln(' Новый файл');
writeln('Название реки, Длина (км), Бассейн (кв.км)');
fori:=l tok do
withmas[i] do
writeln(name:10, dl:10, pl:15);
readln
end.
Задание 4. Решите задачу № 22 своего варианта, используя структуру данных массив записей.
СПИСКИ
1. Понятия о динамической памяти, указателях и динамических переменных.Различают обычную (статическую) и динамическую организации памяти компьютера. В оперативной памяти компьютера можно разместить ограниченное количество данных, в частности, переменных. Для переменных, объявленных в разделе var,система резервирует определенный объем памяти, даже если не все они будут использованы в программе. Память, предоставленная переменным, освобождается лишь после выполнения программы. Однако, на практике встречаются задачи, где заранее неизвестно сколько переменных нужно для их решения, и, следовательно, какой объем памяти следует зарезервировать. В этом случае, а также, если заранее известно, что данных будет много, применяют динамическую организацию памяти. Принцип динамической организации памяти заключается в том, что переменные занимают память по необходимости, обрабатываются и в нужный момент освобождают память. Такие переменные называются динамическими.
Для работы с динамическими переменными используют тип данных - указатель. Если имя статической переменной задает адрес данного в оперативной памяти, то указатель на динамическую переменную указывает лишь тип данного, а не его расположение в памяти. Тип данных указатель описывают с помощью символа ^в разделе type так:
type <название типа> = ^<базовый тип>;
Конкретные указатели на динамические переменные объявляют в разделе var:
var <список указателей на переменные> : <имя типа>;
Пример. Рассмотрим описания типов указателей и объявление указателей на динамические переменные:
Type
UkazNaCelye = ^integer;
UkazNaMassyv = ^array [1..100] of real;
UkazNaZapys = ^Zapys;
Var
cl, c2 : UkazNaCelye;
masl, mas2 : UkazNaMassyv;
zapl, zap2 : UkazNaZapys;
На этапе компиляции память для массивов и записей здесь не резервируется, но сам указатель будет занимать в памяти 4 байта. Память для данных, о возможности появления которых предупреждает указатель, будет предоставлена на этапе выполнения программы с помощью процедуры new:
new(<указатель на переменную>);
Только теперь образовалась динамическая переменная, имя которой имеет такой вид:
<указатель на переменную>^
Различают операции над указателем на динамическую переменную и операции над самой динамической переменной.
Над динамическими переменными можно выполнять те же операции, что и над данными соответствующих базовых типов.
Над указателями определены две операции переадресации
В результате выполнения первой команды переадресации указатель 1 будет указывать на тот же участок памяти, что и указатель 2, то есть они будут указывать на одно и то же данное.
В результате выполнения второй команды переадресации указатель становится свободным - nil. Он не будет указывать ни на какое конкретное данное.
После обработки динамической переменной память можно освободить с помощью процедуры
dispose(<указатель на динамическую переменную>)
Пример. Рассмотрим программу Ukazateli и ее графическую иллюстрацию на рис.1.
programUkazateli;
varcl, c2 : ^integer; {Объявляем два указателя}
Begin
new (cl); {Резервируем память для целого числа}
new (c2); {Резервируем память для целого числа}
с1^ := 5; {Переменной cl^ присваиваем значение 5}
с2^ := 7; {Переменной с2^ присваиваем значение 7}
writeln(cl^, c2^); {Выводим 5 и 7}
cl := с2; {Переадресация}
writeln(cl^, c2^); {Выводим 7 и 7}
с2 := nil; {Указатель с2 зануливаем}
{Память, предоставленную для с2, освобождаем}
dispose(c2)
writeln(cl^) {Выводим 7}
End.
Справка С помощью динамических переменных можно решить задачу поочередной обработки одной программой некоторого количества больших массивов (если все массивы ввести в память одновременно невозможно). Задачу решают так. Объявляют нужное количество указателей на массивы, например, varmasl, mas2,...: ^array...Создают массив new(masl) и обрабатывают динамические переменные masl^[l], masl^[2],...,masl^[i],... Освобождают память: dispose(masl). Создают и обрабатывают элементы второго массива mas2^ [i] и т.д.
Рис. 1. Графическая интерпретация действий с указателями
2. Понятие о списке.Рассмотрим структуру данных — однонаправленный список.
Список - это конечная совокупность данных одного типа, между которыми установлена связь. Элемент (однонаправленного) списка состоит из двух частей: самого данного (возможно сложного) и указателя на следующий элемент списка. Для описания такой структуры используют тип данных запись и тип данных указатель таким образом:
type<имя элемента списка> = ^<запись>;
<запись> = record
<поле данного 1> : <тип данного 1>;
…
<поле данного n> : <тип данного n>;
<поле указателя> : <имя элемента списка>
end;
Пример. Рассмотрим файл, в котором находятся данные о реках и назовем его reki.pas (см. задачу из § 10). Тип записи о реке назовем reka и поставим ему в соответствие элемент списка такого типа:
Type
elspyska =^reka;
reka = record
imia : string[ll];
dl : integer;
pi : longint;
sled : elspyska;
end;
varelement, pervyj, predyd, novyj : elspyska;
Здесь element - указатель на текущий элемент списка, element^ — динамическая переменная типа запись, element^.dl - динамическая переменная типа integer, которая получает значения длины реки, a element^.sled - указатель на следующий элемент списка. Отсюда вытекает, что element^.sled^.dl - это длина следующей реки, a element^.sled^.sled - указатель на далее следующую реку и т.д.
Задача 1. На диске имеется файл данных. К нему необходимо добавить еще одно данное. На базе старого файла создать новый файл с этим данным в начале.
Рассмотрим один из способов решения задачи. Данные следует ввести из файла в оперативную память, обработать и создать на носителе новый файл. Под обработкой будем понимать удаление данных или записывание дополнительных данных и т.д.
Чтобы ввести все данные из файла в оперативную память, хотелось бы использовать структуру данных — массив. Однако, количество данных в файле заранее неизвестно, поэтому обычный массив использовать нельзя. Даже если количество данных известно, то работать с таким массивом нерационально. Ведь, чтобы вставить в середину массива новый элемент, нужно сдвигать «хвост массива». Итак, для решения задачи нужна другая структура данных. Такой структурой данных является список.
Программа SpisokRek решает поставленную задачу и демонстрирует основные приемы обработки списка. Элементы списка обрабатывают друг за другом с помощью цикла. Сначала с помощью цикла создают список и вводят в него данные из файла. Специфика цикла в этой программе такая: после его завершения будет создан лишний (последний) элемент. Его следует ликвидировать, заранее объявив еще один указатель (на предыдущий элемент списка) и приняв predyd^.sled := nil. Существенное преимущество списков состоит именно в том, что удалить зафиксированный, то есть выбранный в соответствии с условием некоторой задачи, элемент можно с помощью одной команды переадресации вида
predyd^.sled := zafix^.sled.
Выводим список на экран. Создаем новый элемент списка и вводим в его поля данные, например, так:
Днепр (делаем пять пропусков и нажимаем клавишу ввода),
2201 (нажимаем клавишу ввода),
504000 (нажимаем клавишу ввода).
Новый элемент сделаем первым в списке, то есть поставим его перед первым элементом существующего списка. Преимущество списка над массивом ощутимое: чтобы вставить новый элемент после зафиксированного, нужно лишь две команды переадресации и никакой «грязной работы с хвостом». Указатель нового элемента переадресовываем туда, куда показывал указатель зафиксированного элемента, а указатель зафиксированного элемента «вонзаем» в новый элемент:
novyj^.sled := zafix^.sled;
zafix^.sled := novyj;
Найдите в программе место, где новый элемент записывается в список перед первым. Таким образом вносят изменения в список, снова пересматривают его на экране и выводят в файл reki2.pas. Убедитесь, что файл создан правильно. Не выходя из среды, средствами меню File и Open откройте файл reki2.pas и просмотрите его.
Рассмотрите рис.2 и программу SpisokRek. Выполните программу и поэкспериментируйте с ней.
program SpisokRek;
uses Crt;
Type
elspyska = ^reka;
reka = record
imia : string[ll];
dl : integer;
pi : longint;
sled : elspyska;
end;
Var
element, pervyj, predyd, novyj : elspyska;
Myfile, Myfile2 : text;
procedure SozdatSpysok(var Myfile : text);
Begin
new(element);
pervyj := element;
while not eof(Myfile) do
Begin
predyd := element;
with element^ do
readln (Myfile, imia, dl, pi);
new(element^.sled);
element := element^.sled
end;
{Удаляем последний лишний элемент}
predyd^.sled := nil;
end;
procedureVyvestyNaEkran;
Begin
writeln('Создан такой список:');
writeln;
element := pervyj;
whileelement <> nil do
Begin
withelement^ do
writeln(imia:ll, dl:8, pl:12);
element := element^.sled
end;
end;
procedureSozdatNovyjElement;
Begin
new(novyj);
writeln;
writeln ('Создаем новый элемент');
withnovyj^ do
Begin
write('Введите название - 11 символов: ');
readln(imia);
write('Введите длину реки: ');
readln(dl);
write('Введите площадь бассейна: ');
readln(pl)
end;
writeln
end;
procedureVyvestyvFile (varMyfile : text);
Begin
element := pervyj;
whileelement <> nil do
Begin
withelement^ do
writeln(Myfile, imiarll, dl:8, pl:12);
element := element^.sled
end;
writeln;
writeln ('Список занесен в файл. Конец работы')
end;
begin{Основная программа}
clrscr;
assign(Myfile, 'reki.pas');
assign(Myfile2, 'reki2.pas');
reset(Myfile);
SozdatSpysok(Myfile);
VyvestyNaEkran;
SozdatNovyjElement;
{Добавляем в список новый элемент и делаем его первым}
element := pervyj;
novyj^.sled := element;
pervyj := novyj;
VyvestyNaEkran;
rewrite(Myfile2);
VyvestyvFile(Myfile2);
close(Myfile);
close(Myfile2);
repeat untilkeypressed
End.
Задание 1. Модифицируйте задачу 1 так, чтобы в начале нового файла было дописано три записи.
Рис. 2. Графическая иллюстрация списка и действий над его
элементами
3. Понятие о стеке и очереди. Стек - это структура данных, в которой элемент, записанный последним, считывают (он является доступным к обработке) первым. Принцип «последний пришел -первый ушел» используется во многих технических устройствах и в быту: вспомните рожок от автомата, посадку пассажиров в вагон с одной дверью и т.д. Стек используют в программировании для реализации рекурсии. Рекурсия выполняется так: сначала все вызовы накапливаются (аналогия такая: пружина сжимается), а потом выполняются вложенные процедуры или функции (пружина распрямляется).
Очередь — это структура данных, в которой элемент, записанный первым, считывают первым. Здесь действует принцип «первый пришел - первый ушел», например: очередь за билетами, очередь на обслуживание и т.п.
Максимально допустимые размеры стека и очереди — важные характеристики реализации языка программирования, определяющие круг задач, которые можно решить. Стеки и очереди описывают и создают в памяти с помощью типа данных - указателя. Соответствующие описания и примеры процедур их обработки можно отыскать в справочниках.
Задание 2. Решите задачу № 21, применив список с целью добавления в файл нового элемента после элемента с номером imod5+1, где i-номер варианта.
Задание 3. Решите задачу № 22, применив структуру данных список.