У ТР імена об'єктів (змінних та ін.) д. п. визначені до моменту використання їх у програмі. Як зазначалося раніше, ОП персонального комп'ютера має за сегментами структуру. Адреса - сукупність двох 16-ти розрядних слів - сегмента і переміщення. (Наприклад: $0060:$01А0). Сегмент - ділянка пам'яті, що має максимальну довжину 64К (65536 байт). Початковий адреса кожного сегмента кратний 16 (тобто. 0, 16, 32, і т.д.), отже, два сегменти відстані одна від одної, принаймні, на 16 байт. Сегменти адресують пам'ять з точністю до параграфа. Параграф - фрагмент пам'яті дорівнює 16 байт. Зсув - лінійна адресація в сегменті. Вона також має 16-ти розрядні адреси та направляє пам'ять з точністю до байта. При цьому глобальні змінні і типізовані константи розміщуються в сегменті даних. Такі змінні називаються статичними, а пам'ять, виділювана компілятором для їх зберігання називається статичної пам'яттю.
Локальні змінні розміщуються в пам'яті динамічно при активізації підпрограми. Після виконання підпрограми пам'ять звільняється.
Пам'ять, яка виділяється під локальні змінні, називається сегментом стека. Вона задається директивою {$M<розмір пам'яті>}. Мінімальний розмір пам'яті 1К, максимальний 64К, за замовчуванням 16к.
У ТР існує можливість створювати нові змінні в момент роботи програми або знищувати їх у відповідність з вимогами завдання. Такі змінні називаються динамічними.
Для динамічних змінних відводиться динамічна пам'ять, яка має стековую структуру і називається «купою» (хипом - Heap-купа). Розмір хипа задається директивою {$M<розмір пам'яті>}.
Доступ до статичних змінним здійснюється через їх імена.
Доступ до динамічних змінним здійснюється через вказівник на місце їх розташування в пам'яті.
Багато практичні завдання важко або неможливо вирішити без використання динамічної пам'яті. Наприклад, обробки великих масивів обсягів (більш 65536 байт).
Посилальні типи. Покажчики на Паскале
Покажчик - це змінна, яка містить адресу іншої змінної (байти пам'яті).
ТР є два види покажчиків: вказівник на об'єкт деякого типу (типізований) і покажчик, не пов'язаний з типом.
пОписание покажчиків.
Для оголошення типізованих вказівників використовується значок ^, який поміщається перед відповідним типом:
Type T = ^T1;
Var A :T;
де: T - ім'я типу;
T 1 - базовий тип (будь-якої в т.ч. покажчик);
^ - покажчик.
Приклади:
Var
a :byte; {виділення пам'яті для змінної де зберігається її значення}
a ;^byte; {виділення пам'яті для змінної де зберігається її адресу}
Var
p1 :^integer;
p2, p3 :^real;
Для оголошення змінних не пов'язуючи їх, з яким небудь типом даних можна використовувати покажчик без типу (pointer).
Var
:ppointer;
де: pointer - не типізований покажчик, який займає в пам'яті 4 байт (2-байти сегмент, 2байта зсув.).
Операції з покажчиками
Для покажчиків допустимі операції порівняння і присвоювання.
Присвоювання. Вказівником можна присвоїти вміст іншого вказівника того ж самого типу або константу NIL - порожній, або адреса об'єкту за допомогою функції ADDR або оператора @.
Приклад:
P1 := PP;
P2 := NIL;
P3 := Порт(X);
P4 := @X;
Процедури і функції для роботи з покажчиками та адресами в Паскале
Опції:
ADDR(X) - результат POINTER, в якому міститься адреса аргументу. (X-ім'я будь-який змінної, чи процедури функції).
OFS(X):WORD - возвращает значення зсуву адреса об'єкта X.
SEG(X):WORD - повертає значення сегмента адреса об'єкта X.
CSEG(X):WORD - возвращает поточне значення регістра Cs.
DSEG(X):WORD - возвращает поточне значення регістра Ds.
SSEG(X):WORD - возвращает поточне значення регістра Ss.
SPRT(X):WORD - возвращает поточне значення регістра Sp.
PRT(SEG,OFS) - перетворює окремо задані значення сегмента і зміщення
до типу вказівника.
MAXAVAIL:LONGINT - повертає розмір найбільшого безперервного ділянки
купи.
MEMXAVAIL:LONGINT - повертає розмір загального вільного простору купи.
Процедури:
DISPOSE(TP:POINTER) - знищує динамічну змінну і повертає
в купу фрагмент динамічної пам'яті, який був зарезервований
покажчиком.
NEW(TP:POINTER) - резервує фрагмент купи для розміщення змінної.
GETMEM(P:POINTER; ZIZE:WORD) -виділяє з купи блок заданого
розміру та адресу його початку присвоює покажчику.
FREEMEM(P:POINTER; ZIZE:WORD) - звільняє блок заданого
розміру..
MARK(P:POINTER) - запам'ятовує поточну вершину купи (адреса початку
вільного ділянки).
RELEASE(P:POINTER) - звільняє ділянку купи від адреси з P до кінця.
Приклад 19.1. Згенерувати випадковим чином масив випадкових чисел. Розмістити масив в динамічній пам'яті, знайти суму елементів і видалити його з пам'яті.
Текст програми
Program Dinmas;
Uses CRT;
Const k1=100; k2=2*k1+1;
Type
Item = Real;
DinArr = array[1..$FFF0 div SizeOf(Item)] of Item;
DinPrt = ^DinArr;
Var
Arr : DinPrt;
I,N : Word;
S :Real;
f :real;
{$R-}
Begin
ClrScr;
Randomize;
Writeln("Введіть кількість елементів масиву N:");
Readln(N);
{N*SizeOf(Item)-розмір необхідної пам'яті }
GetMem(Arr,N*SizeOf(Item));
Writeln("Уведіть масив X(N):");
For i:=1 to N do
begin
f:=random(k2);
Arr^[i]:=k1-f; Write(Arr^[i]:4:2," ":2)
{ Read(Arr^[i]);};
End;
Writeln;
S:=0;
For i:=1 to N do S:=S+Arr^[i];
Writeln(^G"Підсумок:",^J^^M,G"Сума=",S);
FreeMem(Arr,N*SizeOf(Item));
Repeat Until KeyPressed
End.
Результати роботи програми:
Введіть кількість елементів масиву N:
200
Уведіть масив X(N):
-35.00-82.00 45.00 95.00-26.00-72.00 1.00-77.00 10.00 89.00-38.00
-48.00 8.00 26.00 13.00 33.00 6.00 82.00-63.00-83.00-23.00 39.00
6.00 11.00 48.00 72.00-100.00-2.00 93.00 68.00 73.00 66.00-91.00
6.00 0.00-19.00 94.00 32.00-63.00 59.00 87.00 29.00-93.00-51.00 3
4.00 10.00 58.00 0.00 27.00 41.00 6.00 34.00 55.00-84.00 7.00-37.00
-49.00-6.00 71.00 11.00-47.00-85.00 -53.00 51.00 63.00-80.00 32.
00-71.00-73.00-27.00-15.00-7.00-68.00-89.00 32.00-22.00-86.00
-52.00 27.00-16.00 92.00 19.00 -35.00-8.00-78.00 16.00-94.00 -47
.00-8.00-98.00-96.00-5.00-68.00 37.00 10.00 82.00-32.00 15.00 2
2.00-21.00 11.00 55.00-15.00-54.00-20.00-79.00-15.00-79.00-13.
00-62.00-59.00-93.00-57.00-42.00 57.00 41.00-64.00-43.00-71.00
-66.00 49.00 25.00 66.00 89.00 38.00 98.00-84.00 64.00 71.00-75.00
77.00 83.00 27.00-88.00 49.00-100.00 59.00 29.00-57.00 70.00 33.0
0-87.00-8.00-45.00 23.00 88.00-51.00-66.00 5.00 95.00-28.00 15.
00-1.00-26.00-63.00 37.00-76.00-1.00 96.00-43.00-94.00-29.00
-78.00-99.00 4.00-80.00-43.00-5.00-6.00-13.00-1.00-75.00 80.00
43.00-58.00-31.00 69.00-81.00-71.00-62.00-21.00-84.00 4.00 67
.00-82.00-55.00 25.00-4.00 94.00 75.00-55.00 -15.00-86.00-43.00
-92.00 5.00-81.00-18.00-33.00-71.00
Результат:
Сума=-1.8610000000E+03
Приклад 19.2. Згенерувати випадковим чином матрицю випадкових чисел. Розмістити матрицю в динамічній пам'яті, знайти суму елементів і видалити її з пам'яті.
Текст програми:
Program Dinmas;
Uses CRT;
Type
Item = Real;
DinArr=array[1..$Ff div sizeof(item),1..$ff div sizeof(item)] of Item;
DinPrt = ^DinArr;
Var
Arr : DinPrt;
k,j,l,I,N : Word;
S :Real;
{$R-}
Begin
ClrScr;
randomize;
Writeln("Введіть кількість рядків масиву N:"); Readln(i);
Writeln("Введіть кількість стовпчиків масиву N:"); readln (j);
n:=i*j;
{N*SizeOf(Item)-розмір необхідної пам'яті }
GetMem(Arr,N*SizeOf(Item));
{ Writeln("Уведіть масив X(N):");}
For k:=1 i do to
for l:=1 to j do Arr^[k,l]:=random (2000);
S:=0;
For k:=1 i do to
for l:=1 to j do S:=S+Arr^[k,l];
Writeln(^G"Підсумок:",^J^^M,G"Сума=",S);
FreeMem(Arr,N*SizeOf(Item));
Repeat Until KeyPressed
End.
Результати роботи програми:
Введіть кількість рядків масиву N:
1000
Введіть кількість стовпчиків масиву N:
1000
Результат:
пСумма= 5.7820716634E+32
Приклад 19.3. Розмістити запис у динамічної пам'яті, потім видалити її з пам'яті.
Текст програми:
Program pointer1;
{Робота з динамічною папятью}
Uses crt;
Type
FriendRec = Record
Name : string[30];
Age : Byte;
End;
FrPtr = ^FriendRec;
Var
p : FrPtr;
Begin
ClrScr;
GetMem(p, SizeOf(FriendRec)); {Виділення пам'яті в купі}
Write("Введіть ім'я : "); Readln (^p .Name);
Write("Уведіть вік : "); Readln (^p .Age);
Writeln;
Writeln("Пам'ять для запису про імені і віці розподілена в купі.");
Writeln;
Writeln("Ім'я:",^p .Name);
Writeln("Вік",^p .Age);
Writeln;
FreeMem(p, SizeOf(FriendRec)); {Звільнення пам'яті}
Writeln("Пам'ять, займана записом про імені і віці звільнена.");
Repeat until KeyPressed;
End.
Результати роботи програми:
Введіть ім'я: Іванов Олександр Григорович
Введіть вік: 33
Пам'ять для запису про імені і віці розподілена в купі.
Ім'я: Іванов Олександр Григорович
Вік: 33
Пам'ять, займана записом про імені і віці звільнена.