тобто порожній вказівник (за аналогією з порожньою множиною). Щоб одержати таке значення вказівника, треба виконати присвоєння
m:=nil;
Результат виконання цієї операції зображений на рис. 2.
Рис. . Порожній вказівник
1.2. Створення динамічних об'єктів
Далі розглянемо, як уводять динамічні об'єкти. Введення змінної вказівного типу не означає вказівки на якийсь об'єкт, ця змінна не містить навіть значення порожнього вказівника nil. Опис змінної вказівного типу вводить тільки деяку статичну змінну, що може містити вказівку на об'єкт. Самий же динамічний об'єкт він не визначає.
Для створення динамічного об'єкта, пов'язаного з деякою змінною вказівного типу, використовують стандартну процедуру new. Фактичним параметром цієї процедури може бути тільки змінна вказівного типу. У результаті виконання оператора процедури new(m) під час виконання програми буде введено новий динамічний об'єкт, тип якого зазначений в описі змінної вказівного типу, що є фактичним параметром процедури new. Крім цього, змінній вказівного типу (у нашому випадку m) буде присвоєна вказівка на цей уведений динамічний об'єкт. На машинному рівні механізм виконання оператора процедури new(p) полягає в тому, що в пам'яті комп'ютера відводиться місце для розміщення нового динамічного об'єкта, а відповідній змінній вказівного типу буде присвоєна адреса початку цього місця. У нашому випадку new(m) вводить масив десяти символів, а змінній т присвоюється значення, що є вказівкою на цей масив. Зазначимо, що введений об'єкт (у нашому випадку масив) не набуває жодного значення, дія процедури new(m) щодо цього динамічного об'єкта відіграє ту ж роль, що й опис для статичного об'єкта.
У мові Турбо Паскаль можна використовувати процедуру new у функціональній формі. Тоді параметр функції new (тепер це функція) задає вказівний тип, а результатом буде вказівник (значення вказівної змінної) цього типу, що визначає створений унаслідок цього динамічний об'єкт. Наприклад, аналогом оператора процедури new(m) буде оператор
m:=new(mas);
Раніше зазначено, що під час розподілу пам'яті під локальні змінні відводиться спеціальний сегмент оперативної пам'яті (сегмент стека). Для динамічних об'єктів вводиться інша область пам'яті, що є окремо від стекового сегмента і називається купою (heap), або динамічною областю пам'яті.
Для того, щоб присвоювати значення динамічним об'єктам, треба спочатку з'ясувати механізм доступу до цих об'єктів мовою Паскаль. Для звертання до динамічного об'єкта використовують поняття змінної з вказівником. Змінна з вказівником – це змінна вказівного типу, після якої стоїть стрілка.
Нехай у програмі описана деяка змінна q:
var
q: ^integer;
Тоді оператор процедури new(q);
приведе до створення деякої змінної цілого типу, на яку вказуватиме вказівник q. Якщо ж тепер виконати присвоєння
q^:=12;
то введеній динамічній змінній буде присвоєне значення 12. Ще раз зазначимо, що динамічним змінним у програмі не відведені жодні імена, а доступ до них відбувається за допомогою змінних з вказівниками.
Наведемо ще приклади операцій з динамічними змінними. Нехай S – змінна цілого типу. Тоді, використовуючи опис змінної q і процедуру new, можна записати
S:=S-q^*4;
S:=q^mod2:
Якщо В – деякий масив цілих чисел, то
B[q^-2]:=14
Якщо ж є опис
type vkaz^=char;
var
С: array [1..10] of vkaz;
то він уводить масив С вказівників, кожен елемент якого вказує на якусь змінну символьного типу. Тоді можна записати
С[5]^='і';
C[S-2]^:='n'.
1.3. Операції над змінними вказівного типу
Над змінними вказівного типу не визначені жодні операції, які б приводили до значень цього ж типу. З ними виконують тільки операції присвоєння і порівняння. Оператор присвоєння записують так само, як і для інших типів:
S:=r;
де S – змінна вказівного типу, r може бути змінною цього ж вказівного типу, функцією, тобто значенням якої є вказівник цього ж вказівного типу або порожній вказівник nil. Для введених нами раніше змінних вказівного типу р і q оператор
P:=q;
недопустимий, оскільки ці змінні різного типу: р вказує на змінну дійсного типу, q – цілого.
Щоб відчути різницю між присвоєнням значень вказівникам і об'єктами, на які вони вказують, розглянемо такий приклад (рис. 3):
Рис. . Два динамічні об'єкти
На рис. 3 k та j – вказівні змінні, що вказують на певні об'єкти однакового типу. Після виконання оператора
k:=j;
виникне ситуація, відображена на рис. 4 і об'єкт * стане недоступним, буде втра-че-ний. На його місці можна розмістити інший об'єкт після додаткової операції.
Рис. . Результат перетворення вказівника
Якщо ж виконати оператор k^:=j^, то виникне ситуація, відображена на рис. 5.
Рис. . Результат переприсвоєнь динамічного об'єкта.
Після виконання k:=nil матимемо випадок, показаний на рис. 6.
Рис. . Результат занулення вказівника
Розглянемо ще приклад з числовими об'єктами. Нехай описані вказівні змінні т та l:
var m,l: integer;
і визначені відповідні їм динамічні об'єкти – змінні цілого типу
new(m); new(l);
Присвоєння m^=8; l^=19 приводить до ситуації, показаної на рис. 7.
Рис. . Ініціалізація змінних з вказівниками
Якщо тепер виконати присвоєння m:=l, то одержимо випадок, відображений на рис. 8.
Рис. . Результат переприсвоєння вказівної змінної.
А якщо виконати присвоєння m:^=l^, то це приведе до ситуації з рис. 9.
Рис. . Результат переприсвоєння змінної з вказівником
Особливості використання динамічних змінних порівняно зі статичними такі:
1) замість опису динамічних змінних описують вказівки – статичні змінні вказівного типу, які ставлять у відповідність динамічним змінним;
2) для створення динамічних змінних, що відповідають уведеним вказівним, використовують процедуру new, фактичним параметром якої задають відповідну вказівну змінну.
3) доступ до динамічних змінних відбувається за допомогою змінних з вказівником.
Множина операцій над змінними з вказівником визначена типом цих динамічних змінних.
Як зазначено, динамічні структури використовують з метою економії пам'яті комп'ютера. Однак, з іншого боку, треба пам'ятати про недоліки, пов'язані з використанням динамічних змінних замість статичних, а саме: збільшення тексту програми (додається оператор new), погіршення наочності, зменшення швидкодії (потрібно під час виконання програми розміщувати