ПОСЛЕДОВАТЕЛЬНЫЙ И ПРЯМОЙ ДОСТУП
Смысл последовательного доступа заключается в том, что в каждый момент времени доступна лишь одна компонента из всей последовательности. Для того, чтобы обратиться (получить доступ) к компоненте с номером К, необходимо просмотреть от начала файла К-1 предшествующую компоненту. После обращения к компоненте с номером К можно обращаться к компоненте с номером К+1. Отсюда следует, что процессы формирования (записи) компонент файла и просмотра (чтения) не могут произвольно чередоваться. Таким образом, файл вначале строится при помощи последовательного добавления компонент в конец, а затем может последовательно просматриваться от начала до конца.
Рассмотренные ранее средства работы с файлами обеспечивают последовательный доступ.
TURBO PASCAL позволяет применять к компонентным и бестиповым файлам, записанным на диск, способ прямого доступа. Прямой доступ означает возможность заранее определить в файле блок, к которому будет применена операция ввода - вывода. В случае бестиповых файлов блок равен размеру буфера, для компонентных файлов блок - это одна компонента файла.
Прямой доступ предполагает, что файл представляет собой линейную последовательность блоков. Если файл содержит n блоков, то они нумеруются от 1 через 1 до n. Кроме того, вводится понятие условной границы между блоками, при этом условная граница с номером 0 расположена перед блоком с номером 1, граница с номером 1 расположена перед блоком с номером 2 и, наконец, условная граница с номером n находится после блока с номером n.
Реализация прямого доступа осуществляется с помощью функций и процедур FileSize, FilePos, Seek и Truncate.
Функция FileSize( var f ): Longint возвращает количество блоков в открытом файле f.
Функция FilePos( var f ): Longint возвращает текущую позицию в файле f. Позиция в файле - это номер условной границы. Для только что открытого файла текущей позицией будет граница с номером 0. Это значит, что можно записать или прочесть блок с номером 1. После чтения или записи первого блока текущая позиция переместится на границу с номером 1, и можно будет обращаться к блоку с номером 2. После прочтения последней записи значение FilePos равно значению FileSize.
Процедура Seek( var f; N: Longint) обеспечивает назначение текущей позиции в файле (позиционирование). В параметре N должен быть задан номер условной границы, предшествующей блоку, к которому будет производиться последующее обращение. Например, чтобы работать с блоком 4, необходимо задать значение N, равное 3. Процедура Seek работает с от- крытыми файлами.
Процедура Truncate( var f ) устанавливает в текущей позиции признак конца файла и удаляет (стирает) все последующие блоки.
Пример. Пусть на НМД имеется текстовый файл ID.DAT, который содержит числовые значения действительного типа по два числа в каждой строке - значения аргумента и функции соответственно. Количество пар чисел не более 200. Составить программу, которая читает файл, значения аргумента и функции записывает в одномерные массивы, подсчитывает их количество, выводит на экран дисплея и записывает в файл компонентного типа RD.DAT.
Program F;
var
rArg, rF: Array[1..200] of Real;
inf: Text;
outf: File of Real;
n, l: Integer;
begin
Assign(inf,'ID.DAT');
Assign(outf,'RD.DAT');
Reset(inf);
Rewrite(outf);
n:=0;
while not EOF(inf) do
begin
n:=n+1;
ReadLn(inf,rArg[n],rF[n])
end;
for l:=1 to n do
begin
WriteLn(l:2,rArg[l]:8:2,rF[l]:8:2);
Write(outf,rArg[l], rF[l]);
end;
close(outf)
end.
УКАЗАТЕЛИ.
Операционная система MS - DOS все адресуемое пространство делит на сегменты. Сегмент - это участок памяти размером 64 К байт. Для задания адреса необходимо определить адрес начала сегмента и смещение относительно начала сегмента.
В TURBO PASCAL определен адресный тип Pointer - указатель. Переменные типа Pointer
var p: Pointer;
содержат адрес какого - либо элемента программы и занимают 4 байта, при этом адрес хранится как два слова, одно из них определяет сегмент, второе - смещение.
Переменную типа указатель можно описать другим способом.
type NameType= ^T;
var p: NameType;
Здесь p - переменная типа указатель, связанная с типом Т с помощью имени типа NameType. Описать переменную типа указатель можно непосредственно в разделе описания переменных:
var p: ^T;
Необходимо различать переменную типа указатель и переменную, на которую этот указатель ссылается. Например если p - ссылка на переменную типа Т, то p^ - обозначение этой самой переменной.
Для переменных типа указатель введено стандартное значение NIL, которое означает, что указатель не ссылается ни к какому объекту. Константа NIL используется для любых указателей.
Над указателями не определено никаких операций, кроме проверки на равенство и неравенство.
Переменные типа указатель могут быть записаны в левой части опера- тора присваивания, при этом в правой части может находиться либо функция определения адреса Addr(X), либо выражение @ X, где @ - унарная операция взятия адреса, X - имя переменной любого типа, в том числе процедурного.
Переменные типа указатель не могут быть элементами списка ввода - вывода.
ДИНАМИЧЕСКИЕ ПЕРЕМЕННЫЕ
Статической переменной (статически размещенной) называется описанная явным образом в программе переменная, обращение к ней осуществляется по имени. Место в памяти для размещения статических переменных определяется при компиляции программы.
В отличие от таких статических переменных в программах, написанных на языке ПАСКАЛЬ, могут быть созданы динамические переменные. Основное свойство динамических переменных заключается в том, что они соз- даются и память для них выделяется во время выполнения программы. Размещаются динамические переменные в динамической области памяти (heap - области).
Динамическая переменная не указывается явно в описаниях переменных и к ней нельзя обратиться по имени. Доступ к таким переменным осуществляется с помощью указателей и ссылок.
Работа с динамической областью памяти в TURBO PASCAL реализуется с помощью процедур и функций New, Dispose, GetMem, FreeMem, Mark, Release, MaxAvail, MemAvail, SizeOf.
Процедура New( var p: Pointer ) выделяет место в динамической области памяти для размещения динамической переменной p^ и ее адрес присваивает указателю p.
Процедура Dispose( var p: Pointer ) освобождает участок памяти, выделенный для размещения динамической переменной процедурой New, и значение указателя p становится неопределенным.
Процедура GetMem( var p: Pointer; size: Word ) выделяет участок памяти в heap - области, присваивает адрес его начала указателю p, размер участка в байтах задается параметром size.
Процедура FreeMem( var p: Pointer; size: Word ) освобождает учас- ток памяти, адрес начала которого определен указателем p, а размер - параметром size. Значение указателя p становится неопределенным.
Процедура Mark( var p: Pointer ) записывает в указатель p адрес начала участка свободной динамической памяти на момент ее вызова.
Процедура Release( var p: Pointer ) освобождает участок динамичес- кой памяти, начиная с адреса, записанного в указатель p процедурой Mark, то-есть, очищает ту динамическую память, которая была занята после вызова процедуры Mark.
Функция MaxAvail: Longint возвращает длину в байтах самого длинно- го свободного участка динамической памяти.
Функция MemAvail: Longint полный объем свободной динамической па- мяти в байтах.
Вспомогательная функция SizeOf( X ): Word возвращает объем в бай- тах, занимаемый X, причем X может быть либо именем переменной любого типа, либо именем типа.
Рассмотрим некоторые примеры работы с указателями.
var
p1, p2: ^Integer;
Здесь p1 и p2 - указатели или переменные ссылочного типа.
p1:=NIL; p2:=NIL;
После выполнения этих операторов присваивания указатели p1 и p2 не будут ссылаться ни на какой конкретный объект.
New(p1); New(p2);
Процедура New(p1) выполняет следующие действия:
· в памяти ЭВМ выделяется участок для размещения величины целого типа;
· адрес этого участка присваивается переменной p1:
г===== г=====
¦ *--¦--------->¦ ¦
L=====- L=====-
p1 p1^
Аналогично, процедура New(p2) обеспечит выделение участка памяти, адрес которого будет записан в p2:
г===== г=====
¦ *--¦--------->¦ ¦
L=====- L=====-
p2 p2^
После выполнения операторов присваивания
p1^:=2; p2^:=4;
в выделенные участки памяти будут записаны значения 2 и 4 соответ- ственно:
г===== г=====
¦ *--¦--------->¦ 2 ¦
L=====- L=====-
p1 p1^
г===== г=====
¦ *--¦--------->¦ 4 ¦
L=====- L=====-
p2 p2^
В результате выполнения оператора присваивания
p1^:=p2^;
в участок памяти, на который ссылается указатель p1, будет записано значение 4:
г===== г=====
¦ *--¦--------->¦ 4 ¦
L=====- L=====-
p1 p1^
г===== г=====
¦ *--¦--------->¦ 4 ¦
L=====- L=====-
p2 p2^
После выполнения оператора присваивания
p2:=p1;
оба указателя будут содержать адрес первого участка памяти:
г===== г=====
¦ *--¦--------->¦ 4 ¦
L=====- --->L=====-
p1 ¦ p1^ p2^
¦
г===== ¦
¦ *--¦-------
L=====-
p2
Переменные p1^, p2^ являются динамическими, так как память для них выделяется в процессе выполнения программы с помощью процедуры New.
Динамические переменные могут входить в состав выражений, напри- мер:
p1^:=p1^+8; Write('p1^=',p1^:3);
Пример. В результате выполнения программы:
Program DemoPointer;
var p1,p2,p3:^Integer;
begin
p1:=NIL; p2:=NIL; p3:=NIL;
New(p1); New(p2); New(p3);
p1^:=2; p2^:=4;
p3^:=p1^+Sqr(p2^);
writeln('p1^=',p1^:3,' p2^=',p2^:3,' p3^=',p3^:3);
p1:=p2;
writeln('p1^=',p1^:3,' p2^=',p2^:3)
end.
на экран дисплея будут выведены результаты:
p1^= 2 p2^= 4 p3^= 18
p1^= 4 p2^= 4
Не нашли, что искали? Воспользуйтесь поиском по сайту:
©2015 - 2024 stydopedia.ru Все материалы защищены законодательством РФ.
|