Динамічні масиви в delphi, різні статті, статті, програмування - програмування c,

Новая страница 1

Масив √ це упорядкований набір даних. Як правило, кількість елементів масиву обмежена. Середовище Delphi використовує синтаксис мови Object Pascal, а згідно з останнім, масиви оголошуються так:

Де index1 і indexN належать впорядкованого типу, діапазон якого, як написано в документації по Delphi 6, не перевищує 2Gb. BaseType √ тип елементів масиву.

Ми оголосили масив My_Array, що складається з 100 елементів типу Real. Масиви можуть бути одновимірними, дво- та n-мірними. Теоретично, обмеження на розмірність масиву немає, на практиці розмірність обмежена доступною пам'яттю.

Все сказане вірно для статичних масивів. Однак статичні масиви мають істотний недолік. У більшості випадків ми не знаємо, зі скількох елементів складатиметься наш масив. Тому доводиться резервувати пам'ять "про запас": краще я зарезервує пам'ять ще для десяти елементів масиву, ніж один елемент масиву виявиться зайвим. Наприклад, при читанні інформації з файлу ми не знаємо, скільки елементів ми можемо прочитати: один, два, десять або сто. Зазвичай для вирішення таких завдань застосовувалися динамічні списки LIFO (Last In First Out, стек) або FIFO (First In First Out, чергу).

Розробники Delphi в останніх версіях (5,6) свого продукту реалізували досить гнучкий механізм для роботи з динамічними масивами. Нам уже не потрібно створювати динамічні списки, ми вже ніколи не забудемо поставити знак "^" при зверненні до елементу списку і на певний час забудемо про процедурах new, mark і dispose.

Примітка. У більш ранніх версіях (наприклад, 3) такого механізму не існувало.

Як ви бачите, ми просто говоримо Delphi, що нам потрібен одновимірний масив типу Real, а про його розмірі ми сказати просто-напросто забули.

Після виклику цієї процедури буде виділена пам'ять для 100 елементів масиву, які будуть проіндексовані від 0 до 99 (зверніть увагу: індексування починається з нуля, а не з одиниці!).

Динамічні масиви √ це неявні покажчики і обслуговуються тим же самим механізмом, який використовується для обробки довгих рядків (long strings). Щоб звільнити пам'ять, займану динамічним масивом, надайте змінної, яка посилається на масив, значення nil: A: = nil.

Суха теорія без практики √ це ніщо, тому для кращого перетравлення матеріалу розглянемо наступну програму:

Потім відкрийте вікно Watch List, натиснувши комбінацію клавіш Ctrl + Alt + W і встановіть режим вікна Stay On Top (команда Stay On Top з'явиться в спливаючому меню, якщо ви клацніть правою кнопкою де-небудь в області вікна), щоб вікно не сховалося з очей , коли ви запустите програму .У лістингу 1 біля кожного рядка я вказав значення змінних A і B після проходу рядки. Як ви помітили, я пронумерував лише рядки, які містять оператори, що змінюють змінні A і B.

Рядок 1: для змінних A і B пам'ять не виділена. Звідси висновок: до виклику процедури SetLength працювати з масивом можна. У другому рядку пам'ять виділена тільки для масиву A. Оскільки змінна A √ глобальна, значення елементів масиву обнуляються. Якби змінна A була локальною, потрібна була ініціалізація елементів масиву. Локальні змінні не обнуляються і, як правило, містять випадкові значення (сміття), взяті з пам'яті, в якій розміщена змінна.

У третьому рядку ми присвоюємо масиву B масив A. Перед цією операцією не потрібно виділяти пам'ять для масиву B за допомогою SetLength. При присвоєнні елементу B [0] присвоюється елемент A [0], B [1] √ A [1] і т.д. Зверніть увагу на рядок 4: ми присвоїли нові значення змінних масиву A і автоматично (масиви √ це ж покажчики) елементів масиву B присвоєно точно такі ж значення і навпаки: чи варто нам змінити будь-якої елемент масиву B, зміниться елемент масиву A з відповідним індексом .

Тепер починається найцікавіше. При зміні довжини масиву А (рядок 5) стався розрив зв'язку між масивами. Це явище демонструє рядок 6, яка містить ряд операторів присвоювання. Спочатку ми присвоюємо значення елементів масиву A: 2, 4, 5. Потім намагаємося змінити значення елемента A [0], присвоївши елементу B [0] значення 1. Але, як ми переконалися, зв'язку між масивами вже немає і після зміни значення елемента B [0], значення елемента A [0] не було змінено. Ще один важливий момент: при зміні довжини масиву просто додається новий елемент, без втрати вже існуючих значень елементів (рядок 5). Довжина пов'язаного масиву B не змінюється.

У рядку 7 ми звільняємо пам'ять, виділену для масиву A. Масив B залишається існувати до кінця роботи програми. Масиви нульової довжини містять значення nil.

Потрібно сказати пару слів про порівняння масивів:

При спробі порівняння A = B або B = A ми отримаємо true: масиви рівні. А ось в такій ситуації при порівнянні ми отримаємо false:

При спробі привласнити значення елементу статичного масиву, індекс якого виходить за межі масиву, ми отримаємо відповідну помилку: Constant expression violates subrange bounds (порушення кордонів діапазону). При роботі з динамічними масивами ви не побачите такої помилки. З одного боку це добре, а з іншого √ погано. Ви можете витратити багато часу, щоб зрозуміти, чому ви не можете привласнити значення елементу масиву з індексом 4, поки не виявите, що на самому початку програми виділили пам'ять тільки для трьох елементів. Зараз ця ситуація здається смішною, але вона відбувається набагато частіше, ніж вам здається. Функція SetLength породжує помилку EOutOfMemory, якщо недостатньо пам'яті для розподілу масиву.

Чи не застосовуйте оператор "^" до змінної динамічного масиву. Також не слід передавати змінну масиву процедурам New або Dispose для виділення або звільнення пам'яті.

Як тільки динамічний масив був розподілений, ви можете передавати масив стандартних функцій Length, High і Low. Функція Length повертає число елементів в масиві, High повертає масив найвищий індекс (тобто Length √ 1), Low повертає 0. У випадку з масивом нульової довжини спостерігається парадоксальна ситуація: High повертає -1, а Low √ 0, виходить, що High

Як ми можемо використовувати функції High і Low з найбільшою користю? Для цього розглянемо процедуру init і функцію sum. Перша з них инициализирует масив (обнуляє значення елементів), а друга √ підраховує суму елементів масиву:

Залишається неясним один момент: чи можна використовувати багатовимірні динамічні масиви? Да можемо. Оголосити двомірний масив можна так:

Для виділення пам'яті потрібно викликати процедуру SetLength з двома параметрами, наприклад,

Працювати з двовимірним динамічним масивом можна так само, як і зі статичним:

Ви можете створювати не прямокутні масиви. Для цього спочатку оголосите масив:

Потім створіть n рядків, але без колонок, наприклад,

Тепер ви можете створювати колонки різної довжини:

Примітка. Якщо ви працювали з більш ранніми версіями Delphi, то, напевно, знаєте, що функція SetLength використовувалася для динамічного зміни довжини рядка. Швидше за все, ви її не використовували, тому що довжина рядка змінювалася автоматично при операції присвоювання.

Схожі статті