Основи Delphi

Одним із найпотужніших засобів мови Delphi є динамічні масиви. Їхня основна відмінність від звичайних масивів полягає в тому, що вони зберігаються в динамічній пам'яті. Цим і зумовлено їхню назву. Щоб зрозуміти, навіщо вони потрібні, розглянемо приклад:

var N: Integer; A: array[1..100] of Integer; // звичайний масив begin Write('Введіть кількість елементів:'); ReadLn(N); . end.

var N: Integer; A: array[1..N] of Integer; // Помилка! begin Write('Введіть кількість елементів: '); ReadLn(N); . end.

На етапі написання програми неможливо передбачити, які саме обсяги даних захоче обробляти користувач. Тим не менш, Вам доведеться відповісти на два важливі питання:

На яку кількість елементів оголосити масив?

Що робити, якщо користувачу таки знадобиться більша кількість елементів? Ви можете зробити так. Як верхня межа масиву встановити максимально можливу (з вашої точки зору) кількість елементів, а реально використовувати лише частину масиву. Якщо користувачеві потрібно більше елементів, ніж зарезервовано Вами, то йому можна просто ввічливо відмовити. Наприклад:

const MaxNumberOfElements = 100; var N: Integer; A: array[1.. MaxNumberOfElements] of Integer; begin Write('Введіть кількість елементів (не більше ', MaxNumberOfElements, '): '); ReadLn(N); if N > MaxNumberOfElements then begin Write('Вибачте, програма не може працювати'); Writeln('з кількістю елементів більше , 'MaxNumberOfElements, '.'); end else begin . // Ініціалізуємо масив необхідними значеннями та обробляємо його end; end.

Таке вирішення проблеми є неоптимальним. ЯкщоКористувачеві потрібно всього 10 елементів, програма працює без проблем, але завжди використовує обсяг пам'яті, необхідний для зберігання 100 елементів. Пам'ять, відведена під решту 90 елементів, не використовуватиметься ні Вашою програмою, ні іншими програмами (за принципом "сам не гам і іншому не дам"). А тепер уявіть, що всі програми роблять так само. Ефективність використання оперативної пам'яті різко знижується.

Динамічні масиви дозволяють вирішити розглянуту проблему якнайкраще. Розмір динамічного масиву можна змінювати під час роботи програми.

Динамічний масив оголошується без зазначення меж:

var DynArray: array of Integer;

Змінна DynArray являє собою посилання на елементи масиву, що розміщуються в динамічній пам'яті. Спочатку пам'ять під масив не резервується, кількість елементів масиві дорівнює нулю, а значення змінної DynArray дорівнює nil.

Робота з динамічними масивами нагадує роботу з довгими рядками. Зокрема, створення динамічного масиву (виділення пам'яті його елементів) здійснюється тієї ж процедурою, якою встановлюється довжина рядків - SetLength.

SetLength(DynArray, 50); // Виділити пам'ять для 50 елементів

Зміна розміру динамічного масиву проводиться цією ж процедурою: SetLength (DynArray, 100); // Тепер розмір масиву 100 елементів

При зміні розміру масиву значення всіх елементів зберігаються. При цьому послідовність дій така: виділяється новий блок пам'яті, значення елементів зі старого блоку копіюються новий, старий блок пам'яті звільняється.

При зменшенні розміру динамічного масиву зайві елементи втрачаються.

При збільшенні розміру динамічного масиву доданіелементи не ініціалізуються жодним значенням і у випадку їх значення випадкові. Однак, якщо динамічний масив складається з елементів, тип яких передбачає автоматичну ініціалізацію порожнім значенням (string, Variant, динамічний масив, ін.), то додана пам'ять ініціалізується нулями.

Визначення кількості елементів здійснюється за допомогою функції Length:

N := Length(DynArray); // N отримає значення 100

Елементи динамічного масиву завжди індексуються від нуля. Доступ до них нічим не відрізняється від доступу до елементів звичайних статичних масивів:

DynArray[0]: = 5; // Присвоїти початковому елементу значення 5 DynArray[High(DynArray)] := 10; // Присвоїти кінцевому елементу значення 10

До динамічних масивів, як і до звичайних масивів, застосовні функції Low і High, що повертають мінімальний та максимальний індекси масиву відповідно. Для динамічних масивів функція Low завжди повертає 0.

Звільнення пам'яті, виділеної для елементів динамічного масиву, здійснюється установкою довжини значення 0 або присвоюванням змінної-масиву значення nil (обидва варіанти еквівалентні):

SetLength(DynArray, 0); // Еквівалентно: DynArray: = nil;

Однак Вам зовсім необов'язково після закінчення використання динамічного масиву звільняти виділену пам'ять, оскільки вона звільняється автоматично при виході з області дії змінної-масиву (зручно, чи не так!). Ця можливість забезпечується вже відомим Вам механізмом підрахунку кількості посилань.

Також, як і при роботі з рядками, при присвоєнні одного динамічного масиву іншому копія вже існуючого масиву не створюється.

var A, B: array of Integer; begin SetLength(A, 100); // Виділити пам'ять для 100елементів A[0]: = 5; B := A; // A і B вказують на ту саму область пам'яті! B[1]: = 7; // Тепер A [1] теж дорівнює 7! B[0]: = 3; // Тепер A [0] дорівнює 3, а чи не 5! end.

Як і у випадку рядків, пам'ять звільняється, коли кількість посилань стає рівним нулю.

var A, B: array of Integer; begin SetLength(A, 100); // Виділити пам'ять для 100 елементів A [0]: = 10; B := A; // B свідчить про ті самі елементи, як і A A := nil; // Пам'ять ще звільняється, оскільки неї указує B B[1] := 5; // Продовжуємо працювати з B, B [0] = 10, а B [1] = 5 B: = nil; // Тепер посилань блок пам'яті немає. Пам'ять звільняється end;

Для роботи з динамічними масивами можна використовувати знайому по рядках функцію Copy. Вона повертає частину масиву як нового динамічного масиву.