- •ПРЕДИСЛОВИЕ
- •1.1. История и классификация языков программирования высокого уровня
- •1.2. Первое (знакомство с Паскалем
- •Задания
- •Лекция 2
- •2.1. Некоторые сведения о системе ТУрбо-Паскаль
- •2.2. Способы описания языка программирования
- •Лекция 3
- •3.2. Типы данных
- •4.1. Структура Паскаль-программы
- •4.2. Арифметические операции, функции, выражения Арифметический оператор присваивания
- •Форматы процедуры write
- •Задания
- •1. Что будет напечатано программой
- •если последовательно вводятся три числа: 36, -6, 2345?
- •5.2. Функции, связывающие различные типы данных
- •Задания
- •Теперь посмотрим, как это программируется наТЛаскале.
- •Здесь
- •<параметр цикла>::= <имя простой переменной порядкового типа>
- •Задания
- •7.1. Подпрограммы-процедуры
- •7.2. Подпрограммы-функции
- •7.4. Рекурсивные подпрограммы
- •8.1. Что такое рекуррентная последовательность
- •8.2. Программирование вычислений рекуррентных последовательностей
- •Задания
- •Задания
- •6. Вывод результата.
- •Теперь будем составлять подпрограммы.
- •Задания
- •12.2. Операции над множествами
- •12.3. Примеры использования множеств
- •Красивая программа! К сожалению, ею нельзя воспользоваться для
- •В этой программе использована функция определений размера файла:
- •.Fiiesize(<HMH файловой переменной>);
- •Задания
- •14.2. Работа с файлами записей
- •Задания
- •15.2. Связанные списки
- •Лекция 16
- •16.1. Организация внешних подпрограмм
- •16,2. Создание и использование модулей
- •распечаткой текста программы с подробными комментариями.
- •выполнения следующих операции над обыкновенными дробями вида -q
- •(Р — целое, Q — натуральное):
- •1) сложение;
- •2) вычитание;
- •3) умножение;
- •4) деление;
- •5) сокращение дроби;
- •7) функции, реализующие операции отношения (равно, не равно,
- •Используя этот модуль, решить задачи:
- •При разработке модуля рекомендуется такая последовательность
- •Задания
- •Приведем текст программы целиком.
- •ЗАДАНИЯ ПО ТЕМЕ “ЛИНЕЙНЫЕ АЛГОРИТМЫ”
- •ЦЕЛОЧИСЛЕННАЯ АРИФМЕТИКА
- •Сортировка массивов
- •ЗАДАЧИ ПО ТЕМЕ “ОБРАБОТКА СТРОК”
- •ЗАДАНИЯ ПО ТЕМЕ “МОДУЛИ”
- •ЗАДАНИЯ ПО ТЕМЕ “ДИНАМИЧЕСКИЕ ПЕРЕМЕННЫЕ”
- •Задачи, предлагавшиеся на школьных олимпиадах по программированию (Пермская область)
- •Учебное издание
реализуется с использованием тая называемой вариантной ласти за писи. Подробно об этом читайте в книгах по Паскалю.
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 и вычислить его среднее значение.