Студопедия
Новини освіти і науки:
МАРК РЕГНЕРУС ДОСЛІДЖЕННЯ: Наскільки відрізняються діти, які виросли в одностатевих союзах


РЕЗОЛЮЦІЯ: Громадського обговорення навчальної програми статевого виховання


ЧОМУ ФОНД ОЛЕНИ ПІНЧУК І МОЗ УКРАЇНИ ПРОПАГУЮТЬ "СЕКСУАЛЬНІ УРОКИ"


ЕКЗИСТЕНЦІЙНО-ПСИХОЛОГІЧНІ ОСНОВИ ПОРУШЕННЯ СТАТЕВОЇ ІДЕНТИЧНОСТІ ПІДЛІТКІВ


Батьківський, громадянський рух в Україні закликає МОН зупинити тотальну сексуалізацію дітей і підлітків


Відкрите звернення Міністру освіти й науки України - Гриневич Лілії Михайлівні


Представництво українського жіноцтва в ООН: низький рівень культури спілкування в соціальних мережах


Гендерна антидискримінаційна експертиза може зробити нас моральними рабами


ЛІВИЙ МАРКСИЗМ У НОВИХ ПІДРУЧНИКАХ ДЛЯ ШКОЛЯРІВ


ВІДКРИТА ЗАЯВА на підтримку позиції Ганни Турчинової та права кожної людини на свободу думки, світогляду та вираження поглядів



Стан покажчика

Для покажчика, після того як він оголошений у розділі опису змінних, можливі три стани. Покажчик може містити адресу деякої змінної, "порожній” адресу NIL або мати невизначений стан. Перший випадок пояснень не потребує. В другому випадку, коли потрібно, щоб покажчик нікуди не вказував, йому присвоюється спеціальне значення NIL. Що ж стосується невизначеного стану, то воно має місце відразу після початку роботи програми (до того як покажчику буде присвоєна яка-небудь адреса в пам'яті чи значення NIL), або після звільнення пам'яті, на яку даний покажчик посилається.

Якщо когось бентежить "покажчик, який нікуди не вказує", то це можна представити як посилання на область пам'яті, у якій ніяка інформація ніколи не розміщується. Значення NIL — це константа, яку можна присвоїти будь-якому покажчику.

Може виникнути питання, у чому різниця між невизначеним станом покажчика і випадком, коли його значення дорівнює NIL? Оскільки NIL— значення конкретне, хоча і нікуди що не вказує, можна сказати, що два покажчики, що містять NIL, мають рівні значення. У той же час значення двох покажчиків у невизначеному стані рівними визнати не можна.

Установка розмірів динамічної пам'яті

Як уже говорилося, більшість реальних прикладних програм активно використовують динамічні змінні. Це зв'язано як з великою гнучкістю цього механізму, так і з чуттєвим для великих програм обмеженням на загальний об’єм статичних змінних. За замовчуванням для купи виділяється весь об’єм наявної оперативної пам'яті, доступній операційній системі, за винятком пам'яті для коду програми і статичних змінних. Таким чином, розмір динамічної пам'яті може досягати 400K і більш. Однак у ряді випадків такий об’єм є надлишковим чи навіть неприпустимим (зокрема, Pascal-програма, що займає всю оперативну пам'ять, не в змозі здійснити виклик якої-небудь іншої програми, розміщеної в окремому Ехе-файлі). Крім того, деякі програми можуть узагалі не використовувати динамічну пам'ять.

Сказане визначає необхідність засобів керування розмірами динамічної пам'яті, використовуваною програмою. У мові Turbo Pascal для цього служить директива компілятора $M. Ця директива повинна розташовуватися на початку тексту програми і має три цілочисельних параметри, що повинні розділятися комами. Перший параметр визначає максимальний розмір пам'яті, що виділяється під стек локальних змінних, а два наступних параметри задають мінімальний і максимальний розміри динамічної пам'яті.

Приклади директиви $M:

{$M 10240,0,200000}

{$M 16384,1024,650000}

{$M 1024,0,0}

Завдання мінімального розміру динамічної пам'яті (другий параметр) носить обмежувальний характер і встановлює той об’єм необхідної пам'яті, при відсутності якого програма взагалі НЕ МОЖЕ ВИКОНУВАТИСЯ. Якщо цей параметр є 0, то програма буде запущена в будь-якому випадку.

Третій параметр задає максимальний розмір потрібної динамічної пам'яті і носить рекомендаційний характер. Іншим словами, розмір динамічної пам'яті буде визначатися перед початком роботи програми виходячи з реальної наявності вільної оперативної пам'яті, але не буде перевищувати зазначений у цьому параметрі об’єм. Якщо при запуску програми в оперативній пам'яті знаходяться які-небудь програми (наприклад, резидентна частина системи Norton Commander) чи запуск виконується з інтегрованого середовища Turbo Pascal, що саме має досить значний розмір, то реальний об’єм динамічної пам'яті, відведеної програмі, може бути менше замовленого.

За замовчуванням передбачається наявність директиви

{$M16384,0,655360}

тобто під стек виділяється l6K байт, під динамічну пам'ять - уся вільна оперативна пам'ять, доступна операційній системі.

Варто мати на увазі, що, крім директиви $M у тексті програми, можна установити обговорювані розміри за допомогою альтернативи Options/Memory Sizes в інтегрованому середовищі чи передавати їх як параметри при виклику компілятора командного рядка.

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

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

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;




Переглядів: 859

<== попередня сторінка | наступна сторінка ==>
Покажчики | Визначення й описи структур даних

Не знайшли потрібну інформацію? Скористайтесь пошуком google:

  

© studopedia.com.ua При використанні або копіюванні матеріалів пряме посилання на сайт обов'язкове.


Генерація сторінки за: 0.017 сек.