
- •Лекция. Указатели Лекция. Указатели.
- •Указатели и динамическая память
- •2 Элемент списка
- •Операция взятия адреса @»
- •Сравнение указателей
- •Динамическая память.
- •Адресация памяти в компьютере
- •Выделение и освобождение динамической памяти.
- •Процедуры и функции для работы с динамической памятью.
- •9 ©Кащей Владимир Васильевич, миэт, каф. Иувс, тел. (095) 532-9882
Процедуры и функции для работы с динамической памятью.
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 возвращает размер, хранящийся в данной таблице.
[АДМИНИСТРАТОР КУЧИ здесь не рассматривается]
Рассмотрим использование указателей и динамических переменных на примере работы со списками, цепочками строк, деревьями.
Для каждого типа данных относящегося к спискам должны быть определены основные операции:
создание списка;
поиск заданного элемента в списке;
вставка элемента;
удаление элемента.
Рассмотрим строки-цепочки символов.
Описание типов. (Здесь для облегчения понимания мы будем использовать в идентификаторах русские буквы, что, конечно, недопустимо в Турбо-паскале).
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;
Здесь предполагается, что известен адрес удаляемого звена в указателе «звено», то есть поиск уже выполнен.
Вставка элемента.
Надо:
Создать новый динамический объект для вставляемого звена типа «звено».
В поле «элемент» внести литеру «р».
В поле «следующий» внести ссылку на следующий элемент, взятую из поля следующего элемента, за которым должно идти вставляемое звено.
В поле «следующий» звена, за которым должно идти вставляемое звено, занести ссылку на вставляемое звено.
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
* *
Схема с невключением заглавного элемента списка в кольцо.
Для двунаправленных и кольцевых списков определены те же операции:
- поиск элемента в списке;
- вставка заданного элемента в указанное место;
- удаление из списка заданного элемента.