Скачати 301.21 Kb.
|
Глава 1.000000 Динамічні дані1.1.0 Дані у вільній пам’ятіВільна пам’ять і динамічні даніПам’ять процесу виконання програми складається з кількох частин: – код програми (містить команди програми й бібліотечних функцій, які викликаються у програмі); – статична пам’ять (зберігає статичні змінні, що існують протягом усього процесу виконання програми); – автоматична пам’ять, або програмний стек (містить змінні, локальні у викликах функцій); – вільна пам’ять (містить дані, що створюються під час виконання програми за її вказівками). Розмір статичної пам’яті програми не змінюється протягом виконання програми. Програмний стек має певний, відносно невеликий розмір, в межах якого створюються й знищуються змінні, локальні у викликах функцій. На відміну від них, розмір вільної пам’яті обмежений тільки наявною пам’яттю комп’ютера, яку не зайнято іншими програмами. Це дозволяє створювати й обробляти масиви значно більшого розміру ніж у статичній або автоматичній пам’яті. Спосіб організації даних у вільній пам’яті називається купою й реалізується диспетчером пам’яті в складі операційної системи.
Операція new з ім’ям типу як операндом створює динамічну змінну цього типу; значенням операції є адреса змінної. Приклади 1. Інструкції int *p; p = new int; або ініціалізація int *p = new int; оголошують вказівник на цілі, створюють динамічну змінну цілого типу й встановлюють на неї вказівник p. Далі цю змінну ідентифікує вираз *p. Створювану динамічну змінну можна ініціалізувати значенням виразу в дужках. int *p = new int(123); Значенням змінної *p стає 123. 2. Розглянемо інструкції. int *pi = new int(123); int **ppi = new int*(pi); П ![]() ерша створює динамічну цілу змінну зі значенням 123 і встановлює на неї вказівник pi. Друга створює динамічний вказівник, ініціалізує його значенням вказівника pi (адресою змінної *pi) і встановлює на нього вказівник ppi (рис. .1\\\\). Рис. 1.1. Створення динамічних змінних Вільна пам’ять величезна, але обмежена, тому, коли створюється динамічна змінна, незайнятої ділянки потрібного розміру може й не бути. Тоді значенням операції new є NULL, що є ознакою невдалої спроби створити змінну. Звідси, після спроби створити змінну варто перевірити, чи не була ця спроба невдалою, й, якщо так, відповідно відреагувати. ^ if(!p) ... // якщо змінну не створено… Вираз !p (або p==NULL) позначає, що p «встановлено на ніщо». Операція delete, операндом якої є ім’я вказівника, скажімо, delete p, звільняє ділянку пам’яті, на яку встановлено вказівник (знищує динамічну змінну).
Залежно від компілятора спроба доступу до вже знищеної змінної може бути допустимою, або бути помилковою, або аварійно закінчувати програму (як і спроба звільнити вже звільнену змінну). Приклад. Інструкції, наведені нижче, у деяких системах програмування виконуються, але, починаючи з третього рядка, є дуже небезпечними. int *ip = new int (123); delete ip; // знищення змінної *ip *ip=46; // це небезпечно! cout << *ip; // виведення 46 delete ip; // повторне знищення небезпечно! cout << *ip; // виведення «сміття»
Кожен клас має два стандартних конструктори: один дозволяє оголосити об’єкт, інший (конструктор копії) – ініціалізувати об’єкт за допомогою іншого. Перший створює об’єкт, але не надає його полям значень, другий копіює в створений об’єкт значення полів іншого об’єкта. Якщо об’єкти містять поля-вказівники, то стандартних конструкторів зазвичай недостатньо. Адже, коли стандартний конструктор створює об’єкт, значенням вказівника в об’єкті є якась випадкова адреса. Спроба скористатися нею дає непередбачувані наслідки. Копіювання ж полів з іншого об’єкта призводить до того, що вказівники в різних об’єктах вказують на одну й ту саму змінну, що бажано далеко не завжди. Отже, якщо об’єкти класу містять вказівники, зазвичай необхідні власні конструктори. Для ілюстрації розглянемо дуже простий клас: атрибутом є вказівник на цілу змінну, а методи дозволяють встановити й отримати її значення, а також перевірити, чи існує взагалі ця змінна (реалізуємо їх нижче). class PInt { int * p; public: // встановити й повернути значення void setValue(int i); int getValue(); bool isDefined(); // чи існує змінна ... // далі додамо три конструктори й деструктор }; Перш ніж методом getValue отримувати ціле число за допомогою вказівника в об’єкті, необхідно забезпечити, щоб цей вказівник було встановлено на змінну, а змінна мала значення. Чи встановлено вказівник на деяку змінну, визначає метод isDefined. Додамо до класу PInt два конструктори – з цілим параметром і без параметрів. Конструктор з цілим параметром створює динамічну цілу змінну, ініціалізує вказівник у створеному об’єкті її адресою й надає їй початкове значення. PInt(int i) : p(new int) { *p=i; } Конструктор без параметрів ініціалізує вказівник в об’єкті значенням NULL. PInt():p(NULL){} Ненульовий вказівник в об’єкті стає ознакою того, що ціла змінна отримала значення, нульовий – що не отримала. ^ Додамо до класу PInt конструктор копії, який забезпечує кожному об’єкту власний екземпляр цілої змінної. Нагадаємо: конструктор копії має один незмінюваний параметр-посилання, що позначає об’єкт, за допомогою якого ініціалізується створюваний об’єкт. ^ Означимо його за межами класу. У новому об’єкті він присвоює вказівнику NULL, якщо в «базовому» об’єкті вказівник нульовий, інакше створює нову цілу змінну, встановлює на неї вказівник у об’єкті й присвоює їй значення змінної, що належить іншому об’єкту. ^ { if (!old.p) p = NULL; else {p = new int; *p = *(old.p);} } Конструктор копії дозволяє ініціалізувати об’єкт іншим об’єктом, наприклад, як b і c в такій інструкції. PInt a(5), b(a), c=a; Вказівники в об’єктах a, b, c встановлено на три різні цілі змінні, кожна зі значенням 5.
^ звільняє пам’ять, зайняту об’єктом. Якщо в об’єкті класу є поле-вказівник, то дані, на які його встановлено, після знищення об’єкта продовжують займати пам’ять. Їх необхідно знищити або обробити в інший спосіб перед знищенням об’єкта. Ці дії має описувати власний деструктор класу. До класу ^ додамо деструктор, заголовок якого має стандартний вигляд. ~PInt(); Він знищує цілу змінну, на яку вказує вказівник об’єкта (якщо його встановлено). PInt::~PInt() { if(p) delete p; } Без цього деструктора ціла змінна, на яку посилається вказівник в об’єкті, після знищення об’єкта залишається в пам’яті, але є недоступною, оскільки на неї не вказує жоден вказівник.
Реалізуємо методи класу PInt, врахувавши створені конструктори. Метод установки значення setValue присвоює цілій змінній значення, задане параметром. При цьому, якщо вказівник у об’єкті нульовий, метод спочатку створює змінну. Повертає ознаку того, що змінна існує. bool PInt::setValue(int i) { if(!p) p = new int; if(!p) return 0; *p=i; return 1; } Цей метод дозволяє надати значення вже існуючому об’єкту. PInt a; a.setValue(10); Метод отримання значення getValue визначає, чи встановлено вказівник об’єкта на цілу змінну. Якщо так, то повертає її значення, інакше повідомляє про відсутність змінної й закінчує роботу програми. int PInt::getValue() { if(p) return *p; else { cout << "Int variable is absent\n"; exit(1); } } ^ Cтворити динамічний масив можна за допомогою операції new. Нехай T – тип елементів масиву, p – вказівник типу T*. Присвоювання p = new T [n] створює масив елементів типу T з індексами 0, 1, …, n-1 і встановлює p на його перший елемент. Після цього вирази *(p+i) й p[i] позначають i-й елемент масиву. В якості n можна записати довільний вираз із додатним цілим значенням. Операція delete звільняє пам’ять з-під динамічного масиву. Якщо вказівник p встановлено на початок масиву, то масив знищується так. delete [] p; Приклад. Програма створює динамічний масив з п’яти цілих елементів, присвоює їм значення від 0 до 4, виводить їх і знищує створений масив. int main(){ int * p = new int[5]; // створення масиву int i; // обробка масиву for(i=0; i<5; p[i]=i, ++i); for(i=0; i<5; ++i) cout << *(p+i) << ' '; delete [] p; // знищення масиву return 0; } Докладніше роботу з динамічними масивами розглянемо в наступному розділі. Вправи1.1. Імітувати виконання програми з такою головною функцією. int main(){ int * p1 = new int(0), *p2 = new int(2), * p3 = new int; *p3=*p1; *p1=*p2; *p2=*p3; delete p3; p3=p1; cout << *p3 << *p1 << *p2; delete p1; delete p2; return 0; } 1.2. Написати функцію з двома параметрами, що є вказівниками на int. Функція обмінює місцями значення динамічних змінних, на які встановлено ці вказівники. 1.3. Модифікувати конструктор з параметром у класі PInt так, щоб він повідомляв про можливе невдале створення цілої змінної. 1.4. До класу PInt додати метод обміну місцями цілих значень, на які вказують вказівники в об’єктах. 1.5. До класу PInt додати методи введення цілого значення в об’єкт за допомогою клавіатури й виведення з об’єкта на екран. |
![]() | 3. технології проектування педагогічного процесу Підготовку фахівців з вищою освітою регламентують освітньо-кваліфікаційні характеристики, засоби діагностики якості вищої освіти,... | ![]() | Заява про спростування недостовірної інформації, поширеної 29 квітня... «Гроші», в якій автор програми – Жан Новосельцев, журналістка останнього сюжету програми (починаючи з 42: 17 хв.) – Ярослава Коба... |
![]() | Лабораторна робота 3 Робота з програмою «Провідник» Мета Для запуску програми необхідно відкрити головне меню І вибрати Програми – Провідник. Або відкрити папку «Мій комп’ютер» І в ній двічі... | ![]() | Резолюція круглого столу «Запровадження теорії наукового креаціонізму... Навчальні програми шкіл України : керівники І представники громадських організацій, науковці, юристи, педагоги, громадські діячі... |
![]() | Програма розвитку туризму в Тернопільській області на 2013-2015 роки Паспорт програми Дата, номер І назва розпорядчого документа органу виконавчої влади про розроблення програми | ![]() | Оцінка (аналіз) на уроці. Підведення підсумків уроку. Домашнє завдання,... Зичної культури, повноту І точність засвоєння розділів програми за навчальну чверть, семестр, рік, виявити фізичний розвиток та фізичну... |
![]() | Авторські права на текст програми “Українська література, 5-12 кл.”... Авторське право на видрук програми (враховуючи редагування, коректуру, верстку, художнє оформлення) належить видавництву “Перун”... | ![]() | Авторські права на текст програми “Фізика. Астрономія, 7-12 кл.”... Авторське право на видрук програми (враховуючи редагування, коректуру, верстку, художнє оформлення) належить видавництву “Перун”... |
![]() | Авторські права на текст програми “Фізика. Астрономія, 7-12 кл.”... Авторське право на видрук програми (враховуючи редагування, коректуру, верстку, художнє оформлення) належить видавництву “Перун”... | ![]() | Авторські права на текст програми “Зарубіжна література, 5-12 кл.”... Авторське право на видрук програми (враховуючи редагування, коректуру, верстку, художнє оформлення) належить видавництву “Перун”... |