Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
1 Программирование на Паскаль.doc
Скачиваний:
18
Добавлен:
26.04.2019
Размер:
1.18 Mб
Скачать

Динамическое выделение памяти Типизированные указатели

Для выделения памяти служит стандартная процедура new():

new(<имя_указателя>);

Эта процедура ищет в незанятой памяти подходящий по размеру кусок и, "застолбив" это место для безымянной динамической переменной, записывает в типизированный указатель адрес выделенного участка. Поэтому часто говорят, что процедура new() создает динамическую переменную. Размер выделяемого "куска памяти" напрямую зависит от типа указателя.

Например, если переменная p была описана как указатель на integer-переменную, то процедура new(p) выделит два байта; под real-переменную необходимо выделить четыре байта и т.д.

Нетипизированные указатели

Для того чтобы выделить память, на которую будет указывать нетипизрованный указатель pointer, нужно воспользоваться стандартной процедурой getmem(p: pointer; size: word), которая выделит столько байт свободной памяти, сколько указано в переменной size.

Динамическое освобождение памяти Типизированные указатели

Для уничтожения динамической переменной, то есть для освобождения занимаемой ею памяти, предназначена стандартная процедура

dispose(<имя_типизир_указателя>).

Процедура dispose() снимает пометку "занято" с определенного количества байтов, начиная с указанного адреса. Эта область памяти в дальнейшем считается свободной (хотя старое значение бывшей переменной в ней может некоторое время еще оставаться). Количество освобождаемых байтов определяется типом указателя p.

В результате освобождения памяти при помощи процедуры dispose() значение указателя, хранившего адрес освобожденной области, становится неопределенным. Во избежание проблем его лучше сразу же "обнулить":

dispose(p);

p:= nil;

Нетипизированные указатели

Для того чтобы освободить память, на которую указывает нетипизрованный указатель, нужно воспользоваться стандартной процедурой freemem(p: pointer; size: word), которая освободит в памяти столько байтов (начиная с указанного в переменной p адреса), сколько задано в переменной size.

Списочные структуры

Если для каждой динамической переменной описывать и хранить ее "личный" указатель, то никакой выгоды на этапе выполнения программы получить не удастся: часть памяти, как и прежде, будет выделяться статически, а ее общий объем даже увеличится - ведь каждый указатель требует для себя четыре байта.

Следовательно, нужно сделать так, чтобы место под хранение адресов будущих переменных также выделялось динамически. Решением этой проблемы и служат списки - специальные динамические структуры.

Списки применяются, например, в таких ситуациях:

  • программист заранее ничего не знает о том, какой именно объем памяти может потребоваться его программе;

  • некоторые (особенно "тяжелые") переменные нужны поочередно, и после того как первые "отработали свое", их можно смело стирать из памяти, не дожидаясь конца работы программы, - освобождать место для других "тяжелых" переменных;

  • в процессе обработки данных нужно провести большую работу по перестройке всей структуры "на ходу"; и т.д.

Структура списков

Итак, каждый элемент создаваемого списка должен содержать:

  1. полезную информацию, которая может иметь любой формат: integer, real, array, record и т.п.;

  2. специально выделенное поле (и, может быть, не одно), которое хранит адрес другого элемента этой же структуры.

Приведем примеры различных списочных структур:

  • a) Односвязный (линейный) список: структура, каждый элемент которой "знает" адрес только следующего за ним элемента (см. рис. 10.1 (a)). Очень удобно представлять таким списком стек и очередь (см. лекцию 9).

  • b) Двусвязный линейный список: структура, каждый элемент которой "помнит" адрес не только следующего, но и предыдущего элемента списка (см. рис. 10.1 (b)). Этот список удобен для работы с деками (см. лекцию 9)

  • c) Бинарное дерево (см. лекцию 11) может быть представлено двусвязным нелинейным списком: каждая вершина помнит обоих своих возможных потомков (см. рис. 10.1 (c)). Если каждой вершине необходимо помнить не только потомков, но и предка, то список становится трехсвязным.

  • d) Для представления ориентированного графа (см. лекцию 11) можно использовать иерархические списки - комбинацию из двух различных линейных списков (см. рис. 10.1 (d): вершины задаются структурой, содержащей три поля, а дуги - два; справа показан орграф, представленный приведенной списочной структурой).