Б С Бусигін - Прикладна інформатика - страница 49

Страницы:
1  2  3  4  5  6  7  8  9  10  11  12  13  14  15  16  17  18  19  20  21  22  23  24  25  26  27  28  29  30  31  32  33  34  35  36  37  38  39  40  41  42  43  44  45  46  47  48  49  50  51  52  53  54  55  56  57  58  59  60  61  62  63  64  65  66  67  68  69  70  71  72  73  74  75  76  77  78  79  80  81  82  83 

Var

X  : String;

p,  q : Pointer;

p:=Addr(X);

q :=@X;  {Тепер p=q , тобто їх адреси рівні: вони вказують на один й той же об'єкт}

Як Ви вже знаєте, значення типу Pointer не може бути виведено на екран. Але оскільки цей тип складається з двох слів (Word), які зберігають сегмент та зсув, їх можна вивести поодинці, використовуючи функції Seg та Ofs (обидві типу Word):

34б

WriteLn('Сегмент        Seg(p),   ' смещение Ofs(p));

Функція Ptr(Seg, Ofs : Word) виконує протилежну функції Addr(X) роботу: вона організовує посилання на місце у пам'яті яке визначене заданим сегментом та зсувом. Необхідність у такій функції може виникати, коли потрібно наложити динамічну структуру на системну область пам'яті. Так, наприклад, відомо, що образ текстового екрану починається з адреси SBGGGiSGGGG й займає 4 000 байт (кольоровий та чорно-білий режими, 80 стовпців на 25 строк), то можна "наложити" на нього якусь структуру, наприклад, масив, використовуючи посилання на такий масив та функцію Ptr

(рис. 8.92):

VideoArray = Array[0..3999]   of Byte;

Var

V :  AVideoArray; {Посилання на структуру}

Begin

V:=Ptr($B000,  0); {Далі VA[i] звертається безпосередньо до ячеєк

відеопамяті у текстовому режимі}

Функція SizeOf (X) : Word повертає об'єм у байтах, який займає об'єкт X. Причому X може бути не тільки змінною, але й ідентифікатором типу (рис. 8.93):

Program ObjectSizeOf; Type

XType = Array  [1..10,1..10]   of Byte;

Const

L  :  LongInt = 123456; Var

X  : String;

Begin

WriteLn('Xtype =', SizeOf(XType):5,

Type

End.

Рис. 8.92. Використання функції Ptr(Seg,Ofs  : Word)

L

X , SizeOf(L):5, ',SizeOf(X));

ReadLn

End.

Результат:

Xtype = 100

L 4

X 256

Рис. 8.93. Використання функції SizeOf (X)   : Word

Значення SizeOf( строка) завжди дає максимальне значення довжини строки. Реальне значення дає функція Legth.

8.27.5. Посилальні змінні

Усі посилальні змінні мають однаковий розмір, рівний 4-м байтам, і містять адреса початку ділянки оперативної пам'яті, у якому розміщена конкретна динамічна структура даних (Integer, Array, Record і т.ін.), наприклад:

Var

J :  AInteger; {Посилальна змінна, що указує на ціле значення} I  :  Integer; {Ціла змінна}

J  := 2 0 0;

I := 200;

Різниця між цілою змінною I (рис. 8.94, а) та посилальною змінною J на цілу змінну полягає у наступному (рис. 8.94, б):

J - адреса, де міститься адреса

200

1

адреса, де міститься значення 200 у форматі: <СЕГМЕНТ> : <ЗСУВ>

і

значення

200

б)

Рис. 8.94. Зміст даних різного типу I та J Щоб посилання ні на що не вказувало, йому привласнюється значення

Nil:

J := nil;

Це визначена константа типу Pointer, що відповідає адресі 0000:0000. Підсумовуючи усе вищесказане можемо зробити висновок, що для визначення посилальної змінної у ТП потрібно описати її як посилальний тип:

348

I - адреса, де міститься значення

200

1

значення

200

а)

Type

Ім'яПосилальногоТипу = лІм'яБазовогоТипу; {Де Ім'яБазовогоТипу - будь-який ідентифікатор типу (Real, Integer і т.д.), це потрібно компілятору ТП для організації роботи програми}

У результаті цього визначення створювані потім посилальні змінні будуть указувати на об'єкти базового типу, визначаючи тим самим динамічні змінні базового типу:

Type {БАЗОВІ ТИПИ}

DimType = Array  [1..10000]  of Real; {Масив} RecType = record ...  end; {Запис}

{ ПОСИЛАЛЬНІ ТИПИ }

IntPtr = AInteger;  {Посилання на ціле значення} Dim Ptr = ADimType;  {Посилання на масив даних} RecPtr = ARecType;  {Посилання на запис} XXXPtr = Pointer;  {Посилання «узагалі» - указник}

8.27.6. Операція розіменування

Суть цієї операції складається в переході від посилальної змінної через адресу, на яку вона посилається до значення, на яке вона вказує. При цьому слідом за посилальною перемінною указується символ "A":

Var

I,  J  : AInteger;

I:=2; J:=4;

JA:=IA;  {Копіюємо вміст I у J. Зараз указує на 2 (рис. 8.95, а)} J:=I;  {Або можна так: I і J тепер теж указують на 2 (рис. 8.95, б)}

Але ці операції виконуються компілятором ТП по різному (рис. 8.95, а, б).

Ячейка зі значенням 4 перетворюється у «сміття», оскільки до неї тепер немає доступу.

Посилальні змінні і указники сумісні між собою по типу, тобто немає помилки в присвоюванні

DimPtr  := RecPtr;

Але після розіменування починається контроль типів об'єктів по зазначених адресах:

DimPtrA := RecPtrA; {Дає помилку!!!}

J

J

= <адрес 2>

4

2

4

JA = <адрес 4>

іа := JA;

а)

