- •Динамічний розподіл пам’яті Статичні і динамічні змінні
- •Покажчики Поняття покажчика
- •Розподіл динамічної пам’яті Породження динамічних об'єктів
- •Доступ до динамічних об'єктів
- •Обробка динамічних об'єктів
- •Знищення динамічних об'єктів
- •Методи динамічного розподілу пам’яті
- •Стандартні засоби аналізу стану Heap-області
- •Динамічний розподіл пам’яті
- •Динамічні структури даних
Покажчики Поняття покажчика
Використання динамічних об'єктів спричиняє певні труднощі, які полягають, зокрема, у тому, що виникають об'єкти динамічно, у процесі виконання програми, а дії над ними необхідно задавати статично при написанні програми. Окрім того, за замовчуванням, пошук усіх даних здійснюється тільки в сегменті даних.
У мовах програмування зазначена проблема вирішується шляхом використання спеціального посилального типу даних. Посилальний тип - це особливий статичний тип даних, значенням якого є не конкретне дане (число, символ, рядок і т.ін.), а покажчик на який-небудь програмний об'єкт, по якому здійснюється безпосередній доступ до цього об'єкту.
Для опису дій над динамічними об'єктами кожному такому об'єкту в програмі ставиться у відповідність свій статичний покажчик посилального типу у термінах якого і описуються дії над відповідними динамічними змінними. Сам же динамічний об'єкт при необхідності створюється пізніше, під час виконання програми.
Зв'язок покажчика з об'єктом схематично можна представити таким чином:
покажчик динамічний об'єкт (числовий масив)
адреса 56 678 34 78 ...
Таким чином, адресація динамічних змінних відбувається через покажчики.
Розрізняють два види покажчиків: типізовані і нетипізовані (безтипові).
Типізовані покажчики - це покажчик на змінні певного (базового) типу. Їх оголошення різниться у різних мовах програмування. БНФ-нотація оголошення відповідного посилального типу (покажчика) для мови Pascal має вид:
<посилальний тип> ::= ^ <базовий тип>;
Тут знак “^” варто читати як “посилання на ...”.
Значеннями змінних визначеного таким чином посилального типу можуть бути покажчики на динамічні об'єкти, причому лише базового типу. Змінні посилального типу вводяться у вживання аналогічно будь-яким статичним змінним. Наприклад,
type рtr = ^mas;
mas = array[1..10] of real;
var w : ^word; {покажчик на динамічну величину цілого типу}
s : ^string [25]; {покажчик на динамічний рядок }
m : рtr; {покажчик на динамічний масив, тип якого заданий у розділі Type }
При оголошенні посилального типу може використовуватися ідентифікатор типу, що визначається в описовій частині пізніше (mas).
Безтипові покажчики – це покажчики на область пам'яті, в якій може розміщуватися будь-яка інформація, незалежно від її типу.
Розрізняють стандартні безтипові покажчики (HeapPtr, HeapEnd, SPtr, тощо) і безтипові покажчики користувача, що описуються стандартним типом pointer, який вважається сумісним із усіма посилальними типами. Наприклад,
var p : pointer; {нетипізований покажчик}
Розглянемо приклад. Нехай у програмі описані наступні покажчики:
var p,w :^word;
Прослідкуємо зміни їх значень і значень відповідних змінних з покажчиками в результаті послідовного виконання наступних операторів присвоєння :
p^:= 3;
w^:= 58;
p := w;
w = nil;
Для наочності отримані при цьому результати представимо у вигляді схеми (рис. 1).
Рис. 1. Зміна значень покажчиків
Слід звернути увагу, що в даному прикладі після виконання оператора присвоєння р:= w на динамічний об'єкт із значенням 3 не вказує жоден покажчик, тобто він став недоступним для програми. З іншого боку, в результаті виконання цього ж оператора присвоєння не утворюється новий динамічний об'єкт із значенням 58, а покажчик р посилатиметься на вже існуючий динамічний об'єкт, на який посилається і покажчик w.
Важливо чітко розуміти різницю між покажчиком, тобто значенням посилальної змінної, і значенням динамічного об'єкту, тобто значенням відповідної змінної з покажчиком. Якщо замість оператора р:= w у попередньому прикладі виконати оператор р^:= w^, то отримаємо наступний результат:
Оскільки безтипові покажчики користувача (pointer) вважаються сумісним із усіма посилальними типами, то вони також можуть використовуватися у операторах присвоєння. Наприклад, оголошення
var p1 : ^ integer; {покажчик на змінну цілого типу}
p2 : ^ real; {покажчик на дійсне число}
p3 : pointer; {нетипізований покажчик}
допускають присвоєння виду:
p3 := p1; або p3 := p2; , але не p1 := p2.