Программирование на языке Object Pascal
Методическое пособие - Компьютеры, программирование
Другие методички по предмету Компьютеры, программирование
?зм динамической памяти. Динамической считается все оперативная память за вычетом сегмента данных, сегмента стека и сегмента с кодом программы. Память называется динамической, т.к. она выделяется непосредственно в процессе работы программы. Память, расположенная в сегменте данных - статическая и выделяется на этапе компиляции программы.
Динамическая память основана на работе с адресами. При динамическом выделении памяти, заранее не известно: не тип, не количество размещаемых данных. В динамической памяти нельзя обращаться по именам, а только по адресам.
Адреса и указатели
Операционная память представляет собой совокупность элементарных ячеек для хранения информации. Каждая ячейка может хранить один байт информации и обладает уникальным номером, который называется адресом.
Указатель - переменная, которая в качестве своего значения содержит адрес байта памяти:
p: pointer;[@]
В ПЭВМ адреса задаются совокупностью двух шестнадцатеричных слов:
. первое слово - сегмент;
. второе слово - смещение.
Структура адреса ячейки на примере 20-и разрядной адресации:
Объявление указателей
Существует два типа указателей:
1.типизированные (связываются с некоторым типом данных);
2.не типизированные (просто хранят адрес определенного участка памяти). Указатели объявляются в разделе описания переменных и в разделе описания типов (Type и Var).
Объявление типизированных указателей.
имя: ^название типа;
Var: ^integer;: ^real;
...=^PersonRecord;=Record;: string [20];: byte;: PersonPeinter;;
В OPascal любой идентификатор или тип, перед его использованием должен быть предварительно объявлен (исключение сделано только для указателей, которые могут ссылаться на еще не объявленный тип данных). Это связано с тем, что динамическая память дает возможность организовывать данные в виде списка.
Объявление не типизированных указателей.
имя: painter;
Var: painter;,p2: ^byte;[1 байт]3,p4: ^real;[8 байт]
Типизированные и не типизированные указатели хранят значение адресов, однако, значение одного указателя не всегда можно передавать другому. В OPascal передавать значение можно только между указателями, которые связаны с одним и тем же типом данных, исключение составляют не типизированные указатели, которые совместимы со всеми типами данных.
Var: painter;,p2: ^byte;,p4: ^real;
...:=p2;:=p4;1:=p3;
p4:=p2;
p1:=p1;
p3:=p;
Обнуление указателя
p:=Nil; - после выполнения этой операции указатель продолжает занимать место в памяти, но указывает в никуда (т.е. ни на одну ячейку).
p:=Nil;
Выделение и высвобождение динамической памяти
Вся динамическая память в OPascal рассматривается как сплошной массив байт, который называется куча (HEAP). Физически она располагается в старших адресах памяти сразу за областью, которую занимает код программы.
При работе с кучей используются стандартные, объявленные по умолчанию переменные:
1.HeapOrg - хранит адрес начала кучи;
2.HeapEnd - хранит адрес конца кучи;
3.HeapPTR - хранит адрес начала незанятого участка кучи.
Выделение в памяти для типизированных указателей осуществляется с помощью процедуры New (имя указателя):
Var
p: ^byte;
New(p);
p^:=2;
1.Администратор кучи просматривает ее содержимое и если есть свободный байт - выделяет его, а адрес этого байта записывается в переменную (p).
2.Запись числа (2) в свободное место с адресом (p).
p^ - разадресация указателя, т.е. обращение к значению хранящемуся по адресу, который лежит в (p).
Процедура New выделяет динамическую память для требуемого указателя и только после этого указатель можно использовать. Указатели можно использовать только в операциях соответствующего типа, т.е. в операциях с адресами.
Разадресованные указатели могут использоваться в любых выражениях и операциях:
Var:^byte;:real;(p);^:=2;:=SQRT(p^)+2*p^/3
Высвобождение динамической памяти.
После использования динамических переменных, память занятую ими необходимо высвободить, для этого используется процедура dispose(имя указателя):
Dispose(p);
После процедуры dispose указателю снова можно выделить память.
После процедуры dispose значение переменной высвобождается, а указателю присваивается значение Nil.
При работе с указателями ответственность за высвобождение памяти ложится на программиста, т.к. Pascal при завершении работы приложения, самостоятельно занятую память не высвобождает, это может привести к утеске динамической памяти.
Для не типизированных указателей выделение памяти осуществляется процедурой: GetMem (имя указателя, размер). Размер - количество байт, которые будут помечены как занятые. Он может быть от 1 до 65535 байт.
Высвобождение памяти для не типизированных указателей:
FreeMem (имя указателя, размер);
Пример:
Var: pointer;
…(p,400);
…
FreeMem (p,400);
…
Процедуры для высвобождения динамической памяти:
Mark (p) - запоминает адрес указателя (p);
Release (p) - высвобождает динамическую память начиная от адреса хранящегося в (p) до конца кучи.
Эти процедуры могут применяться к типизированным и не типизированным указателям.
Пример:
, p2, p3, p4, p5: ^integer;(p1);(p2);(p3);(p4);(p5);
…
Процедуры и функции для работы с динамической памятью:
Addr(x): pointer; - функция возвращает результат типа pointer в котором содержится адрес аргумента (x