і := J;

б)

J

J

Рис. 8.95. Операції розіменування

Розіменовані посилання на структури (масиви) індексуються або розділяються на поля запису звичайним образом:

DimPtrA[i] - доступ до елемента I динамічного масиву ЯесРтіЛПоле - доступ до поля динамічного запису

8.27.7. Розміщення динамічних змінних. Процедури New і GetMem

Розміщення динамічних змінних у ТП виконується процедурами New(Var

P:  Pointer) і GetMem(Var P:  Pointer) (табл. 52).

Таблиця 52.

Процедури розміщення динамічних змінних

Процедури і функції

Призначення

New(Var P :  Pointer) або Ме\^(ТипПосилання)   : Pointer

Відводить місце для збереження динамічної змінної PA і привласнює її адресу посиланню P

GetMem(Var P: Pointer; Size  : Word)

Відводить місце в Size байт у купі (Heap), присвоюючи адресу його початку указнику (посиланню) P

Як Ви вже знаєте, у ТП мається спеціальний не типізований указник Pointer. Він оголошується стандартним образом:

Var

X  : Pointer;

2

I

I

2

2

2

I

I

4

Не типізованому указнику може бути призначене значення будь-якого типізованого указника або навпаки. Він виконує роль своєрідного буфера для збереження адреси динамічної змінний будь-якого типу. Нехай маємо:

Type

IntPtr = AInteger; {Посилання на ціле значення}

Var

P    :    IntPtr;   {Посилальна змінна типу IntPtr, що визначає

посилання на ціле число}

Тоді при виклику

New(P); Або

P:=New(IntPtr);

У купі виділяється блок пам'яті розміром SizeOf (Integer) тобто 2 байти й адреса першого байта цього блоку запишеться у P. Після виконання New можна вже посилатися на динамічну змінну PA.

Окрім того, можна виклик New (P) замінити на GetMem (P, SizeOf (Ім'яБазовогоТипу_Р)), де SiZeOf (X) - стандартна функція ТП, що повертає розмір у байтах базового типу.

Процедура GetMem призначена для виділення пам'яті указникам:

Var

P :  Pointer; {Оголошуємо указник}

Begin

GetMem   (P,   4*1024);   {Тепер P указує на блок пам'яті в купі

розміром 4Кб. PA не має типу, але містить 4096 байт}

End.

8.27.8. Звільнення динамічних змінних. Процедури Dispose і FreeMem

Для звільнення пам'яті, яку займає динамічна змінна P, використовується процедура Dispose (Var P: Pointer) . Ця процедура працює тільки з типізованими посилальними змінними (табл.. 53). Для коректної роботи Ви завжди повинні робити виклики Dispose парними викликам New. Після виклику процедури значення посилання P не визначене, як і значення розіменування PA.

Таблиця 53.

Процедури і функції

Призначення

Dispose   (Var P: Pointer)

Знищує зв'язок, створений раніше New, між посиланням Р і значенням, на яке вона посилається

FreeMem  (Var P: Pointer; Size  : Word)

Звільняє Size байт у купі, починаючи з адреси, записаної в указнику (посиланні Р)

Для звільнення безупинних ділянок пам'яті заданого розміру потрібно використовувати процедуру

FreeMem  (Var P  :  Pointer;  Size  : Word)

Виклики FreeMem, як і Dispose, повинні бути парні викликам GetMem. Значення посилальної змінної Р після виклику FreeMem вважаються невизначеними.

8.27.9. Поєднуємо разом поняття Record і динамічних змінних: рішення задачі по створенню динамічних структур типу

"черга"

Найбільш важливим аспектом програмування з використанням динамічних структур даних є стекові структури, однозв'язкові і двозв'язкові списки, черги, двоїчні дерева і т.д. Для програмної підтримки всіх цих структур можна застосовувати масиви, але при ближчому розгляді стає очевидним, що або необхідно описувати досить великі масиви з відомою надмірністю, або, у випадку визначення свідомо малих масивів, область прикладного застосування програми буде обмежена. Альтернативою масивам служать указники у сполученні зі структурою Record, у яку включають інформаційну частину й указник на наступну структуру Record. Їхня перевага полягає як у тім, що вони дозволяють створювати динамічні структури необхідної розмірності, так і в тім, що ми одержуємо можливість оперувати великими об'єктами за допомогою усього лише 4-байтних указників.

Страницы:
1  2  3  4  5  6  7  8  9  10  11  12  13  14  15  16  17  18  19  20  21  22  23  24  25  26  27  28  29  30  31  32  33  34  35  36  37  38  39  40  41  42  43  44  45  46  47  48  49  50  51  52  53  54  55  56  57  58  59  60  61  62  63  64  65  66  67  68  69  70  71  72  73  74  75  76  77  78  79  80  81  82  83 


Похожие статьи

Б С Бусигін - Прикладна інформатика