Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции по программированию..pdf
Скачиваний:
10
Добавлен:
15.11.2022
Размер:
12.2 Mб
Скачать

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

14.2.Работа с файлами записей

Чаще всего записи используются как элементы файлов, составляю­ щих компьютерные информационные системы. Рассмотрим примеры программ, работающих с файлами записей.

П ример 1. Сформировать файл FM.DAT, содержащий экзаменаци­ онную ведомость одной студенческой группы. Записи файла состоят

из следующих элементов: (фамилия, и., о.; номер зачетной книжки; оценка).

Program

Examen;

 

 

 

Type

Stud в Record

String[30];

 

 

 

FIO

 

 

 

Nz

 

String[6];

 

 

 

Mark

2..5

 

Var

Fstud

End;

Of Stud;

 

File

 

 

S

Stud;

 

 

 

 

N,

I

Byte;

 

 

 

Begin

 

 

'FM.DAT');

 

Assign(Fstud,

 

Rewrite(Fstud);

 

 

Write('Количество студентов в группе? ');

ReadLn(N);

N Do

 

For I :* 1 To

 

Begin

1,

'-и, Фамилия И.О. ');

 

Write(I

 

ReadLn(S.FIO);

 

');

 

Write('Номер зачетки:

 

ReadLn(S.Nz);

 

');

 

 

 

Write('Оценка:

 

 

 

ReadLn(S.Mark);

 

 

 

Write(Fstud, S)

End;

Writeln('Формирование файла закончено!');

Close(Fstud)

End.

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

Прямой доступ к записям файла. В стандарте языка Паскаль до­ пустим только последовательный доступ к элементам файла. Одной из дополнительных возможностей, реализованных в ТУрбо-Паскале, яв­ ляется прямой доступ к записям файла.

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

Установка указателя на нужный элемент файла производится про­ цедурой

Seek(FV,n).

Здесь FV — имя файловой переменной, п — порядковый номер эле­ мента. В следующем примере эта процедура будет использована.

П ример 2. Имеется файл, сформированный программой из преды­ дущего примера. Пусть некоторые студенты пересдали экзамен и по­ лучили новые оценки. Составить программу внесения результатов пе­ реэкзаменовки в файл. Программа будет запрашивать номер студента в ведомости и его новую оценку. Работа заканчивается, если вводится несуществующий номер (9999).

Program New.Marks;

 

Type Stud = Record

String[30];

FIO

Nz

String[6];

Mark

2..5

Var Fstud

End;

File Of Stud;

S

Stud;

N

Integer;

Begin

 

 

Assign(Fstud, ’FM.DAT');

Reset(Fstud);

Write С Номер в ведомости? *);

ReadLn(N);

While N О 9999 Do

Begin

Seek(Fstud, N - 1);

Read(Fstud, S);

Write(S.FI0, * оценха? *);

ReadLn(S.Mark);

Seek(Fstud, N - 1);

Write(Fstud, S);

Write(,HoKep в ведомости? О;

ReadLn(N);

End;

WriteLnC Работа закончена!') ;

Close(Fstud)

End.

Пример требует некоторых пояснений. Список студентов в ведомо­ сти пронумерован, начиная от 1, а записи в файле нумеруются от 0. Поэтому, если п это номер в ведомости, то номер соответствующей записи в файле равен п -1 . После прочтения записи номер п -1 указа­ тель смещается к следующей n-й записи. Для повторного занесения на то же место исправленной записи повторяется установка указателя.

Задания

1.Описать запись, содержащую сведения о рейсе самолета.

2.Описать массив записей, содержащий таблицу Д.И. Менделеева. Составить программу заполнения массива.

3.Рассматривая комплексное число как двухэлементную запись, со­ ставить процедуры выполнения арифметических операций с комплек­ сными числами.

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

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

в) выяснить, какие детали имеются в наибольшем количестве, какие —

в наименьшем; г) вывести информацию о наличии на складе деталей данного типа и их количестве;

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

15.1. Динамическая память и указатели

До сих пор мы рассматривали программирование, связанное с об­ работкой только статических данных. Статическими величинами на­ зываются такие, память под которые выделяется во время компиляции

исохраняется в течение всей работы программы.

ВПаскале существует и другой способ выделения памяти под дан­ ные, который называется динамическим. В этом случае память под величины отводится во время выполнения программы. Такие величины будем называть динамическими. Раздел оперативной памяти, распре­ деляемый статически, называется статической памятью; динамически распределяемый раздел памяти называется динамической памятью.

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

Работа с динамическими величинами связана с использованием еще одного типа данных — ссылочного тппа. Величины, имеющие ссылоч­

ный тип, называют указателями.

Указатель содержит адрес поля в динамической памяти, хранящего величину определенного типа. Сам указатель рас­ полагается в статической памяти.

Статическая память

Динамическая память

Указатель

Величина

1 Адрес

■Н Значение 1

Адрес величины — это номер первого байта поля памяти, 3 котором располагается величина. Размер поля однозначно определяется типом.

Величина ссылочного типа (указатель) описывается в разделе опи-

сания переменных следующим образом:

Var <идентификатор> <ссылочный тип>;

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

< ссылочный тип> := "<имя типа>;

Вот примеры описания указателей:

Type Massiv = Array[l..100] Of Integer;

Var PI "Integer;

P2 "Char;

Pm "Massiv;

Здесь PI — указатель на динамическую величину целого типа; Р2 — указатель на динамическую величину символьного типа; РМ — указа­ тель на динамический массив, тип которого задан в разделе Туре.

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

Каким же о бразом происходит выделение памяти под динамическую величину? Память под динамическую величину, связанную с указате­ лем, выделяется в результате выполнения стандартной процедуры NEW. Формат обращения к этой процедуре:

NEW (<указатель>);

Считается, что после выполнения этого оператора создана динами­ ческая величина, имя которой имеет следующий вид:

<имя динамической величины>

<ужаэатель>"

Пусть в программе, в которой имеется приведенное выше описание, присутствуют следующие операторы:

NEW(Pl); NEW(P2); NEW(PM);

После их выполнения в динамической памяти оказывается выделен­ ным место под три величины (две скалярные и один массив), которые имеют идентификаторы:

Р1~, Р2~, РМ~

Например, обозначение Р1~ можно расшифровать так: динамичес­ кая переменная, на которую ссылается указатель Р1Л.

На схеме показана связь между динамическими величинами и их указателями.

Статическая память

Динамическая память

Дальнейшая работа с динамическими переменными происходит точно так же, как со статическими переменными соответствующих типов. Им можно присваивать значения, их можно использовать в ка­ честве операндов в выражениях, параметров подпрограмм и пр. На­ пример, если переменной Р1Лнужно присвоить число 25, переменной Р2~ присвоить значение символа “W ” , а массив PJT заполнить по по­ рядку целыми числами от 1 до 100, то это делается так:

Р1~ := 25;

Р2~ := ’W ’;

For I := 1 То 100 Do

Р*Г[1] := I;

Кроме процедуры NEWзначение указателя может определяться опе­ ратором присваивания:

<указатель> := Сссылочное выраженйе>;

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

указатель;

ссылочную функцию (т.е. функцию, значением которой является указатель);

— константу Nil.

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

До присваивания значения ссылочной переменной (с помощью опе­ ратора присваивания или процедуры NEW) она является неопределен­ ной.

Ввод и вывод указателей не допускается.

Рассмотрим пример. Пусть в программе описаны следующие указа­ тели:

Var D, Р *Integer;

К"Boolean;

Тогда допустимыми являются операторы присваивания

D:= Р;

К:» Nil;

поскольку соблюдается принцип соответствия типов. Оператор К := D ошибочен, т.к. базовые типы у правой и левой части разные.

Если динамическая величина теряет свой указатель, то она стано­ вится “мусором” . В программировании под этим словом понимают информацию, которая занимает память, но уже не нужна.

Представьте себе, что в программе, в которой присутствуют опи­ санные выше указатели, в разделе операторов записано следующее:

NEW(D); NEW(P);

D~

:* 3; Р~ := 5;

Р

:= D;

WriteLn(P~, D~);

{Выделено место в динамической памяти под две целые переменные. Указатели получили соответствующие значения} {Динамическим переменным присвоены значения}

{Указатели Р и D стали ссылаться на одну и ту же величину, равную 3} {Дважды напечатается число 3}

Таким образом, динамическая величина, равная 5, потеряла свой указатель и стала недоступной. Однако место в памяти она занимает. Это и есть пример возникновения “мусора” На схеме показано, что произошло в результате выполнения оператора Р := D.

В Паскале имеется стандартная процедура, позволяющая освобож­ дать память от данных, потребность в которых отпала. Ее формат:

DISP0SE(<yKa3aTenb>);

Например, если динамическая переменная Р~ больше не нужна, то оператор

DISPOSE(P)

удалит ее из памяти. После этого значение указателя Р становится не­ определенным. Особенно существенным становится эффект экономии памяти при удалении больших массивов.

В версиях Турбо-Паскаля, работающих под операционной системой MS DOS, под данные.одной программы выделяется 64 килобайта па­ мяти. Это и есть статическая область памяти. При необходимости работать с большими массивами информации этого может оказаться мало. Размер динамической памяти — много больше (сотни килобайт). Поэтому использование динамической памяти позволяет существенно увеличить объем обрабатываемой информации.

Следует отчетливо понимать, что работа с динамическими данными замедляет выполнение программы, поскольку доступ к величине про­ исходит в два шага: сначала ищется указатель, затем по нему --- вели­ чина. Как это часто бывает, действует “закон сохранения неприятно­ стей” : выигрыш в памяти компенсируется проигрышем во времени.

Пример. Создать вещественный массив из 10000 чисел, заполнить его случайными числами в диапазоне от 0 до 1. Вычислить вреднее значение массива. Очистить динамическую память. Создать целый массив размером 10000, заполнить его случайными целыми числами в диапазоне от -100 до 100 и вычислить его среднее значение.