- •1. Подпрограммы
- •1.1. Описание подпрограмм
- •1.2. Обращение к подпрограммам
- •1.3. Виды параметров подпрограмм
- •1.3.1. Параметры-значения и параметры-переменные
- •1.3.2. Параметры процедурного типа
- •1.3.3. Параметры-константы
- •1.3.4. Нетипизированные параметры подпрограмм
- •1.3.5. Массивы и строки открытого типа
- •1.4. Рекурсивные подпрограммы
- •2. Файлы данных
- •2.1. Текстовые файлы
- •2.2. Типизированные файлы
- •2.3. Нетипизированные файлы
- •2.4. Обработка ошибок, возникающих в действиях с файлами
- •3. Указатели - ссылочные типы данных
- •4. Модули
- •5. Локальные и глобальные сети эвм
- •6. Базы данных
- •6.1. Модели организации данных
- •6.2. Нормализация данных
- •6.3. Типы связей между объектами
- •7. Основы компьютерной безопасности
- •7.1. Компьютерные вирусы
- •7.2. Защита информации в Интернете
- •Контрольные работы
- •Тема 1. Параметры-значения и параметры-переменные
- •Пример выполнения задания
- •Решение. Составляем алгоритм (изображен ниже), а затем программу.
- •Варианты задания
- •Тема 2. Процедурный тип Пример выполнения задания
- •Варианты задания
- •Тема 3. Рекурсия Пример выполнения задания
- •Варианты задания
- •Тема 4. Текстовые и типизированные файлы Пример выполнения задания
- •Варианты задания
- •Тема 5. Указатели Пример выполнения задания
- •Варианты задания
- •Тема 6. Модули Пример выполнения задания
- •Варианты задания
- •Библиографический список
- •Оглавление
- •1.1. Описание подпрограмм ……………………………………………… 1
2.4. Обработка ошибок, возникающих в действиях с файлами
Останов программы, возникающий из-за ошибок, связанных с файловыми операциями, может быть предотвращен и заменен соответствующим диалогом с пользователем. Для этого необходимо перед очередной файловой операцией в программе отменить директивой {$I-} действующий по умолчанию (директива {$I+}) автоматический контроль ошибок. В этом случае становится доступной для применения функция без параметров IOResult. Она возвращает код ошибки (0 – если нет ошибки), а также разблокирует операции ввода/вывода. Покажем на иллюстративном примере вариант организации диалога с пользователем в случае возникновения ошибок этапа выполнения (Run-Time).
program Obrabotka_Oshibok_Rabot_s_Files;
var
f : text;
s : string;
kod : byte;
begin
{$I-} {Отключение автоконтроля}
repeat
writeln('Введите имя файла'); readln(s);
assign(f, s);
reset(f); {Файловая операция}
kod := IOResult; {Код результата}
if kod <> 0 then begin {Возникла ошибка}
writeln('Ошибка при открытии файла');
case kod of
2 : writeln('Файл не найден'); {Коды ошибок}
3 : writeln('Путь не найден') {времени выполнения}
end {case}
end {if}
until kod = 0;
{$I+} {Пример действий – вывод строк из файла на экран}
repeat
readln(f, s);
writeln(s)
until eof(f)
end.
3. Указатели - ссылочные типы данных
До сих пор нами рассматривались статические структуры данных. Память под них выделяется при компиляции. Имеется другой способ выделения и освобождения памяти – динамический, при котором память распределяется в процессе выполнения программы. Производится это с помощью особых типов данных – указателей. Именно указатели позволяют реализовать одну из основных технологий современных операционных систем, базирующуюся на библиотеках динамической компоновки (DLL – Dynamic Linking Library). В памяти компьютера имеются области для системных целей, сегмента стека, выполняемых программ. Вся не занятая названными областями память может быть использована в процессе выполнения программ и потому получила название динамически распределяемой памяти (ДРП) или кучи (Heap). По умолчанию минимальный и максимальный размеры кучи составляют соответственно 0 и 655360 байтов.
Указатели бывают типизированными и нетипизированными. Переменные, относящиеся к названным типам указателей, описываются так:
var <Имя> : pointer; {Нетипизированный указатель}
<Имя> : ^ <Базовый тип>; {Указатель на базовый тип}
Символ '^' читается как 'указатель на'. В качестве примера опишем указатель на элемент некоторого списка, размещаемого в ДРП. Элемент имеет два поля: информационное и адресное. При том возникает ситуация, в которой нарушается требование описания объекта до его использования. Для указателей сделано единственное исключение из названного правила.
type
point = ^element; {Указатель на тип element}
element = record
data : word; {Поле данных}
next : point {Поле указателя}
end;
var
p, q : point; {Переменные типа указатель}
Указатели не могут быть ни введены, ни выведены; для однотипных указателей применима операция присваивания, их можно сравнивать. Значением переменной типа указатель является адрес объекта базового типа, и его можно получить следующими двумя способами:
p := @<Переменная> или q := Addr(<Переменная>).
Так как адрес любого объекта в памяти компьютера представляет собой совокупность номера сегмента и смещения в нем, то можно воспользоваться стандартными функциями для отыскания составляющих адреса:
Seg(<Переменная>) и Ofs(<Переменная>).
При этом следует учитывать то обстоятельство, что динамические переменные не имеют собственного имени и обращаются к ним через указатель с помощью конструкции, получившей название разыменования. Так, запись p^ означает 'переменная, на которую ссылается указатель p' (это и будет динамическая переменная). Зная сегмент и смещение, можно найти значение указателя с помощью стандартной функции ptr:
p := ptr(<Сегмент>, <Смещение>).
Указатель занимает 4 байта памяти: 2 – номер сегмента и 2 – смещение.
Динамическое выделение и освобождение памяти производят для типизированного указателя p процедурами New(p) и Dispose(p) соответственно, а для указателя q любого типа – GetMem(q, Size) и FreeMem(q, Size). Второй параметр последней пары процедур задает размер памяти в байтах. Процедуры должны использоваться только в таком сочетании друг с другом. Размер поля, выделяемого процедурами New и GetMem, всегда доводится до кратного 8. Пока динамические переменные не созданы, значение указателя не определено. В этом случае переменной типа указатель можно присваивать значение nil. Константа nil означает отсутствие ссылки на какой-либо объект и распознается системой.
Рассмотрим примеры использования указателей для решения таких распространенных задач, как действия со списками и создание структур большого размера в ДРП.
Пример 1. Создадим с помощью трех указателей три элемента в ДРП
a
b
c
и свяжем их между собой так, чтобы поле ссылки первого элемента содержало адрес второго, поле ссылки которого – адрес третьего элемента. После установления таких связей можно ‘обнулить’ исходные указатели b и c.
a
b
:= nil
c := nil
nil
В приведенной ниже программе использована стандартная функция MemAvail, возвращающая размер свободной ДРП. Имеется также функция MaxAvail, возвращающая размер максимального непрерывного участка свободной области ДРП.
program ukazateli;
type
pnt = ^z; {Тип указатель на базовый тип z}
z = record
inf : word; {Информационное поле}
uk : pnt {Поле ссылки}
end;
var
a, b, c : pnt;
begin
writeln('Свободно ', MemAvail, ' байтов');
{Выделение памяти под три динамические переменные}
new(a); new(b); new(c);
writeln('Свободно ', MemAvail, ' байтов');
a^.inf := 2; {Заполнение полей данных записей}
b^.inf := 4;
c^.inf := 11;
a^.uk: = b; {Связываем элементы друг с другом}
b^.uk := c;
c^.uk := nil; {Последний элемент ни на что не ссылается}
b := nil; c := nil; {‘Обнуляем’ ссылки на второй и третий элементы списка}
writeln('Значение информационного поля третьего элемента:');
writeln(a^.uk^.uk^.inf); {Оно доступно через соответствующие указатели}
repeat {Освобождение динамической памяти}
b := a;
a := a^.uk;
dispose(b)
until a = nil;
writeln('Свободно ', MemAvail, ' байтов');
writeln('Нажмите ENTER'); readln
end.
Пример 2. С помощью указателей можно создавать в ДРП структуры большого размера, который превышает максимально допустимый размер в 65520 байтов для статических структур. Создадим для примера матрицу 200х100 вещественных чисел.
program Gros_Mas;
type
Stroka = array[1..100] of real; {Базовый тип}
var
p : array[1..200] of ^Stroka; {Массив указателей на строки}
j, i : byte;
begin
writeln('Свободно до размещения массива в ДРП', MemAvail, ' байтов');
for i:=1 to 200 do begin
GetMem(p[i], SizeOf(Stroka)); {Выделение памяти под i-ю строку матрицы}
for j := 1 to 100 do
p[i]^[j] := i + j; {Заполнение i-й строки матрицы}
end;
writeln('Свободно после размещения массива в ДРП ', MemAvail, ' байтов');
writeln('Контрольный вывод второго и 99-го элементов из 1 и 100 строк');
writeln(p[1]^[2] : 2 : 0);
writeln(p[100]^[99] : 4 : 0);
for i:=1 to 200 do {Очистка памяти}
FreeMem(p[i], SizeOf(Stroka));
writeln('Нажмите ENTER'); readln end.
Среди стандартных средств языка имеются следующие типизированные константы типа pointer. Для обозначения начала ДРП служит инициализированная переменная HeapOrg, а ее конца – HeapEnd. На край занятой части ДРП указывает HeapPtr. Процедура Release(<Нетипизированный указатель>) освобождает участок ДРП, начало которого обозначает <Нетипизированный указатель>, а конец – HeapPtr. Оператор Release(HeapOrg); освобождает всю ДРП. Процедуру не следует использовать попеременно с процедурами Dispose и FreeMem.
