Читайте также:
|
|
Вся динамическая память в турбо-паскале рассматривается как подобная стеку структура, называемая кучей (Heap). Физически куча располагается в старших адресах, сразу за областью памяти для загрузки оверлеев.
Адрес начала кучи хранится в переменной HeapOrg, конец – в FreePtr, текущая граница не занятой динамической памяти хранится в HeapPtr.
Для выделения памяти под любую переменную используется процедура New, единственным параметром которой является типизированный указатель.
Пример:
Var
I,j: ^Integer;
R: ^Real;
Begin
New(I); New(R);
После выполнения New(I) указатель I приобретает значение, которое имел перед этим текущий указатель границы HeapPtr. Сам указатель HeapPtr увеличивает свое значение на 2, так как длина внутреннего представления типа Integer равна 2 байтам. New(R) вызовет смещение на 6 байт.
После того как указатель приобрел конкретное значение, то есть стал указывать на конкретный физический адрес, по этому адресу можно разместить значение соответствующего типа, например,
I^:=2;
R^:=2*Pi;
Допускается, например, R^:=Sqr(R^)+I^-17. Но совершенно недопустимо: R:= Sqr(R^)+I^-17, так как указателюR нельзя присвоить значение вещественного выражения.
Динамическую память можно (и рекомендуется) возвращать в кучу: Dispose(R); Dispose(I) – вернет в кучу 8 байт, ранее взятых.
Процедура Dispose(Ptr) не изменяет значения указателя Ptr, а лишь возвращает в кучу память, ранее связанную с этим указателем. Однако, повторное применение процедуры к «свободному» указателю приведет к возникновению ошибки периода исполнения. Чтобы пометить освободившийся указатель, можно использовать Nil.
Const
P:^Real=Nil;
…….
If P=Nil then
New(P);
…
Dispose(P);
P:=Nil;
Следует учесть, что начальное значение указателя при его объявлении в разделе переменных может быть произвольным. Использование указателей, которым не присвоено значение процедурой New или каким-либо другим способом, никак не контролируется системой и может привести к непредсказуемым результатам.
Чередование New и Dispose обычно приводит к «ячеистой» структуре памяти.
Существует еще одна возможность для освобождения целого фрагмента кучи. Перед выделением памяти текущее значение указателя HeapPtr запоминается с помощью процедуры Mark. Теперь можно в любой момент освободить фрагмент кучи от этого адреса до конца кучи с помощью процедуры Release.
Var
P, P1, P2, P3, P4, P5:^Integer;
Begin
P1^ |
P2^ |
P3^ |
P4^ |
P5^ |
New(P1);
New(P2);
Mark(P);
New(P3);
New(P4);
New(P5);
…
Release(P);
P1^ |
P2^ |
P4^ |
P5^ |
Dispose (P3)
P1^ |
P2^ |
Release(P)
Следует учесть, что вызов Release уничтожает список свободных фрагментов в куче, созданных до этого процедурой Dispose поэтому совместное использование Dispose и Release в одной программе не рекомендуется.
Для нетипизированных указателей:
GetMem(P,Size) – резервирование памяти
FreeMem(P,Size) –освобождение памяти
P –нетипизированный указатель
Size – размер запрашиваемой или освобождаемой кучи в байтах.
При работе с GetMem и FreeMem требуется осторожность: освобождать нужно ровно столько памяти, сколько было запрошено
Применение нетипизированных указателей открывает широкие возможности для неявного преобразования типов, что не всегда полезно.
Некорректное использование New и Dispose также может привести к ошибкам:
Var
I,J:^Integer;
R:^Real;
Begin
New(I); {I:=HeapOrg; HeapPtr:= HeapOrg +2}
J:=I; {J:=HeapOrg }
J^:=2;
Dispose(I); {HeapPtr:= HeapOrg }
New(R); {R:= HeapOrg; HeapPtr:= HeapOrg }
R^:=Pi;
WriteLn(J^);
End.
Что будет выведено на экран дисплея? На экране появятся символы 8575, так как J^ будет рассматривать только 2 байта внутреннего представления числа Pi и будет интерпретировать их как представление целого числа.
Дата добавления: 2015-04-12; просмотров: 25 | Поможем написать вашу работу | Нарушение авторских прав |