Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Динамическая память.docx
Скачиваний:
30
Добавлен:
18.03.2015
Размер:
189.06 Кб
Скачать

Страница 26 из 55Динамика, динамические структуры

  1. Динамическая память.

Ранее использовались переменные, память под которые выделялась статически, то есть на стадии компиляции. Эти области памяти (для переменных из раздела VARданного блока) существуют до конца работы блока, даже если эти переменные уже не нужны. При этом память нередко используется неэффективно, достаточно вспомнить «настройку» массива на фактическое количество элементов, а также, если, например, объявлено несколько массивов большого объема статической памяти, а в каждый конкретный момент используются не все.

Исправить положение можно, применив специальный механизм распределения памяти. Паскаль предоставляет возможность выделять и освобождать память в процессе выполнения программы, динамически.

Можно отметить следующие достоинства динамической памяти:

- экономичность и эффективность ее использования;

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

- статические переменные существуют только в течение жизни блока, в котором они объявлены, а динамические - и после выхода из блока до окончания программы. Переменная, размещаемая динамически, не объявляется в разделе VARи не имеет имени в программе («невидимка»). Компилятор не планирует выделение места в памяти под такие переменные.

Все переменные, объявленные в программе, размещаются в одной непрерывной области оперативной памяти, которая называется сегментом данных. Длина сегмента данных определяется архитектурой микропроцессоров 80х86 и составляет 65536 байт, что может вызвать известные затруднения при обработке больших массивов данных. С другой стороны, объем памяти ПК (обычно не менее 640 Кбайт) достаточен для успешного решения задач с большой размерностью данных. Выходом из положения может служить использование так называемой динамической памяти.

Динамическая память- это оперативная память ПК, предоставляемая программе при ее работе, за вычетом сегмента данных (64 Кбайт), стека (обычно 16 Кбайт) и собственно тела программы. Размер динамической памяти можно варьировать в широких пределах. По умолчанию этот размер определяется всей доступной памятью ПК и, как правило, составляет не менее 200...300 Кбайт.

Динамическая память -- это фактически единственная возможность обработки массивов данных большой размерности. Многие практические задачи трудно или невозможно решить без использования динамической памяти. Динамическое размещение данных означает использование динамической памяти непосредственно при работе программы. В отличие от этого статическое размещение осуществляется компилятором Паскаля в процессе компиляции программы. При динамическом размещении заранее не известны ни тип, ни количество размещаемых данных, к ним нельзя обращаться по именам, как к статическим переменным.

    1. Указатель.

Обращение к участку динамической памяти в программе осуществляется с помощью специальной ссылочной переменной, которая называется указателем (ссылкой).

Переменная типа «указатель» содержит адрес размещения участка динамической памяти, с которой связан этот указатель. Компилятор отводит под переменную типа «указатель» четыре байта статической памяти. Обычно указатель, связанный с определенным типом данных, называется типизированным. Однако он может быть и не типизированным, то есть совместимым с указателями любого типа данных. В этом случае указатель называется свободным (несвязанным).

Для работы с динамическими переменными в программе должны быть выполнены следующие действия:

  • Выделение памяти под динамическую переменную;

  • Инициализация указателя;

  • Освобождение памяти после использования динамической переменной.

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

Формат описания типа «указатель» следующий:

Type <идентификатор указателя>=^<тип>;

Примеры объявления типов «указатель» и переменных типа «указатель».

Type

{ правильные объявления типов}

//идентификатор типа «указатель» на данные типа word

p1=^word;

//идентификатор типа «указатель» на данные типа char

p2=^char;

//идентификатор типа «указатель» на массив //указателей, ссылающихся на данные типа real

p4=array[1..10] of ^real;

{ неправильные объявления типов}

p5=^array[1..10] of real;

p6=^string[25];

p7=^record

field1 : string [15];

field2 : real;

end;

В формате объявления типа «указатель» должен быть указан идентификатор типа, поэтому стандартные идентификаторы (integer, realи т.д.) можно указывать непосредственно в описаниях типа «указатель». Ошибки в описаниях типовp5, p6иp7будут отмечены компилятором из-за того, что, в таких случаях надо прежде описать идентификатор типа, а затем использовать его в других описаниях.

Следующие описания будут правильными:

type

...

TMas = array[1..10] of real;

TSt = string[25];

Trec = record

field1 : string [15];

field2 : real;

end;

var

p5 : ^Tmas;

p6 : ^Tst;

p7 : ^Trec;

...

Особое место отводится типу pointer – не типизированный указатель. Данный тип обеспечивает общее использование указателя на любую основанную на памяти переменную. То есть тот, к которому доступен для ссылки. Например, добавим к вышеописанным переменным, переменную

p8: pointer;

тогда можно в теле программы производить следующие операции:

p8:=p7;

p7:=p8;

действие p7:=p6; приведет к ошибке!

в свою очередь, не смотря на то что действие

p8:=p6;

p7:=p8;

не приведет к ошибке компилятора, но данные на которые будет ссылаться p7– будут не верными.

Указатель может находиться в одном из трех состояний, а именно:

  1. еще не инициализирован;

  2. содержит адрес размещения;

  3. содержит значение предопределенной константы nil; такой указатель называется пустым, то есть не указывает ни на какую переменную. Указатель со значениемnil содержит 0 в каждом из четырех байтов.

Указатели можно сравнивать с другими указателями ( =, <> ), присваивать им адрес или значение другого указателя, передавать как параметр. Указатель нельзя отпечатать или вывести на экран.

Обращение к выделенной динамической памяти кодируется следующим образом:

<идентификатор указателя>^

Рассмотрим пример обращения к переменным, размещенным в динамической памяти:

type

Tsym=^char;

Tzap=record

field1, field2: real;

end;

Tm=array[0..9] of word;

var

ch : Tsym;

rec : ^Tzap;

mas : ^Tm;

...

//обращение к динамической переменной типа char,

//запись в эту область символа звездочка

ch^:='*';

...

//обращение к полю field1 динамической записи, ввод

//в него данных с клавиатуры

readln (rec^.field1);

...

//обращение к элементу mas[5] динамического

//массива, вывод на экран значения указанного

//элемента

writeln ( mas[5]^);

...

Фактически можно говорить, что ch^, rec^.field1 и mas[5]^исполняют роль имён динамических объектов в программе, адреса которых хранятся в указателяхсh, rec и masсоответственно.

Следует отметить, что обращение к переменным типа pointer(указателям, которые не указывают ни на какой определенный тип и совместимы со всеми другими типами указателей) приводит к ошибке.

Например.

var

p:pointer;

...

p^:=1; {ошибка!}