Міністерство освіти і науки України
НУ „Львівська політехніка”
Кафедра __________
ЗВІТ
Про виконання лабораторної роботи №.....
На тему:________________________________________________________________
________________________________________________________________________
________________________________________________________________________
___________________
(Студент)
___________________
(Група)
___________________
(Керівник лаб. Занятть)
------Львів 200…------
Л а б о р а т о р н а р о б о т а N 10

Вказiвники та динамiчнi структури даних
Метою роботи є вивчення способiв оголошення та використання вказiвникiв для роботи з оперативною пам'яттю.
1. Сегментна органiзацiя пам'ятi

Глобальнi змiннi та типованi константи програми розмiщуються в однiй неперервнiй областi пам'ятi, яка називається сегментом даних. Локальнi змiннi та параметри пiдпрограм зберiгаються у сегментi стека. Стек - це область оперативної пам'ятi, в якiй останнє записане значення буде прочитане першим. Код програми зберiгається у сегментi коду.
Довжина одного сегменту не може перевищувати 64 Кбайти. Сегменти починаються з фiзичної адреси, кратної 16 байтiв. Область пам'ятi розмiром в 16 байтiв називається параграфом. Сегмент адресує пам'ять з точнiстю до параграфа. В загальному випадку програма може мати декiлька сегментiв коду та даних. Сегменти можуть йти один за одним без промiжкiв, з iнтервалами або перекриватися.
Розмiщення у пам'ятi кожного з сегментiв визначається в процесi завантаження програми на виконання. При роботi з вибраними сегментами коду, даних та стека їх адреси зберiгаються вiдповiдно у регiстрах CS, DS та SS. Програма може мати ще додатковий сегмент даних, який адресується регiстром ES.
Для доступу до даних в межах одного сегменту, крiм значення адреси сегменту, необхiдно знати змiщення вiд початку сегменту до потрiбної змiнної. Для сегменту коду таке змiщення визначається значенням регiстру лiчильника команд IP, для сегменту стека - регiстром SP, для сегменту даних - одним з робочих регiстрiв або безпосередньо у командi програми.
Таким чином, логiчна адреса елемента даних задається в програмi у виглядi двох слiв seg:ofs, де seg - сегмент, а ofs - змiщення. У Турбо Паскалi значення адреси можна запам'ятати у змiннiй-вказiвнику.
2. Оголошення та iнiцiалiзацiя вказiвникiв
Вказiвник - це змiнна, яка приймаї значення адреси областi оперативної пам'ятi. Вказiвник пов'язується з деяким типом даних, який визначається при його оголошеннi. Оголошення вказiвника здiйснюється вказанням його базового типу, перед яким йде символ ^ (каре):
type
iм'я_типу_вказiвника=^базовий_тип;
В якостi базового типу може використовуватись довiльний
тип Турбо-Паскаля, наприклад:
type
tptr_i=^integer; {тип-вказiвник на цiлий тип}
tptr_b=^boolean; {тип-вказiвник на логiчний тип}
tptr_c=^char; {тип-вказiвник на символ}
diap=1..10;
tptr_d=^diap; {тип-вказiвник на дiапазон}
enum=(white,red,green,blue,black);
tptr_p=^enum; {тип-вказiвник на перелiковий тип}
tptr_s=^string; {тип-вказiвник на рядок символiв}
arr=array[1..10] of real;
tptr_arr=^arr; {тип-вказiвник на масив дiйсних чисел}
tmas_ptr=array[1..10] of ^real; {тип - масив вказiвникiв
на дiйснi числа}
tptr_rec=^rec1; {тип-вказiвник на запис}
rec1=record
name:string[20];
time:real
end;
Допускається оголошення базового типу даних пiсля оголошення вказiвника на цей тип, як це має мiсце для останнього прикладу.
Для базового типу "запис" можна визначити поле з типом вказiвника на цей же запис, наприклад:
type
tptr_rec1=record
data:real;
next:^tptr_rec1
end;
Така конструкцiя типу використовується для розмiщення в динамiчнiй пам'ятi зв'язаного списку елементiв - рiзного роду динамiчних структур даних.
В Турбо-Паскалi можна оголосити вказiвник, не пов'язуючи його з конкретним базовим типом. Для цього служить ключове слово pointer:
var
p:pointer;
Такi вказiвники називаються нетипованими i використовуються для динамiчного розмiщення даних, структура i тип яких мiняється в ходi роботи програми. Такi вказiвники сумiснi по присвоєнню iз вказiвниками на iншi типи даних.
Оголошення змiнних типу "вказiвник" здiйснюється в блоцi var, наприклад:
var
x:tptr_i;
y:^real;
z:tptr_rec;
Змiнна типу "вказiвник" зберiгається в пам'ятi як подвiйне слово (4 байти). Старше слово визначає сегмент, а молодше - змiщення в межах даного сегменту.
Iнiцiалiзацiя вказiвника може здiйснюватися за допомогою операцiї @, функцiї Ptr, константи nil, процедур New та GetMem.
Наприклад:
var a:byte;
p1,p2,p3,p4:^byte;
{..........}
a:=2;
p1:=@a; {p1 приймає значення адреси змiнної a}
new(p2); {p2 приймає значення адреси iз вiльної областi динамiчної пам'ятi}
p3:=Ptr($40,$49); {p3 приймає значення абсолютної адреси,що задаються значеннями сегменту та змiщення}
p4:=nil; {p4 не вказує нi на який об'єкт}
Вказiвник визначає адресу першого байта пам'ятi, яка вiдводиться пiд змiнну базового типу.
3. Розiменування вказiвникiв
Якщо ptr - змiнна типу "вказiвник на базовий тип", то для доступу до значення, яке знаходиться по визначенiй адресi, необхiдно виконати операцiю "розiменування вказiвника". Дана операцiя заключається в тому, що пiсля iдентифiкатора змiнної-вказiвника записується символ ^ (каре), наприклад:
writeln(p1^); { 2 }
p2^:=4;
Суть операцiї "розiменування" iлюструється наступною схемою:
|---------------------|
ptr------>| ptr^ |
|---------------------|
Для прикладу розглянемо органiзацiю прямого доступу до вiдеопам'ятi для текстового режиму роботи вiдеоадаптера за допомогою типованого вказiвника:
Type VideoArray=array[1..25,1..80] of
record
code,attr:byte
end;
Var V:^VideoArray;
Begin
V:=Ptr($B800,$0);
V^[10,20].code:=65;
V^[10,20].attr:=$5A;
End.

При застосуваннi операцiї "розiменування" до вказiвникiв типу pointer необхiдно здiйснити явне перетворення типу, наприклад:
Type float=real;
Var p:pointer;
x:real;
Begin
x:=Pi;
p:=@x;
writeln(REAL(p^):5:2) { 3.14}
writeln(FLOAT(p)^:5:2) { 3.14}
End.
Оскiльки в якостi базового типу вказiвника може бути довiльний тип, то можна сформувати вказiвник на вказiвник, наприклад:
type
p1:^byte;
p2:^p1;
var x:p2; {x визначає адресу адреси даних з базовим типом byte}
Тодi для доступу до значення базового типу byte можна використати наступну операцiю розiменування: x^^, принцип дiї якої демонструється наступною схемою:
|----------| |- --------|
x----->| x^ |----->| x^^ |
|---------| |---------|
адреса адреса значення
адреси
Завдання для роботи: Сформуйте однонаправлений кiльцевий список елементiв типу char та оформiть у виглядi процедур наступнi операцi¦ над ним:
а) виключити iз списку повторнi входження одного й того ж елемента;
б) подво¦ти кожен елемент списку.
Текст програми: