Міністерство освіти і науки України НУ „Львівська політехніка” Кафедра __________ ЗВІТ Про виконання лабораторної роботи №..... На тему:________________________________________________________________ ________________________________________________________________________ ________________________________________________________________________ ___________________ (Студент) ___________________ (Група) ___________________ (Керівник лаб. Занятть) ------Львів 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 входження одного й того ж елемента; б) подво¦ти кожен елемент списку. Текст програми: