
2.5. Знищення динамічних об’єктів
На рис. 1 та 2 видно, що після того, як виконали оператор:
P := D
об’єкт 5 став недопустимим для програми, але в оперативній пам’яті
залишився. Це так зване “сміття”, яке забиває оперативну пам’ять. Тому такі
об’єкти необхідно знищувати. Для знищення динамічних об’єктів існує
стандартна процедура DISPOSE. Параметром цієї процедури є вказівник на
об’єкт, який необхідно знищити:
DISPOSE (P);
Після виконання цієї команди динамічний об’єкт, на який вказує
вказівник Р, перестає існувати, місце, яке він займав у пам’яті, звільняється, а
значення вказівникової змінної Р стає невизначеним. Процедура DISPOSE
знищує тільки сам об’єкт, але не вказівник на нього.
2.6. Динамічні структури даних. Рядки
Під рядком (або словом) розуміють упорядковану послідовність символів
конкретного алфавіту.
Рядок може бути поданий у вигляді масиву – тобто статичного об’єкта.
Наприклад, слово “АЛГОРИТМ” можна подати у вигляді вектора
ARRAY [1..10] OF CHAR.
119
Під час роботи з рядком найчастіше здійснюються такі три операції:
1) пошук входження заданого символу в рядок;
2) вставка заданого символу у вказане місце рядка;
3) видалення заданого символу із вказаного місця рядка.
Оскільки доступ до кожного елемента рядка, описаного як вектор,
здійснюється через індекс цього елемента, то для процедури вставки необхідно
спочатку розсунути рядок і лише після цього вставити потрібний елемент.
Тобто усі елементи масиву, які розміщені після вставленої літери, необхідно
пронумерувати індексом на одиницю більшим від попереднього.
Аналогічна ситуація з видаленням визначеного елемента. Тому недоліка-
ми векторного подання рядка є:
1. На операцію вставки та видалення витрачається занадто багато часу че-
рез необхідність зсувати частину слова і пошуку маркера кінця рядка.
2. Якщо довжина рядка наперед невідома, то необхідно резервувати пам’ять
із запасом.
Але кожен рядок можна зобразити у вигляді ланцюжка символів, у якому
кожен попередній елемент містить вказівник на наступний.
Іншими словами опис рядка (ланцюжка) містить два поля: в першому –
записані символи ланцюжка (літери А, Л, Г, ...) а у другому – вказівник на
наступний елемент. Опис такого типу:
TYPE
ZV = ↑POINTER;
POINTER = RECORD
ELEM : CHAR;
NEXT : ZV
END;
Кожна ланка запису складається з двох полів: поле ELEM містить
безпосередньо символьні елементи рядка, поле NEXT містить вказівник на
наступний елемент.
При описі типу ZV ми порушили основне правило мови Паскаль: тип
POINTER використовується до того, як описується. Це єдиний випадок, коли
можна використовувати ім’я типу до його опису. Тільки у разі опису вказів-
никових типів допускається використання імені типу до його опису.
Для того, щоб сформувати рядок (рис. 6) або слово, необхідно описати
дві вказівникові змінні:
VSLOV – вказівник на слово,
VLAN – вказівник на ланку (окремий елемент).
А
NIL VSLOV *
а)
б)
А
NIL * VSLOV
VLAN
в)
А
NEXT VSLOV *
VLAN
VLAN↑.NEXT
г)
А
NEXT VSLOV *
VLAN
Л
NIL
VLAN↑.NEXT
А
NEXT VSLOV * Л
NIL
VLAN
д)
Рис. 6. Формування динамічного рядка
Вказівник VSLOV завжди буде вказувати на початок слова. При породженні:
NEW (VSLOV);
у пам’яті машини виділяється місце для розміщення динамічної
структури з двома полями:
VSLOV.ELEM
VSLOV.NEXT
' '
' '
' '
' '
' ' ' '
121
У поле ELEM – запишемо першу літеру слова, у поле NEXT – запишемо
NIL, оскільки вказівник на слово вказує лише на початок слова та з іншими
ланцюгами не зв’язаний (рис. 6, а).
Наступну, другу літеру слова необхідно розмістити у наступній ланці
ланцюга. Але якщо ми породимо знову VSLOV, то це буде вже нове слово і
зв’язку із літерою “А” не буде.
Використати вказівник VSLOV вже не можна, по-перше, цей вказівник
повинен вказувати завжди на початок слова, по-друге, літера “А” у цьому
випадку стане недоступна.
Якщо породити VLAN командою: NEW (VLAN); то втратиться зв’язок з
першою ланкою, де записана літера “А”. Тому для задання вказівника на
біжучу ланку використовується вказівник VLAN та у перший момент він буде
вказувати на першу літеру слова, тобто (рис. 6, б)
VLAN := VSLOV;
Тепер, у разі породження нового динамічного об’єкта:
NEW (VLAN↑.NEXT);
у поле NEXT елемента VLAN запишеться адреса наступного елемента,
тобто елемента, де буде записано другу літеру слова (рис. 6, в).
Записуємо у поле породженого елемента VLAN↑.NEXT значення поля
ELEM літеру “Л”, а у поле NEXT – значення NIL (оскільки невідомо, чи будуть
ще наступні ланки, див. рис. 6, г):
VLAN↑.NEXT↑.ELEM :=SYM;
VLAN↑.NEXT↑.NEXT :=NIL;
Наступний об’єкт, який повинен породжуватися VLAN↑.NEXT↑.NEXT.
Але, щоб не повторювати постійно слово NEXT, доцільно використати оператор:
VLAN := VLAN↑.NEXT;
Тобто перенести вказівник VLAN на наступну ланку (рис. 6, д).
Породження наступної ланки може виконуватися у циклі, де оператор:
VLAN := VLAN↑.NEXT;
аналогічний оператору I :=I +1 для подання рядка за допомогою вектора.
Фрагмент програми мовою Паскаль для формування слова має такий вигляд
(у разі набору з клавіатури символ вертикальної стрілки ↑ позначається ^ ):
PROGRAM DINSTR (INPUT, OUTPUT);
TYPE
ZV = ↑POINTER;__
POINTER = RECORD
ELEM : CHAR;
NEXT : ZV
END;
VAR
VLAN, VSLOV : ZV;
SYM : CHAR;
BEGIN
READ(SYM);
NEW (VSLOV);
VSLOV↑.ELEM := SYM;
VSLOV↑.NEXT := NIL;
VLAN := VSLOV;
WHILE SYM <> ’.’ DO
BEGIN
READ(SYM);
NEW(VLAN↑.NEXT);
VLAN := VLAN↑.NEXT;
VLAN↑.ELEM := SYM;
VLAN↑.NEXT := NIL;
END;
END.