Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции_Паскал.doc
Скачиваний:
2
Добавлен:
21.09.2019
Размер:
1.21 Mб
Скачать

Сумісність і перетворення посилкових типів

Усі посилкові типи вважаються різними відповідно до загальних правил. Так наприклад, два типи, оголошені як

type

TP1 = ^integer,

TP2 = ^real;

визначають неспівпадаючі множини значень, хоча фізична природа посилкових типів у всіх випадках це адреси в оперативній пам'яті. Тому наступні змінні:

var

P1 : TP1; P2 : TP2;

не можуть передавати один одному значення (наприклад, у присвоюванні). Для посилкових змінних одного типу, зрозуміло, припустимі подібні дії, наприклад:

var

P1, P2 : TP1;

begin

P1 := P2;

Для посилкових типів, так само, як і для скалярних типів, допускаються конструкції явного перетворення. Нехай маються наступні описи:

type

R = record

Hi, Lo : word

end;

PR = ^R;

PL = ^longint;

var

VI : PR; V2 : PL; X : longint;

Змінні VI і V2 є покажчиками на значення різних типів, однак за допомогою конструкції приведення їх можна трактувати як покажчики на той самий тип; наприклад, можливі наступні оператори:

PR(V2)^.Нi := 5;

PL(V1) := @Х; X := PL(V1)^;

Перший оператор перетворить покажчик на довге ціле в покажчик на комбінований тип і використовує його в такій якості для присвоювання значення старшим розрядам числа, на яке посилається V2.

Два наступних оператори, навпаки, інтерпретують запис як іншу форму представлення довгого цілого, присвоюючи покажчик на тип longint покажчику на комбінований тип і поміщаючи значення запису в довге ціле.

Помітимо, що в подібних перетвореннях базові типи покажчиків можуть мати різні розміри; ніяких перевірок на цей рахунок не робиться. Наприклад, для наступного фрагмента:

type

PB = ^byte;

PS - ^string;

var

P1 : PB;

P2 : PS;

В: byte;

begin

P1 := @B;

синтаксично коректної є змінна виду PS(Pl)^[10] яка має тип char як 10-ий елемент рядка, на яку посилається покажчик PS(Pl). Однак, у цій якості дана змінна не зв'язана ні з якою статичною (оголошеною в програмі) змінною, ні з динамічною змінною; P1 посилається на один байт у пам'яті (змінну в), а покажчик PS(P1) - на область з 256 елементів, початок який збігається з адресою змінної В; ця область ні автоматично, ні явно не була виділена програмі, її вміст не визначений, однак мається можливість, власне кажучи, довільного доступу до неї описаним способом. Тому використовувати перетворення посилкових типів потрібно з відомою обережністю і тільки якщо це дійсно необхідно; у будь-якому випадку варто уникати формування покажчиків на області пам'яті, характер умісту яких невідомий.

Динамічні структури даних

Повернемося тепер до питання про економію пам'яті при збереженні табличних даних. З використанням покажчиків можна відмовитися від масиву і використовувати динамічні структури. Найпростіший з них є список, що схематично зображується так:

Прямокутники на цій схемі — динамічні змінні типу запис, Data ( поле (чи поля), що містять корисну інформацію (наприклад прізвища і номери телефонів), поле, що зображене нижче Data — це покажчик на наступну запис. Змінна List також є покажчиком на запис. Жирна крапка в поле «наступний елемент» у самому останньому записі означає, що там лежить значення nil, щоб показати, що цей запис останній в списку.

Для опису списку на Паскалs досить описати тип покажчика на запис і тип самого запису. Виглядає все це так:

type tItemPtr = ^tItem; {покажчик на елемент}

tItem = record

Data: tData; {корисні дані}

Next: tItemPtr; {покажчик на наступний елемент списку}

end;

Оголосити сам список можна як покажчик на елемент:

var List : tItemPtr;

поки наш список порожній, List варто пприсвоїти значення nil. При створенні першого елемента будемо виконувати дії New(List); List^.Next:=nil.

У списках завжди зберігається рівно стільки елементів, скільки потрібно; якщо який-небудь елемент даних утратив свою цінність, то його завжди можна видалити зі списку; якщо з'явилися нові дані, то можна додати новий елемент.

Напишемо тепер модуль для роботи зі списками. У ньому містяться процедури первісної підготовки списку; додавання елемента в початок списку; видалення елемента, що стоїть за зазначеним; пошук елемента з заданим номером; підрахунку елементів і очищення списку.

unit Lists;

interface

type tData = record

Name: string[50];

Phone: longint;

end;

tItemPtr = ^tItem;

tItem = record

Data: tData;

Next: tItemPtr;

end;

procedure InitList(var l: tItemPtr);

procedure AddItemToHead(var l: tItemPtr; d: tData);

function DeleteItemAfter(var l: tItemPtr; num: word): boolean;

function Count(l: tItemPtr): word;

function GetItem(l: tItemPtr; num: word; var d: tData): boolean;

procedure ClearList(var l: tItemPtr);

{---------------------------------------------------------------}

implementation

procedure InitList(var l: tItemPtr);

begin l:=nil end;

procedure AddItemToHead(var l: tItemPtr; d: tData);

var p: tItemPtr;

begin

new(p);

p^.data:=d;

p^.next:=l;

l:=p;

end;

function DeleteItemAfter(var l: tItemPtr; num: word): boolean;

var p,q: tItemPtr;

i: word;

begin

i:=1;

p:=l;

while (i<>num)and(p<>nil) do begin

i:=i+1;

p:=p^.next;

end;

if p<>nil then begin

if p^.next<>nil then begin

q:=p^.next^.next;

dispose(p^.next);

p^.next:=q;

DeleteItemAfter:=true;

end

else DeleteItemAfter:=false; {не вилучений}

end

else DeleteItemAfter:=false;

end;

function Count(l: tItemPtr): word;

var p: tItemPtr;

i: word;

begin

i:=0;

p:=l;

while p<>nil do begin

i:=i+1;

p:=p^.next;

end;

count:=i;

end;

function GetItem(l: tItemPtr; num: word; var d: tData): boolean;

var p: tItemPtr;

i: word;

begin

i:=1;

p:=l;

while (i<>num)and(p<>nil) do begin

i:=i+1;

p:=p^.next;

end;

if p<>nil then begin

d:=p^.data;

GetItem:=true;

end

else GetItem:=false;

end;

procedure ClearList(var l: tItemPtr);

var p: tItemPtr;

begin

while (l<>nil) do begin

p:=l^.next;

dispose(l);

l:=p;

end;

end;

end.