Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь КАТЕГОРИИ: АрхеологияБиология Генетика География Информатика История Логика Маркетинг Математика Менеджмент Механика Педагогика Религия Социология Технологии Физика Философия Финансы Химия Экология ТОП 10 на сайте Приготовление дезинфицирующих растворов различной концентрацииТехника нижней прямой подачи мяча. Франко-прусская война (причины и последствия) Организация работы процедурного кабинета Смысловое и механическое запоминание, их место и роль в усвоении знаний Коммуникативные барьеры и пути их преодоления Обработка изделий медицинского назначения многократного применения Образцы текста публицистического стиля Четыре типа изменения баланса Задачи с ответами для Всероссийской олимпиады по праву Мы поможем в написании ваших работ! ЗНАЕТЕ ЛИ ВЫ?
Влияние общества на человека
Приготовление дезинфицирующих растворов различной концентрации Практические работы по географии для 6 класса Организация работы процедурного кабинета Изменения в неживой природе осенью Уборка процедурного кабинета Сольфеджио. Все правила по сольфеджио Балочные системы. Определение реакций опор и моментов защемления |
Выделение и освобождение динамической памяти
Вся динамическая память в Турбо Паскале рассматривается как сплошной массив байтов, который называется кучей (heap). Физически куча располагается в старших адресах сразу за областью памяти, которую занимает тело программы. Начало кучи хранится в стандартной переменной heaporg, конец – в переменной heapend. Текущую границу незанятой динамической памяти указывает указатель heapptr. Память под любую динамически размещаемую переменную выделяется процедурой new. Параметром обращения к этой процедуре является типизированный указатель. В результате обращения указатель приобретает значение, соответствующее динамическому адресу, начиная с которого можно разместить данные, например:
Var i, j: ^integer; r: ^real;
Begin New(i); … End.
После выполнения этого фрагмента указатель i приобретет значение, которое перед этим имел указатель кучи heapptr, а сам heapptr увеличит свое значение на 2, так как длина внутреннего представления типа integer, с которым связан указатель i, составляет 2 байта (на самом деле это не совсем так: память под любую переменную выделяется порциями, кратными 8 байтам). Оператор
New(r);
вызовет еще раз смещение указателя heapptr, но теперь уже на 6 байт, потому что такова длина внутреннего представления типа real. Аналогичным образом выделяется память и для переменной любого другого типа. После того как указатель приобрел некоторое значение, т.е. стал указывать на конкретный физический байт памяти, по этому адресу можно разместить любое значение соответствующего типа. Для этого сразу за указателем без каких—либо пробелов ставится значок ^, например:
i^:= 2; {В область памяти i помещено значение 2} r^:= 6.5; {В область памяти r помещено значение 6.5}
Таким образом, значение, на которое указывает указатель, т.е. собственно данные, размещенные в куче, обозначаются значком ^, который ставится сразу за указателем. Если за указателем нет значка ^, то имеется в виду адрес, по которому размещены данные. Динамически размещенные данные можно использовать в любом месте программы,где это допустимо для констант и переменных соответствующего типа, например: r^:= sqr(r^) + i^ - 17; Разумеется, совершенно недопустим оператор r:= sqr(r^) + i^ - 17; так какуказателю r нельзя присвоить значение вещественного выражения.Точно так же недопустим оператор
r^:= sqr(r); поскольку значением указателя r является адрес, иего (в отличие от того значения, которое размещено поэтому адресу) нельзя возводить в квадрат, ошибочным будет и такое присваивание: r^: = i; Динамическую память можно не только забирать из кучи, но и возвращать обратно. Для этого используется процедура Dispose. Например, операторы Dispose (r); Dispose (i); вернут в кучу 8 байт, которые ранее были выделены указателям iиr. Процедура Dispose(ptr)не изменяет значения указателя, а лишь возвращает в кучу память, ранее связанную с этим указателем. Однако повторное применение процедуры к свободному указателю приведет к возникновению ошибки периода исполнения. Освободившийся указатель программист может пометить зарезервированным словом nil. Другая возможность состоит в освобождении целого фрагмента кучи. С этой целью перед началом выделения динамической памяти текущее значение указателя heapptr запоминается в переменной—указателе с помощью процедуры Mark. Теперь можно в любой момент освободить фрагмент кучи, начиная от того адреса, который запомнила процедура Mark, и до конца динамической памяти. Для этого используется процедура Release. Например: Var p, pl, p2, p3, p4, p5: ^integer; Begin New (pl); New (p2); Mark (p); New (p3); New (p4); New (p5) Release (p); End. В этом примере процедурой Mark(p)в указатель p было помещено текущее значение heapptr, однако память под переменную не резервировалась. Обращение Release(p)освободило динамическую память от помеченного места до конца кучи. Как уже отмечалось, параметром процедуры Newможет быть только типизированный указатель. Для работы с нетипизированными указателями используются процедуры: GetMem (p, size) – резервирование памяти; FreeMem (p, size) – освобождение памяти. Здесь р — нетипизированный указатель; size — размер в байтах требуемой или освобождаемой части кучи. За одно обращение к куче процедурой GetMemможно зарезервировать до 65521 байта динамической памяти. Использование процедур GetMem и FreeMem, как и вообще вся работа с динамической памятью, требует особой осторожности и тщательного соблюдения простого правила: освобождать нужно ровно столько памяти, сколько ее было зарезервировано, и именно с того адреса, с которого она была зарезервирована.
Примеры использования указателей Пример: создать в динамической памяти массив из переменных вещественного типа размерностью 100 * 200. Для решения данной задачи воспользуемся следующими функциями: Seg(x) – возвращает сегментную часть адреса; Ofs(x) – возвращает смещение. (Тип обоих функций – word). Аргументом x при обращении к этим функциям может служить любая переменная, в том числе и та, на которую указывает указатель. С помощью встроенной функции
Ptr (seg, ofs: word): pointer
можно создать значение указателя совместимое с указателями любого типа. Для рассматриваемого примера удобно резервировать фрагменты такой длины, чтобы в них могли, например, разместиться строки прямоугольной матрицы, т.е. 200 * 6 = 1200 байт. Начало каждого фрагмента, т.е. фактически начало размещения в памяти каждой строки, запоминается в массиве PtrStr, состоящем из 100 указателей. Теперь для доступа к любому элементу строки нужно вычислить смещение этого элемента от начала строки и сформировать соответствующий указатель:
Var i, j: integer; PtrStr: array [1..100] of pointer; pr: ^real; Const SizeOfReal = 6;
Begin for i:= 1 to 100 do GetMem (PtrStr[i], SizeOfReal * 200); … {Обращение к элементу матрицы [i,j]} pr:= Ptr(Seg (PtrStr[i]^), Ofs (PtrStr[i]^) + (j – 1) * SizeOfReal); … End.
Пример: создать в памяти матрицу размерностью N * M, заполнить ее случайными числами и вычислить среднее значение.
const SizeOfReal = 6; {Длина переменной типа REAL} N = 100; {Количество столбцов} М = 200; {Количество строк}
var i, j: integer; PtrStr: array [1..N] of pointer; s: real;
type RealPoint = ^real;
function AddrR (i, j: word): RealPoint; {Функция по сегменту i и смещению j выдает адрес вещественной переменной} begin AddrR:= Ptr (Seg (PtrStr[i]^), Ofs (PtrStr[i]^)+(j –1)* SizeOfReal); end;
function GetR (i, j: integer): real; {Функция в ыдает значение вещественной переменной по сегменту i смещению j ее адреса} be gin GetR:= AddrR (i, j)^; end;
procedure PutR (i, j: integer; x: real); {Процедура п омещает в переменную, адрес которой имеет сегмент i смещение j, вещественное значение х} be gin AddrR (i, j)^:= x; en d;
{Основная программа} begin for i:=1 to N do begin GetMem (PtrStr[i], M * SizeOfReal); for j:= 1 to M do PutR (i, j, Random) end; s:= 0; for i:= 1 to N do for j:= 1 to M do s:= s + GetR(i,j); WriteLn (s / (N * M): 12:10) end.
|
||||||
Последнее изменение этой страницы: 2017-02-05; просмотров: 403; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.17.150.163 (0.019 с.) |