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

Вопрос21

Распределение памяти и указатели

Динамические переменные и память

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

большинстве языков программирования имеется возможность создавать и удалять переменные во время выполнения программы. Такие переменные

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

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

кучей (heap). Работать с переменными в куче можно только через указатели. Указатели – это особый тип данных (pointer) для хранения адресов ячеек памяти, в которых находятся другие переменные. Адресом переменной является адрес первого байта ячейки памяти, которая под нее отводится. Для данных структурных типов (массивов и записей) их адресом считается адрес первого байта первого элемента.

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

Нетипизированный указатель – адрес первого байта области памяти, в которой может размещаться любая информация вне зависимости от ее типа.

Примеры объявления указателей:

var

p1,p2: ^integer; {указатели на переменные целого

типа}

p3: ^string; {указатель на строку}

p: pointer; {нетипизированный указатель}

Тип pointer

совместим со всеми типами указателей.

Время жизни динамической переменной начинается от момента выделения ей памяти и заканчивается в момент освобождения выделенной памяти. Этим

процессом управляет программист, указывая в коде программы следующие команды.

Для типизированных указателей:

new(p);

Выделение памяти.

Указателю p

присваивается адрес первого байта выделенной памяти.

dispose(p);

Освобождение памяти.

Освобождается выделенная память, на которую

указывает p.

Для нетипизированных указателей:

getmem(p,size);

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

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

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

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

знаком ^.

Для указателей, которые не хранят ни каких адресов, введена константа пустой (нулевой) адрес с именем nil.

В неопределенном состоянии указатель находится в начале работы программы до первого присваивания ему конкретного адреса или пустого адреса

nil, а также после освобождения области памяти, на которую он указывает.

Операции с указателями

Примеры допустимых операций:

Указателю допускается присвоить значения только

того же типа или типа pointer, а также значение nil.

var x,y:integer;

...

px:^integer;

px:=@x;

Получение адреса ( @□)

Результат унарной операции

@– указатель типа

pointer, который можно присвоить любому

указателю.

...

y:=px^; {y=x}

p1^:=5; p2^:=2;

x:=p1^+3*p2^+4; {x=15}

^– доступ к переменной,

на которую ссылается указатель. Нетипизированные указатели разыменовывать нельзя.

var b:boolean;

...

b:=p1<>p2;

if p1=nil then ...

Проверка равенства = и неравенства

<> адресов.

Результат логического типа (true, false).

Действия с указателями

Разберем пример простейших действий с указателями:

type

pint=^integer; {описание типа указателя}

var

p1,p2: pint; {описание указателей}

begin

new(p1); {выделение 1-й ячейки памяти по указателюp1}

new(p2); {выделение 2-й ячейки памяти по указателю p2}

p1^:=10; {занесение данных в 1-ю ячейку}

p2^:=20; {занесение данных во 2-ю ячейку}

p1^:=p2^; { копирование данных из 2-й ячейки в 1}

dispose(p1); {освобождение 1-й ячейки памяти}

p1:=p2; {копирование адреса 2-й ячейки в указатель p1}

{Теперь оба указателя ссылаются на 2-ю ячейку.}

p1^:=p1^+p2^+5; {изменение данных во 2-й ячейке: 20+20+5=45}

p2:=nil; {обнуление указателя p2 (nil – пустой адрес)}

dispose(p1); {освобождение 2-й ячейки памяти}

p1:=nil; {обнуление указателя p1 (nil - пустой

адрес)}

...

end.

Выделение и освобождение памяти

Необходимо помнить, что выделенная память, ссылка на которую утеряна, недоступна и не сможет быть освобождена во время выполнения

программы.

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

может заполнить всю динамически распределяемую память. После освобождения памяти (dispose(p)) указатель p находится в неопределенном состоянии, т.е. p ссылается на неиспользуемую ячейку.

Поэтому сразу после команды dispose(p)

принято обнулять (или переопределять) указатель p.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]