Урок 95 Інформатика (АП)
Покажчики; використання динамічної пам’яті.
Мета.
Навчальна. Ознайомлення з додатковими можливостями мови Паскаль, зокрема з покажчиками та їх використання для опрацювання даних.
Розвиваюча. Розвивати логічне мислення, самостійність, вміння розуміти і бачити структуру програми, що працює з масивом.
Виховна. Виховувати наполегливість, зібраність, уважність, грамотно висловлювати свої думки, вміння раціонально використовувати час.
Тип уроку. Засвоєння нових знань, вмінь і навичок.
План
Пам’ятка для учня!
1 Пригадайте правила техніки безпеки при роботі з ПК.
2 Через кожні 15 хв виконуйте вправи для очей та для зняття м’язової втоми.
Хід уроку
1. Перевірка домашнього завдання.
1. Наявність.
2. Питання.
2. Актуалізація опорних знань.
Дано текст українською мовою, який закінчується крапкою. У тексті видалити всі голосні літери.
Приклад тексту: Ви танцюєте, але ноги - це ще не крила.
3. Викладення нового матеріалу.
Нам у житті завжди чогось бракує, а програмістам завжди, в першу чергу, бракує комп'ютерної пам'яті.
Давайте нагадаємо, яким чином зберігаються дані в пам'яті комп'ютера. Значення кожної змінної записане в деякій області пам'яті. Програмі відомо, за якою адресою записана ця змінна і скільки місця в пам'яті комп'ютера вона займає, оскільки кожна змінна має свій тип і довжину.
Отже, приходимо до ідеї роботи з безіменними величинами, звертаючись до них лише за адресами, з яких вони починаються.
Тому тепер треба знати не ім'я змінної, а її адресу. Величини, які містять адреси, мають тип pointer, тобто «точка входу». Це новий для нас тип. Величини цього типу займають в пам'яті 4 байти.
У чому полягає зручність використання змінних, які містять адреси замість імен змінних? Тепер можна, змінюючи значення змінної типу pointer, насправді змінювати адресу, яка там записана, і тим самим подорожувати пам'яттю, читаючи звідти інформацію або записуючи її туди. Звичайно, такі подорожі дуже ризиковані і можуть призвести до втрати дорогоцінної інформації. Тому до набуття певного досвіду варто обережно використовувати тип pointer.
Тип pointer указує на початок пам'яті, в якій записано певну інформацію, розміри якої невідомі. Ми їх можемо звідти читати щонайменше байтами. Але найчастіше в програмах маємо справу з типізованими змінними. Тому нам зручно було б, крім адреси початку значення змінної, вказати також програмі, скільки місця займає ця змінна. Для цього в Pascal існують різновиди типу pointer, які носять назву посилальних типів і позначаються символом «^» перед типом змінної. Тип самої змінної, на яку вказує змінна посилального типу, називається базовим.
Перейдемо до прикладів:
type A=array [1 ..100] of real;
var P_int: ^integer;
P_real: ^real;
P_A: ^A;
P: pointer;
Змінна P_int міститиме адресу, що вказуватиме на комірку пам'яті, починаючи з якої записане значення цілої величини, тобто довжиною в 2 байти. При читанні цього значення Pascal розкодовуватиме послідовність 0 та 1, яка там міститься, за правилами кодування цілих чисел.
Змінна Р_геаl відповідно міститиме адресу початку величини типу real.
Корисно розібрати змінну Р_А. Вона вказуватиме на початок області пам'яті комп'ютера, з якої починається розташування елементів масиву А, кожний з яких є дійсним числом. Реальна кількість елементів масиву, з якою працюватиме користувач, поки що невідома. Відомо лише, що вона не може перевищувати числа 100.
У багатьох типів Pascal існує можливість присвоювання «нульових» значень:
v_integer := 0; v_string := ' '; v_set := [].
Схожа операція є і для посилальних типів:
v_point := nil.
У цьому випадку змінна v_point вказуватиме «в нікуди».
Як же дістатися до значення, що записане за адресою, на яку вказує змінна типу «покажчик» або посилального типу? Для цього в Pascal існує операція розіменовування.
Якщо Р вказує на адресу, за якою записане деяке значення, то Р^ — це вміст області пам'яті комп'ютера, тобто значення змінної, записаної за адресою Р.
Наприклад, результатом виконання операції J^ := I^ буде копіювання значення змінної, записаної за адресою I, в область пам'яті, на яку вказує змінна J. Ця операція можлива, якщо за обома адресами записані значення змінних однакового типу (рис.1).
Рис.1
Якщо виконати операцію J:=І, то змінна J матиме таку саму адресу, як і змінна I (рис.2).
Рис.2
У результаті виконання цієї операції посилання на значення 4 втрачене. У пам'яті комп'ютера в цьому місці фактично лишилося «сміття», бо цим значенням уже ніхто не зможе скористатися. Саме подібних ситуацій треба уникати.
Структури змінних, на які вказують величини посилальних типів, називають ще динамічними, оскільки ми самі розподіляємо їх у пам'яті та звільняємо від них пам'ять, коли необхідність у їх значеннях відпадає. Це класичний спосіб роботи з масивами невідомої наперед довжини. Бувають також задачі, коли кількість і розмірність масивів не дозволяє одночасно розташувати їх у пам'яті. Проте з алгоритму видно, що робота з усіма масивами одночасно не ведеться. Отже, резервувати для них заздалегідь пам'ять, як ми робили це досі, нераціонально.
Для розміщення динамічних змінних Pascal відводить спеціальну область пам'яті розміром в 64 Кбайти. Ця область носить назву «купи».
Розглянемо процедурні та функціональні можливості Pascal, які допоможуть вам при використанні посилальних типів.
Нагадаємо, що в процедурах і функціях після їх назв подається список формальних параметрів із зазначенням їх типів. Параметри, перед якими є службове слово var, є результатами, а перед якими немає - аргументами.
А тепер розглянемо програму, що демонструє роботу з динамічною пам'яттю. Для цього використаємо задачу, подібну до тих, які розв'язували, вивчаючи масиви.
Нехай нам треба розташувати в динамічній пам'яті елементи цілочислового масиву, кількість яких наперед невідома, та порахувати кількість значень, з яких утворено цей масив, якщо відомо, що їх кількість не перевищує 256.
program dimension;
type Dim = array [1 ..5000] of integer;
var P: ^Dim;
i, n, L, m: integer;
SL: integer;
PSize: longint;
S: set of byte;
begin
write ('Задайте кількість елементів масиву: ');
readln (n);
SL:=StzeOf (integer);
PSize := SL*(MaxAVail div SL);
L := n*SL;
if (L > PSize) or (SizeOf(Dim) > PSize)
then
writeln ('Такий масив не може бути розміщений у пам’яті')
else
begin
GetMem(P, L);
S:=[];
m:=0;
for і:= 1 to n do
begin
readln (Р^[і]);
if not(P"[i] in S) then
begin
S:=S + P^[i];
m := m+1;
end;
writeln (Р^[і]);
end;
for і := 1 to n do
writeln (Р^[і]);
writeln ('Кількість значень, з яких складається масив:т);
FreeMem(P, L);
end;
end.
У цій програмі використано функцію SizeOf, яка визначає розмір у байтах одного елемента вказаного типу.
Використання динамічної пам'яті для розміщення даних різної структури - дуже потужна можливість.
За допомогою динамічних змінних організовуються і розміщуються в пам'яті такі дані, як стеки, списки, черги, дерева.
4. Підсумки уроку.
5. Домашнє завдання.