- •Розділ 1. Об’єктно-орієнтоване програмування
- •Тема 1.1. Візуальне програмування.
- •Тема 1.2. Приклади та застосування інкапсуляції, успадкування, поліморфізму.
- •Тема 1.3. Бібліотека візуальних компонентів vcl та її базові класи.
- •1. Клас tWinControl.
- •2. Клас tСustomControl.
- •3. Клас tGraphicControl.
- •Тема 1.4. Обробка виняткових ситуацій.
- •1. Використовування виняткових ситуацій.
- •2. Протоколювання виняткових ситуацій.
- •3. Коди помилок у виняткових ситуаціях.
- •4. Виняткова ситуація eAbort. Функція Assert.
- •Розділ 2. Мова програмування Object Pascal.
- •Тема 2.1. Середовище Delphi.
- •Тема 2.2. Елементи мови Object Pascal.
- •1. Коментарі.
- •2. Логічні вирази.
- •Тема 2.3. Типи даних, процедури та функції.
- •1. Вказівники та динамічна пам'ять. Динамічна пам'ять
- •Вказівники
- •Виділення і звільнення динамічної пам'яті
- •Процедури і функції для роботи з динамічною пам'яттю
- •Тема 2.4. Управляючі структури Object Pascal.
- •Розділ 3. Програмування в середовищі Delphi.
- •Тема 3.1. Застосування списків. Способи запису/читання зі списків.
- •Є списком CheckBox елементів.
- •Тема 3.2. Масиви.
- •1. Пошук мінімального (максимального) елементу масиву.
- •2. Пошук в масиві заданого елементу.
- •Тема 3.3. Робота з файлами.
- •Тема 3.4. Типи даних визначені програмістом.
- •1. Показники.
- •2. Динамічні змінні.
- •Тема 3.5. Графічні програми.
- •1. Бітові образи.
- •2. Мультиплікація.
- •Властивості компоненту Timer
- •Тема 3.6. Приклади застосування анімацій у Delphi.
- •Тема 3.7. Рекурсія.
- •1. Крива Гільберта.
- •2. Пошук шляху.|колії|
- •Значення властивостей компоненту stringGrid1
- •3. Пошук найкоротшого шляху.|колії|
- •Тема 3.8. Компоненти для інтернету. Компонента tSocketConnection
- •Розділ 4. Бази даних.
- •Тема 4.1. Види баз даних. Структура та зв’язки між таблицями. Бази даних
- •Класифікація баз даних
- •Структура бази даних
- •Модель бази даних в Delphi
- •Тема 4.2. Модифікація структури таблиці в bde.
- •1. Зміна структури таблиці.
- •2. Встановлення перевірок правильності даних.
- •3. Завдання вторинних індексів.
- •Тема 4.3. Об’єкти відображення даних бази даних Delphi.
- •1. Класифікація компонентів відображення даних.
- •2. Елемент керування тdbGrid.
- •3. Компонент tdbEdit.
- •4. Компонент tdNavigator.
- •Тема 4.4. Обчислювальні поля і поля підстановки в Delphi.
- •1. Створення поля підстановки (поля синхронного перегляду).
- •2. Обчислювальні поля.
- •Тема 4.5. Компонента tdbEdit.
- •Тема 4.6. Переміщення по записам таблиці. Набір методів і властивостей tDataSet. Огляд
- •Клас tDataSet
- •Відкриття і закриття DataSet
- •Тема 4.7. Налаштування фільтрів.|
- •Тема 4.8. Приклади застосування пошуку.
- •Тема 4.9. Поєднання різних видів пошуку.
- •Тема 4.10. Типи даних та пошук в діапазоні.
- •Список літератури
1. Вказівники та динамічна пам'ять. Динамічна пам'ять
Динамічна пам'ять – це оперативна пам'ять ПК, що надається програмі при її роботі. Динамічне розміщення даних означає використовування динамічної пам'яті безпосередньо при роботі програми. На відміну від цього статичне розміщення здійснюється компілятором Object Pascal в процесі компіляції програми. При динамічному розміщенні наперед не відомий ні тип, ні кількість розміщуваних даних.
Вказівники
Оперативна пам'ять ПК є сукупністю осередків для зберігання інформації – байтів, кожний з яких має власний номер. Ці номери називаються адресами, вони дозволяють звертатися, до будь-якого байта пам'яті. Object Pascal надає в розпорядження програміста гнучкий засіб управління динамічною пам'яттю – так звані покажчики. Покажчик – це змінна, яка як свого значення містить адресу байта пам'яті. За допомогою покажчиків можна розміщувати в динамічній пам'яті будь-який з відомих в Object Pascal типів даних. Лише деякі з них (Byte, Char, ShortInt, Boolean) займають у внутрішньому уявленні один байт, інші – декілька суміжних. Тому насправді покажчик адресує лише перший байт даних.
Як правило, покажчик зв'язується з деяким типом даних. Такі покажчики будемо називати тими, що типізуються. Для оголошення покажчика, що типізується, використовується значок ^, який поміщається перед відповідним типом, наприклад:
var
p1 : ^Integer;
р2 : ^Real;
type
PerconPointer = "PerconRecord;
PerconRecord = record Name : String;
Job : String;
Next : PerconPointer ,
end;
Зверніть увагу: при оголошенні типу PerconPointer ми послалися на тип PerconRecord, який заздалегідь в програмі оголошений не був. Як вже наголошувалося, в Object Pascal послідовно проводиться в життя принцип, відповідно до якого перед використовуванням якого-небудь ідентифікатора він повинен бути описаний. Виключення зроблено тільки для покажчиків, які можуть посилатися на ще не оголошений тип даних.
В Object Pascal можна оголошувати покажчик і не зв'язувати його при цьому з яким-небудь конкретним типом даних. Для цього служить стандартний тип pointer, наприклад:
var
р: Pointer;
Покажчики такого роду будемо називати нетипізованими. Оскільки покажчики, що нетипізуються, не пов'язані з конкретним типом, з їх допомогою зручно динамічно розміщувати дані, структура і тип яких міняються в ході роботи програми.
Як вже говорилося, значеннями покажчиків є адреси змінних в пам'яті, тому слід було б чекати, що значення одного покажчика можна передавати іншому. Насправді це не зовсім так. В Object Pascal можна передавати значення тільки між покажчиками, пов'язаними з одним і тим же типом даних.
Якщо, наприклад
var
pI1,pI2: ^integer;
pR: ^Real;
p: Pointer;
pI1 := pI2;
pl1 :=pR;
p := pR;
pI1 := p;
і тим самим досягти потрібного результату.
Виділення і звільнення динамічної пам'яті
Вся динамічна пам'ять в Object Pascal розглядається як суцільний масив байтів, який називається купою.
Пам'ять під будь-яку динамічно розміщувану змінну виділяється процедурою New. Параметром звернення до цієї процедури є покажчик, що типізується. В результаті обіг покажчик придбаває значення, відповідне адресі, починаючи з якої можна розмістити дані, наприклад:
var pI,pJ: ^Integer;
pR: ^Real;
begin
New (pI) ;
New (pR) ;
end;
Після того, як покажчик набув деяке значення, тобто став указувати на конкретний фізичний байт пам'яті, за цією адресою можна розмістити будь-яке значення відповідного типу. Для цього в операторі привласнення відразу за покажчиком без яких-небудь пропусків ставиться значок ^, наприклад:
PJ^ := 2; // В область пам'яті pJ поміщено значення 2
PR^ := 2*pi; // В область пам'яті pR поміщено значення 6.28
Таким чином, значення, на яке указує покажчик, тобто власне дані, розміщені в купі, позначаються значком ^, який ставиться відразу за покажчиком. Якщо за покажчиком немає значка ^, то мається на увазі адреса, по якій розміщені дані. Має сенс ще раз задуматися над тільки що сказаним: значенням будь-якого покажчика є адреса, а щоб вказати, що йдеться не про адресу, а про ті дані, які розміщені за цією адресою, за покажчиком ставиться ^ (іноді про це говорять як про розіменування покажчика).
Динамічно розміщені дані можна використовувати в будь-якому місці програми, де це допустимо для констант і змінних відповідного типу, наприклад:
рR^ := Sqr(pR") + І^ - 17;
Зрозуміло, абсолютно недопустимbq оператор
pR := Sqr(pR") + I^ - 17;
оскільки покажчику pR не можна привласнити значення речовинного виразу. Так само недопустимий оператор
pR ^ := Sqr(pR); оскільки значенням покажчика pR є адреса і його (на відміну від того значення, яке розміщене за цією адресою) не можна зводити в квадрат. Помилковим буде і таке привласнення:
pR^' := pJ;
оскільки речовинним даним, на які указує pR, не можна привласнити значення покажчика (адреса).
Динамічну пам'ять можна не тільки забирати з купи, але і повертати назад. Для цього використовується процедура Dispose. Наприклад, оператори
Dispose(pJ);
Dispose(pR);
повернуть в купу пам'ять, яка раніше була закріплена за покажчиками pJ і pR (див. вище).
Помічу, що процедура Dispose (pPtr) не змінює значення покажчика pPtr, а лише повертає в купу пам'ять, раніше пов'язану з цим покажчиком. Проте повторне застосування процедури до вільного покажчика приведе до виникнення помилки періоду виконання. Покажчик, що звільнився, програміст може помітити зарезервованим словом nil. Чи помічений який-небудь покажчик чи ні, можна перевірити таким чином:
const
pR: ^Real = NIL;
begin
if pR = NIL then
New (pR) ;
Dispose(pR) ;
pR := NIL;
end;
Ніякі інші операції порівняння над вказівниками не дозволені.
Приведений вище фрагмент ілюструє переважний спосіб оголошення покажчика у вигляді константи, що типізується, з одночасним привласненням йому значення nil. Слід врахувати, що початкове значення покажчика (при його оголошенні в розділі змінних) може бути довільним. Використовування покажчиків, яким не привласнено значення процедурою New або іншим способом, не контролюється Delphi і викличе виключення.
Як вже наголошувалося, параметром процедури New може бути покажчик, що тільки типізується. Для роботи з покажчиками, що нетипізуються, використовуються Процедури GetMem І FreeMem:
GetMem(P, Size); // резервування пам'яті;
FreeMem(P, Size); // звільнення пам'яті.
Тут р – покажчик, що нетипізується; size – розмір в байтах необхідної або звільняється частини купи.
Примітка
Використання процeдуp GetMem/FreeMemMem, як і взагалі вся робота динамічної пам'яттю, вимагає особливої обережності і ретельного дотримання простого правила: звільняти потрібно рівно стільки пам'яті, скільки її було зарезервовано, і саме з тієї адреси, з якої вона була зарезервована.
