Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Delphi, Pascal.docx
Скачиваний:
8
Добавлен:
26.04.2019
Размер:
566.19 Кб
Скачать

16. Понятия статического и динамического распределения памяти. Что такое указатель? Операции над указателями. Что такое динамическая переменная? Наложение переменных с помощью указателя.

В наиболее структурированных языках, подобных C и C++, "Дельфи" программист может использовать два вида памяти: статический и динамический.

Статическое распределение памяти – это распределение памяти в процессе компиляции программы, т. е. до начала ее выполнения. Основные типы данных, называемые также типами значений, являются статическими, и их требуемые объемы и конфигурации памяти известны и устанавливаются во время компиляции. Целые числа "Дельфи", перечислительные типы, записи и статические множества — примеры статических переменных. В языке C все типы данных являются статическими.

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

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

Type

Pukaz=^<тип переменной>;

Pint = ^integer;

TMas = array[1..4] of integer

PMas = ^TMas;

Var

Uk : Pukaz;

a, b : PInt; // Типизированные указатели

p, q : pointer; // Нетипизируемые указатели

U : Pmas; // Указатель на одномерный массив

C : array[1..2,1..2] of integer; // Обычный двумерный массив

begin

...

U:=Addr(C); // Указателю U присваивается

// адрес статической переменной C

a:=p; // Адрес указателя p комируется в указатель a

p:=Nil; // Очистка адреса

...

Каждая переменная типа указатель (a, b, p, q, u) занимает 4 байта памяти, и сожержит адрес первого байта некоторого участка оперативной памяти, данные на котором интерпретируются в соответствии с объявленным типом. С помощью указателя (адреса) реализуется доступ к данным, расположенным в ячейке с этим адресом, например u^[2]:=3. Более того, появляется возможность интерпретации данных разного пипа, например одномерного массива, как двумерного.

Организация динамического распределения памяти:

Для получения памяти программе необходимо выполнить запрос к операционной системе. По этому запросу ОС выделяет память в свободной от загруженных программ (в динамической области) оперативной памяти компьютера, называемой кучей (heap) и возвращает программе начальный адрес выделенного участка оперативной памяти. Доступ к данным, значения которых расположены в выделенной динамической области памяти, требует использования в программе переменной, значением которой и будет возвращаемый ОС адрес. Такая переменная имеет специальный, ссылочный тип данных –указатель.

Для выделения памяти в динамической области оперативной памяти компа, наз-ой кучей используются процедуры New, Dispose или GetMem, Free-Mem.

Процедура: New(var P: Pointer), выделяет участок памяти, размер которого определяется типом указателя P. Указателю P присваивается адрес первого байта этого участка. После того как необходимость работы с этой переменной отпала, данный участок памяти освобождается с помощью процедуры Dispose(var P: Pointer); После освобождения адрес в указателе P остается, однако доступ к ячейке с этим адресом запрещен. Например:

Var a, b : PInt;

begin

New(a);

b:=a;

a^:=9;

b^:=5

Write(a); …

Dispose(b);

Здесь выделена память под переменную типа integer. Указать b стал указывать на ту же область памяти, что и указатель a . В выделенную область сначала занесено значение, равное 9, затем туда же значение равное 5. Для освобождения памяти можно использовать как Dispose(b) так и Dispose(a).

Процедура GetMem используется при работе как с типизированными, так и с нетипизированными указателями, поэтому задается не только имя указателя, но и объем необходимой памяти в байтах:

GetMem(P:pointer;size:Word);

Процедура

FreeMem(P:pointer;size:Word);

освобождает область памяти, связанную с указателем Р, и имеющую размер, равный size.

Для определения размера, который требуется выделить под переменную обычно пользуются функцией sizeof(<имя типа>).

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

Языки программирования, в которых предусмотрен тип указателей, содержат, как правило, две основные операции над ними: присваивание и разыменование. Операция присваивания- присваивает указателю некоторый адрес. Операция разыменования -служит для обращения к значению в памяти, на которое указывает указатель. Разыменование может быть явным и неявным, в большинстве современных языков программирования разыменование происходит только при явном указании.

В случае если указатель хранит адрес какого-либо объекта, то говорят, что указатель ссылается или указывает на этот объект p. Языки, предусматривающие использование указателей для управления динамической памятью, должны содержать оператор явного размещения переменных в памяти. В некоторых языках помимо этого оператора предусмотрен ещё и оператор явного удаления переменных из памяти. Обе эти операции часто принимают форму встроенных подпрограмм.

Динамическая переменная- переменная в программе, место в оперативной памяти под которую выделяется во время выполнения программы. По сути, она является даже не переменной, а участком памяти, выделенным системой программе для конкретных целей. Динамическая переменная — один из классов памяти переменной.

Так как динамическая переменная создаётся во время выполнения программы, у неё нет собственного идентификатора. Работа с динамической переменной ведётся косвенно, через указатель. Создание такой переменной заключается в выделении участка памяти с помощью специальной функции. Эта функция возвращает адрес в памяти, который назначается указателю. Процесс доступа к памяти через указатель называется разыменованием. После окончания работы с динамической переменной выделенную под неё память необходимо освободить — для этого тоже есть специальная функция.

Наложение переменных: использование указателей позволяет «накладывать» переменные разных типов друг на друга, интерпретируя по разному данные, расположенные по некоторому адресу. Например:

Var s:String[200];

Ch:Char;

k,I:^byte;

begin

I:=Addr(ch); k:=Addr(s);

Ch:=’A’; s:=’Lena’;

Write(sh,I^:4,’ N=’,k^); .....

Будет выведен сам символ ’А’ и его номер в кодовой таблице 160, а также N=4 - текущая длина строки s.

Следующий пример иллюстрирует наложение одномерного массива на двухмерный:

Var a:^array[1..4] of integer;

b:array[1..2,1..2] of integer;

begin

a:=Addr(b);

for i=1 to 4 do a^[i]:=4-i;

Write(’b12=’,b[1,2]);// будет выведенo b12=1 ......

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