Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Указатели в Pascal и Delphi лекция.doc
Скачиваний:
2
Добавлен:
01.07.2025
Размер:
156.16 Кб
Скачать

Процедуры и функции для работы с динамической памятью.

FUNCTION ADDR(X):Pointer

Здесь Х – любой объект программы. Функция возвращает адрес, совместимый с указателем любого типа. Аналогичный результат дает операция @.

FUNCTION CSEG:Word

Возвращает текущее значение сегмента CS в начале работы программы – там содержится сегмент начала кода программы.

PROCEDURE DISPOSE(Var P:pointer)

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

Невозможно использование с процедурами MARK и RELEASE.

Существует расширенный синтаксис процедуры, где в качестве второго параметра используется деструктор объекта. Например Dispose(P, Done).

FUNCTION SSEG:Word

Возвращает текущее значение регистра SS.

FUNCTION SPTR:Word

Возвращает текущее значение регистра SP.

FUNCTION DSEG:Word

Возвращает текущее значение регистра DS. В начале работы программы в нем содержится сегмент начала данных программы.

Procedure FREEMEM(Var P:Pointer; Size:Word)

Освобождение динамической памяти размера Size байт, которая была ранее зарезервирована за нетипизированным указателем.

Повторное использование к уже освобожденному фрагменту вызывает ошибку времени исполнения. Эту процедуру нельзя использовать совместно с процедурами Mark и Release в одной программе.

PROCEDURE GETMEM(Var P:Pointer; Size:Word)

Создает новую динамическую переменную размера Size байт и помещает ее адрес в указатель. (Size <=64K). Если нет указанного количества свободной памяти – возникает ошибка времени исполненияЕсли память не фрагментирована, то последовательные обращения к процедуре резервируют последовательные участки памяти (последующий сразу за предыдущим).

PROCEDURE MARK(Var P:Pointer)

Запоминает текущее значение указателя кучи HeapPtr в переменную p. данную процедуру нельзя использовать с процедурами FreeMem и Dispose.

ASSIGNED(Var P:Pointer):Boolean

Проверяет равенство указателя значению значению nil.

MAXAVAIL:Longint

Возвращает размер максимальногонепрерывного свободного размера блока в куче.

MEMAVAIL:Longint

Возвращает сумму размеров всех свободных блоков динамической области памяти.

NEW (Var P:Pointer)

Резервирует фрагмент кучи для размещения динамической переменной и устанавливает указатель на нее. За одно обращение резервируется не более 64К памяти. Если нет памяти указанного размера – возникает ошибка времени исполнения. Если память не фрагментирована, то последовательные обращения резервирует последовательные участки памяти.

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

New(P,Int(360,174))

Такая конструкция используется при реализации объектов (ООП).

Процедура New в синтаксисе Турбо-паскаля версии 6.0 была расширена до возможности использования ее в качестве функции, возвращающей указатель. Такая форма New как функции применима для всех типов указателей, а не только для объектных.

Функция New, так же как и процедура New, может иметь второй параметр – конструктор объектного типа.

OFS(X):Word

Возвращает смещение адреса Х, где Х – выражение любого типа или имя процедуры.

PTR(SEG,OFS:Word):Pointer

Возвращает значение типа указатель по заданномусегменту (SEG) и смещению (OFS). Значение PTR совместимо с указателем любого типа

RELEASE (Var P:Pointer)

Освобождает динамическую память от места помеченного с помощью процедуры Mark(p) до конца кучи. Нельзя использовать с помощью Freemem и Dispose.

SEG(X):Word

Возвращает сегмент Х, где Х – выражение любого типа или имя процедуры.

SIZEOF(X):Integer

Возвращает количество байт, занимаемых аргументом. Когда обращаются к экземпляру объектного типа, который имеет таблицу виртуальных методов, SizeOf возвращает размер, хранящийся в данной таблице.

[АДМИНИСТРАТОР КУЧИ здесь не рассматривается]

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

Для каждого типа данных относящегося к спискам должны быть определены основные операции:

  1. создание списка;

  2. поиск заданного элемента в списке;

  3. вставка элемента;

  4. удаление элемента.

Рассмотрим строки-цепочки символов.

Описание типов. (Здесь для облегчения понимания мы будем использовать в идентификаторах русские буквы, что, конечно, недопустимо в Турбо-паскале).

Type

Тип_элемента=char;

Связь=^звено_строки;

Звено_строки=record

Элемент:тип_элемента;

Следующий:связь;

End;

Динамическая_строка=связь;

Var

Str:динамическая строка;

Поиск элемента в строке

Function поиск(St:динамическая_строка; эл:тип_элемента;var res:связь):Boolean;

var

q:связь;

begin

поиск:=false; res:=nil; q:=st^.следующий;

while (q<>nil) and (res=nil) do

begin

if q^.элемент=эл then

begin

поиск:=true;

res:=q;

end;

q:=q^.следующий;

end;

end;

Удаление элемента

Procedure удаление(звено:связь);

Var

q:связь;

begin

if звено^.следующий<>nil then

begin

q:=звено^.следующий;

звено^.следующий:=звено^.следующий^.следующий;

dispose(q);

end;

end;

Здесь предполагается, что известен адрес удаляемого звена в указателе «звено», то есть поиск уже выполнен.

Вставка элемента.

Надо:

  1. Создать новый динамический объект для вставляемого звена типа «звено».

  2. В поле «элемент» внести литеру «р».

  3. В поле «следующий» внести ссылку на следующий элемент, взятую из поля следующего элемента, за которым должно идти вставляемое звено.

  4. В поле «следующий» звена, за которым должно идти вставляемое звено, занести ссылку на вставляемое звено.

Procedure вставка(звено:связь; элемент:тип_элемента);

Var

q;связь;

begin

new(q);

q^.элемент:=элемент;

q^.следующий;=звено^.следующий;

звено^.следующий:=q;

end;

Двунаправленные списки

Рассмотренная ранее строка является частным случаем однонаправленного списка.

С

*

*

*

элемент1

*

элемент2

nil

элемент2

П

Заглавное

звено

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

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

С

**

nil

*

эN

вязь2=^звено2;

З вено2=record

Следующее:связь2;

Предыдущее;связь2;

Элемент:элемент_списка

End;

Часто бывает удобно замкнуть список в кольцо.

**

*

*

эN

Такие списки называются кольцевыми списками.

**

*

*

эN

*

*

Схема с невключением заглавного элемента списка в кольцо.

Для двунаправленных и кольцевых списков определены те же операции:

- поиск элемента в списке;

- вставка заданного элемента в указанное место;

- удаление из списка заданного элемента.