Читайте также: |
|
Динамічні структури даних
Незв’язані динамічні дані
Дані, які використовуються у програмі, поділяються на статичні й динамічні.
Статичні структури даних розміщуються у статичній пам’яті, виділеній компілятором у процесі компіляції програми. Їх взаємне розміщення, взаємозв’язки елементів і кількість завжди залишаються сталими в процесі виконання програми.
Динамічні структури даних розміщуються у динамічній пам’яті, яка виділяється на етапі виконання програми. Їх внутрішня побудова формується за деяким законом, а їх взаємне розміщення, взаємозв’язки елементів і кількість можуть динамічно змінюватися в процесі виконання програми. Для роботи з динамічними даними використовуються вказівники.
ОПИС ЗМІННИХ-ВКАЗІВНИКІВ
<Ім’я змінної-вказівника>:^тип динамічної змінної
Наприклад, a:^integer; b:^real;
Щоб змінити значення динамічній змінній, на яку вказує деяка змінна-вказівник z, необхідно виконати команду:
z^:=<значення> (z – це змінна вказівник, а z^ - динамічна змінна, на яку вказує вказівник z).
Щоб змінити значення змінної-вказівника z (направити її на іншу динамічну змінну) необхідно:
z:=<деякий вказівник на іншу динамічну змінну>
Вказівник – це статична змінна, значенням якої є адреса пам’яті. За допомогою вказівників можна розміщувати в динамічній пам’яті будь-які типи даних (цілі, дійсні, логічні, символьні, символьні рядки, масиви, записи та інші). Вказівники, які вказують на конкретний тип даних називаються типізованими. Для опису типізованого вказівника використовується знак ^, який записується перед відповідним типом даних. Наприклад,
Type Tank = record
p, i, b: string[15];
rn: word;
ps: string[20];
end;
Var v1, s1: ^integer;
v2: ^real;
v3: ^Tank;
Тут v1, s1 вказівники на дані цілого типу, v2 вказівник на дані дійсного типу, а v3 вказівник на дані типу запис.
Можна описати вказівник і не зв’язувати його з конкретним типом даних. Для цього є стандартний тип pointer, наприклад,
Var p1, p2: pointer;
такі вказівники називають не типізованими. З їх допомогою зручно працювати з динамічними даними, структура і тип яких змінюється при виконанні програми.
Значеннями вказівників є адреси змінних, розміщених у динамічній пам’яті. Для них допустима операція присвоєння, якщо вони вказують на один і той же тип даних та типізованому вказівнику можна присвоювати значення не типізованого, а навпаки недопустимо. Наприклад, v1:=s1; p1:=p2; s1:=p1; – допустимі присвоєння, а v1:=v2 і p1:=v3; – недопустимі.
Для звернення до даних, на які вказує вказівник, за його іменем зразу ставиться знак ^. Наприклад,
v1^:=5; або s1^:=v1^.
Вказівник може бути у трьох станах:
· помічений зарезервованим словом NIL (не вказує ні на які дані).
ВИДІЛЕННЯ ПАМ’ЯТІ ПІД ДИНАМІЧНУ ЗМІННУ
Оскільки динамічна змінна не має імені (а отже не описується в блоці var), то на початку роботи програми пам’ять під дану змінну не виділяється. А відповідна змінна-вказівник ні нащо не вказує. Коли змінна-вказівник ні нащо не вказує, то говорять, що вона вказує на nil.
Щоб виділити пам’ять, необхідно виконати процедуру new(x), де х – змінна-вказівник.
Після виконання даної процедури (new(x)) вказівник x буде вказувати на комірку пам’яті відповідного типу.
Наприклад,
Var x:^integer;
Begin
……..
New(x);
…….
End.
ЗМІНЕННЯ ЗНАЧЕНЬ ДИНАМІЧНИХ ЗМІННИХ
ТА НАПРЯМКІВ ЗМІННИХ-ВКАЗІВНИКІВ
Змінити значення динамічної змінної (нехай на неї вказує вказівник а) можна використовуючи вказівку:
a^:=<значення>
Щоб змінити напрям вказівника а необхідно:
a:=<інша змінна-вказівник>
Нехай на якомусь етапі роботи програми вказівник a вказує на деяку динамічну змінну, що містить число 5, а b на іншу змінну, що містить число 10.
Після виконання вказівки a^:=10 (або a^:=b^) напрям вказівника a не змінюється, змінюється значення динамічної змінної (в нашому випадку зміниться значення змінної за адресою 1: замість 5 там буде міститися 10).
Якщо ж замість a^:=b^ записати a:=b, то напрям вказівника a змінюється. Змінна-вказівник a буде вказувати на ту ж змінну, що і вказівник b. Тепер значення динамічної змінної, що знаходиться за адресою 2 можна змінити двома способами: використовуючи вказівник a та вказівник b.
Після виконання вказівок:
a:=b;
a^:=100;
b^:=15;
edit1.text:=inttostr(a^);
на екрані буде число 15 (а не 100)
Приклад 1. Демонструє зміну напрямків вказівників на дві незалежні динамічні змінні.
var a,b,c:^integer;
begin
new(a);
new(b);
a^:=strtoint(edit1.Text);
b^:=strtoint(edit2.Text);
c:=a;
a:=b;
b:=c;
edit3.Text:=inttostr(a^);
edit4.Text:=inttostr(b^);
end;
Результат роботи програми:
1 2
2 1
В даній програмі використовується лише дві динамічні змінні (дві комірки пам’яті)
Приклад 2. Демонструє перестановку двох динамічних змінних з використанням третьої.
var a,b,c:^integer;
begin
new(a);
new(b);
new(c);
a^:=strtoint(edit1.Text);
b^:=strtoint(edit2.Text);
c^:=a^;
a^:=b^;
b^:=c^;
edit3.Text:=inttostr(a^);
edit4.Text:=inttostr(b^);
end;
Результат роботи програми:
1 2
2 1
В даній програмі використовується три динамічні змінні (три комірки пам’яті). Вона працює повністю аналогічно як у випадку із звичайними статичними змінними.
Приклад 1 ефективніший за приклад 2, бо
По-перше, використовується дві комірки пам’яті;
По-друге, вміст комірок пам’яті не змінюється.
Проаналізуйте наступну програму:
var i,p:^integer;
begin
new(p);
new(i);
p^:=5;
i^:=1;
Label1.Caption:='p->'+inttostr(p^)+' i->'+inttostr(i^);
i:=p;
Label2.Caption:='p->'+inttostr(p^)+' i->'+inttostr(i^);
p^:=10;
Label3.Caption:='p->'+inttostr(p^)+' i->'+inttostr(i^);
i^:=15;
Label4.Caption:='p->'+inttostr(p^)+' i->'+inttostr(i^);
end;
Результат роботи програми:
p -> 5 i -> 1
p -> 5 i -> 5
p -> 10 i -> 10
p -> 15 i -> 15
Якщо вказівку i:=p змінити на i^:=p^, то результат програми буде наступним:
p -> 5 i -> 1
p -> 5 i -> 5
p -> 10 i -> 5
p -> 10 i -> 15
Вся динамічна пам’ять розглядається як суцільний масив байтів, який називається купою. Для виділення і звільнення динамічної пам’яті використовуються процедури:
· Procedure New (Var P: Pointer); – резервує фрагмент купи динамічної пам’яті для розміщення змінної і записує в типізований вказівник P адресу першого байта.
· Procedure Dispose (Var P: Pointer); – повертає в купу фрагмент динамічної пам’яті, який був зарезервований за типізованим вказівником P. Якщо вказівник P невизначений, то фіксується помилка.
· Procedure GetMem (Var P: Pointer; Size: Integer); – резервує за не типізованим вказівником P фрагмент динамічної пам’яті розміру Size (в байтах) і присвоює йому адресу цієї області.
· Procedure FreeMem (Var P: Pointer; Size: Integer); – повертає в купу фрагмент динамічної пам’яті, який був зарезервований за не типізованим вказівником P. Звільняти потрібно такий розмір пам’яті, який був виділений.
Розрізняють незв’язані і зв’язані динамічні дані. Незв’язані динамічні дані аналогічні статичним, тільки вони можуть з’являтися і зникати під час виконання програми. Розглянемо приклад моделювання масиву зі змінною верхньою межею.
Дата добавления: 2015-10-26; просмотров: 125 | Нарушение авторских прав
<== предыдущая страница | | | следующая страница ==> |
Размещение объектов (полей формы) на HTML-странице. | | | Зв’язані динамічні дані |