Реферати

Реферат: Object Pascal

Поема "Кому на Русі жити хорошо"- вершина творчості Н. А. Некрасова. Вінцем творчості великого російського поета Некрасова є його поема "Кому на Русі жити добре". Почавши писати її в 1863 році, він працював протягом 15 років, до самої своїй смерті, так і не завершивши роботу.

Мікроскопічне дослідження деревини і целюлозних волокон. Виробництво волокнистих напівфабрикатів у паперовій промисловості. Основні методи анатомічного аналізу деревних тканин і целюлозних волокон. Мікроскопічне дослідження зрізів деревини хвойних і листяних порід, а також целюлозних волокон.

Технологія монтажу баштових кранів. Вантажопідйомні машини, що характеризуються повторно-короткочасним режимом роботи. Баштові крани, їхні види, область застосування, компонування і способи монтажу. Конструктивні елементи. Нарощування за допомогою монтажної щогли. Схеми подращивания колон.

Научение і пам'ять. Прості форми научения і їх нейронная основа. Системи головного мозку і пам'ять. Гиппокамп і мигдалини. Медиаторние системи. Нейропептиди. Білковий синтез. Система пам'яті в людини. Короткочасна і довгострокова пам'ять. Консолідація слідів пам'яті.

Психологія груп і типи міжособистісних конфліктів. Види груп і їхня психологічна характеристика, особливості взаємодії учасників усередині групи. Основні типи міжособистісних конфліктів і характер їхнього розвитку. Визначення понять "конфабуляция", "сприйняття", "мислення", "конформность", "сугестія".

1. Основи мови Object Pascal

1.1. Алфавіт мови

Основними символами мови Object Pascal є:

- символи _ + -

- 26 великих і 26 малих латинських букв А, В,. . Y,. Z, a, b,. .., у, z

- 10 арабських цифр 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,

- спеціальні символи * / = ^ < > () [ ] { }. ,: ; ' # $ @

Букви російського алфавіта не входять до складу алфавіта мови. Їх використання допустиме тільки в рядкових і символьних значеннях.

Немає відмінностей при використанні великих і малих букв в записі імен змінних, процедур, функцій і міток. Їх максимальна довжина обмежена 126 символами.

1.2. Короткі відомості про структуру програми

Програма, написана в середовищі Delphi за допомогою мови Object Pascal, завжди складається з декількох модулів. Як мінімум таких модулів повинне бути два. Один модуль завжди є головною програмою і має назву program. Інші модулі грають допоміжну і залежну від головної програми або від інших модулів роль і називаються unit. Мінімально структурована програма має один модуль program і один модуль unit. Серйозні програми крім модуля program можуть містити до декількох десятків авторських модулів unit і велика кількість посилань на фірмові або розроблені як самим автором, так і іншими розробниками модулі unit.

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

Початковий програмний текст кожного модуля складається на мові Object Pascal і вміщується в окремий файл, який завжди має розширення. pas. Текст модуля program має розширення. dpr.

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

1.3. Лексична структура мови

Будівельним матеріалом для конструювання програмного тексту модуля є лексеми - особливі язикові конструкції, що мають самостійне значення. Лексеми будуються за допомогою символів алфавіта мови. У Object Pascal розрізнюють наступні основні класи лексем:

Зарезервовані (службові) слова. Цей клас складається з слів, побудованих тільки за допомогою букв алфавіта. Службові слова можна використати тільки за прямим призначенням, т. е. так, як їх призначення визначив розробник мови. Ні в якому іншому вигляді, наприклад як імена змінні, їх використати не можна.

Нижче представлений список таких слів:

And

asm

class

destructor

do

end

file

for

if

inherited

interface

library

not

or

procedure

raise

resource

shl

then

try

until

while

with

array

begin

const

dispose

downto

except

finalization

function

implementation

initialization

in

interface

is

mod

object

out

program

record

string

shr

threadvar

type

uses

as

case

constructor

div

else

exports

finally

goto

in

line

label

nil

of

packed

property

repeat

set

string

to

unit

var

xor

Крім того, не можна використати наступні слова, не належні до цього класу: private, protected, public, published, automated, directives, on, virtual.

Ідентифікатори (імена). Ідентифікатори або імена призначені для позначення констант, змінних, типів, процедур, функцій, міток. Вони формуються з букв, цифр і символа "_" (підкреслення). Довжина імені може бути довільною, однак компілятор враховує імена по його перших 63 символах. Всередині імені не повинно бути пропусків.

Object Pascal в іменах не розрізнює великих і малих букв. Так наступні імена будуть ідентичні:

SaveToFile, SAVETOFILE, savetofile, sAVEtOfILE.

Серед програмістів встановилося хороше правило, відповідно до якого імена формуються таким чином, щоб одночасно виконувати роль коментаря, що пояснює призначення імені. Так, в приведеному прикладі ім'я переводиться з англійського як "зберегти в файлі". Крім того, з урахуванням неможливості вставки всередину такого імені пропусків, перші букви слів звичайно пишуть заголовними, а інші рядковими. З приведеного прикладу добре видно, що саме такий спосіб запису найбільш наочний для візуального сприйняття імені. Нерідко як замінник пропуску використовують символ "_". Однак це подовжує і без того довгі імена. Переваги довгих імен зовсім не означають, що не можна застосовувати короткі імена. Зрозуміло, що простіше набрати з клавіатури і використати оператор

а: = а + 1,

чим ідентичний йому оператор

Disk_C_DirctoryCounter: = Disk_C_DirctoryCounter +1.

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

Зображення. До їх числа відносяться константи, символьні рядки і деякі інші значення.

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

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

Коментарі. Ці лексеми використовують для пояснення окремих фрагментів тексту програми. Вони являють собою послідовність символів, взяту в фігурні дужки { } або в роздільники (* і *), а також послідовність символів, розташованих в рядку праворуч від двох наступних один за одним символів /.

Приклади коментарів:

{ Функція обчислення кількості днів між двома датами }

(* Функція обчислення кількості днів між двома датами *)

// Неправильна відповідь

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

1.4. Деякі важливі поняття

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

Осередок. Цей трохи застаріліший, але вельми зручний термін означає фрагмент пам'яті, який можна представити як деякий контейнер для зберігання даних певної структури. Осередок завжди має своє унікальне ім'я, яке служить адресою, по якій розташовані дані, що знаходяться в ній. Прикладом осередку можуть служити будь-які дозволені імена, наприклад a1, Imk12, Count і т. д. Термін "осередок" не є язиковим терміном Object Pascal і використовується тут тільки для більшої наглядності при описі основ мови.

Значення - це постійна величина або структурний комплекс постійних величин, виражених в явному вигляді. Значення не має імені.

Приклади значень:

- 55.455051 { звичайне дійсне число},

' Розрахунок посадки з натягом' {рядок символів}.

Константа - це осередок, в якому завжди зберігається одне значення. Константи не можуть бути змінені в ході виконання програми. У цьому значенні константа відповідає загальноприйнятому визначенню постійної (незмінної) величини. Всяка константа повинна бути описана, т. е. повинне бути явно вказане її значення. Значення константи неявно визначає її тип.

Необхідно відмітити, що в мові існують так звані типизованние константи, які в ході проходження програми можуть бути змінені. Тип константи вказується в спеціальній язиковій конструкції, що починається словом Type (тип).

Змінна - це осередок, в якому в кожний момент часу зберігається одне значення або не зберігається нічого. Змінна в будь-який момент часу може бути змінена програмою. Всяка змінна повинна бути описана. т. е. повинен бути явно вказаний її тип. Тип змінної вказується в спеціальній язиковій конструкції, що починається словом Var (від англійського variable - постійна).

Тип - це структура і опис безлічі значень, які можуть бути привласнені змінною.

Оператор привласнення - це команда, призначена для зміни що міститься осередку. З його допомогою відбувається зміна значення змінної (або типизованной константи).

Синтаксис оператора привласнення:

х: = у; { читається "х привласнити у" }

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

Приклади:

d: = 5; { значення 5 записується в змінну D },

h: = d + 12.5; { вич. 5+12.5, рез. 17.5 записується в змінну h }.

2. Система типів

В мові Object Pascal всі змінні, т. е. елементи пам'яті, призначені для запису, читання і зберігання значень, повинні бути заздалегідь описані. Це означає, що всяка змінна повинна бути явно віднесена до якого-небудь типу.

Тип - це одночасно структура і опис безлічі значень, які можуть бути привласнені такою змінною.

Мова Object Pascal має безліч різноманітних типів. Більше за те він дозволяє самому користувачу конструювати самі різноманітні типи, які можуть бути йому необхідні. Конструювання таких типів проводиться з порівняно обмеженої кількості стандартних типів.

Типи мають свою ієрархію. На верхньому поверсі ієрархії розташовані наступні типи: прості, складові, посилальний і процедурні.

3. Стандартні прості типи

Основними типами мови є стандартні прості типи і стандартні структурні типи.

Прості типи діляться на скалярні і обмежені типи. Скалярні типи діляться на стандартні і перечислимие. Стандартні скалярні типи діляться на п'ять видів:

- ціле [Integer],

- речовинні [Real],

- логічний (булевский) [Boolean],

- символьні [Char],

- рядкові [String].

До них примикає особливий варіантний тип [Variant].

3.1. Цілі типи

Ця група типів охоплює безліч цілочисельних значень. Вони відрізняються один від одного діапазоном допустимих значень і кількістю займаної пам'яті.

Цілими типами є ShortInt, SmallInt, LongInt, Int64, Byte, Word і LongWord, характеристики яких приведені в табл. 1.

Таблиця 1

Тип

Діапазон значень

Розмір пам'яті

1.

2.

3.

4.

5.

6.

7.

ShortInt

SmallInt

LongInt

Int64

Byte

Word

LongWord

- 128. . 127

- 32768. . 32767

- 2147483648. . 2147483647

- 2^63. . 2^63-1

0...255

0...65535

0. . 4294967295

1 байт

2 байта

4 байта

8 байтів

1 байт

2 байта

4 байта

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

Так якщо значення змінної будуть тільки позитивними, то можна її віднести до одного з типів Byte, Word, LongWord. Якщо відомо також, що її значення ніколи не вийдуть за 255 (наприклад, якщо змінна призначена для зберігання номера місяця поточного року), то краще використати тип Byte. При цьому пам'ять буде витрачатися найбільш економно.

Не треба, однак, прагнути до зайвої економії пам'яті на змінних. Нерідко економно описана змінна може привести до ситуації, коли програма спробує записати в неї таку константу, яка перевищує допустимий діапазон значень. Це приведе до негайного аварійного завершення програми з повідомленням "Range check error" (вихід за допустиму межі діапазону). Повідомлення такого роду можуть генеруватися самими різними операціями і в самих різних місцях програми. З цієї причини пошук помилки в програмі, особливо якщо вона многомодульна і складна, може надовго затягнутися.

Не треба також зловживати многообъемними типами, т. до. це може привести до зайвої перевитрати, а іноді і недостачі пам'яті, з одного боку, і уповільненню роботи програми - з іншою.

Приклади:

Var

А, A_Par: Integer;

T1, T2, T3: LongInt;

CircleCounter: byte;

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

Приклади:

0 9877 -56 $F1 (те ж, що 241)

Над цілими значеннями можна виконувати чотири звичайних арифметичних дії: складання (+), віднімання (-), множення (*), ділення (/) і дві додаткових дії: ділення без остачі (div) і взяття залишку від ділення (mod). При виконанні ділення результатом буде речовинне значення, у всіх інших операціях - ціле.

3.2. Речовинні типи

Ця група типів охоплює речовинні значення.

Речовинні типи не можуть бути використані:

- як індекси масивів;

- в операторах For і Case;

- як базисний тип при визначенні множин;

- при визначенні подтипов.

При описі замість Real48 можна вказувати Real.

Нижче в табл. 2 приведений список типів і їх характеристики.

Таблиця 2

Тип

Діапазон значень

цифр, що Означають в мантисі

Розмір пам'яті

1.

2.

3.

4.

5.

6.

Real48

Single

Double

Extended

Comp

Currency

2.9 х 10^-39. .. 1.7 х 10^38

1.5 х 10^-45. .. 3.4 х 10^38

5.0 х 10^-324. .. 1.7 х 10^30

3.6 х 10^-4951. .. 1.1 х 10^4932

- 2^63+1. .. 2^63 -1

- 922337203685477.5808. .. 922337203685477.5807

11 - 12

7 - 8

15 - 16

19 - 20

19 - 20

19 - 20

6 байтів

4 байта

8 байтів

10 байтів

8 байтів

8 байтів

Приклади:

Var

rA, rA_Par: Real;

Т: Integer;

Речовинні значення можна зобразити:

- в формі з фіксованою десятеричною точкою;

- в формі з плаваючою десятеричною точкою.

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

12.455

- 988.45

- 8.0

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

< значення з фіксованою точкою > Е < порядок >

Приклади:

- 45.2 E6 (те ж, що -45,2 106)

5.245Е-12 (те ж, що 5,24 10-12)

Порядок таких чисел повинен бути завжди цілим числом.

3.3. Логічний (булевский) тип

Логічні змінні мають тип boolean. Така змінна займає один байт пам'яті і може мати одне з двох можливих значень - True (істина) або False (брехня).

Приклади:

Var

b: boolean;

b1, Ti: boolean;

3.4. Символьний тип

Типи AnsiChar і WideChar описують безліч окремих символів мови, включаючи букви російського алфавіта. AnsiChar описує безліч з 256 ASCII-кодів і займає один байт пам'яті, WideChar описує безліч Unicode - універсальна безліч кодів і займає два байти пам'яті. Тип AnsiChar еквівалентний базовому типу Char колишніх версій мови.

Приклади:

Var

Ch, k: AnsiChar;

Char_Massivr: array[1..100] of Char;

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

'h' 'X' '#' '$' ''''

3.5. Рядкові типи

Цей тип багато в чому схожий з типом Array of Char, т. е. масивом символів. Відмінність складається в тому, що змінна цього типу може мати динамічну кількість символів (від нуля до верхньої межі), в той час як масив символів завжди статичний і має однакову кількість символів.

Таблиця 3

Тип

Довжина рядка

Займана пам'ять

1.

2.

3.

ShortString

AnsiString

WideString

0 - 256 символів

0 - 2 Гб символів

0 - 2 Гб символів

(К-ть символів) х 1 байт

(К-ть символів) х 1 байт

(К-ть символів) х 2 байта

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

Особливо потрібно виділити тип String. Якщо довжина String-рядка не оголошена, то при дії директиви компілятора {$Н+} або без її вказівки таке оголошення рівносильно AnsiStrig. Якщо встановлена директива {$Н-}, то тип String равносилен типу ShortString.

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

Приклади значень рядкових типів:

' Иванов І. І.' '' 'Газета'ИЗВЕСТИЯ"' ' Рядок символів'

Приклади опису змінних рядкових типів:

Var

s1, s2: ShortString [12];

st1, st2: AnsiString [580];

ChMassiv: array [1..15] of String;

3.6. Рядковий тип PChar

Для зв'язку з функціями Windows в мову Object Pascal введений новий тип рядків - PChar-рядки із завершальним нулем. У звичайній і звичній для колишніх версій мови String-рядку нульовий байт відведений для зберігання реальної кількості символів цього рядка, а самі символи послідовно розташовуються починаючи з першого байта. У PChar-рядку, навпаки, символи розташовуються починаючи з нульового байта, а їх послідовність закінчується завершальним нулем.

Рядки PChar можна оголошувати як звичайні символьні масиви. Наприклад, рядок довжини 3000 плюс один байт, зарезервований під завершальний нуль, можна визначити таким чином:

Var

s: array[1. . 3000] of Char;

П р і м е ч а н і е. Без необхідності не використайте PChar-рядка. Рядкові String-типи і функції для обробки таких рядків добре налагоджені, вони легше у використанні, і, як правило, надійніше за PChar-рядки.

3.7. Динамічні PString-рядки

Цей тип рядків так само, як PChar, введений в мову для звернення до функцій Windows. Детальніше за PString-рядок описані далі.

3.8. Перечислимие типи

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

Приклади перечислимих типів:

Type

MaleNames = (Ivan, Peter, Serge);

SwithOpts = (On, Off);

SostTypes = (Active, Passive, Waiting);

Sides = (Left, Right, Top, Down);

У першому прикладі змінна оголошеного типу може приймати значення одного з трьох чоловічих імен. У другому - одне з двох значень - On (включено) або Off (вимкнено) і т. д.

Імена з списку перечислимого типу вважаються константами відповідного перечислимого типу і в межах блоку не повинні повторюватися.

Наприклад, описи вигляду

Type

Days1 = (Monday, Wednesday, Friday);

Days2 = (Tuesday, Wednesday, Saturday, Sunday);

містять помилку, т. до. константа Wednesday використовується двічі.

3.9. Обмежені типи

Цей тип формується самим користувачем за допомогою звуження значень раніше певного або стандартного типів.

Приклади:

Type

Diapason = 1. . 30;

Letters = 'a'. . 'v';

TList = (t1, t2, t3, t4, t5, t6, t7, t8, t9, t10);

TlistSmall = (t2. . t8);

3.10. Варіантний тип (Variant)

Тип Variant - особливий тип мови Object Pascal. Значення цього типу наперед невідоме, однак може бути визначене через значення, що привласнюється одним з наступних типів: всі цілі, речовинні, рядкові, символьні і логічні типи, за винятком Int64.

Наступні приклади демонструють використання типу Variant і механізм конверсії типів при змішуванні його з іншими типами. Супровідні коментарі пояснюють правила, за допомогою яких оператори привласнення міняють тип Variant-змінних в залежності від прийнятого ними значення.

Var

V1, V2, V3, V4, V5: Variant; {опис Variant-змінних }

I: Integer;

D: Double;

S: string;

...

begin

V1: = 1; { integer-значення }

V2: = 1234.5678; { real-значення }

V3: = ' Іванов'; { string-значення }

V4: = '1000'; { string-значення }

V5: = V1 + V2 + V4; { real-значення 2235.5678}

I: = V1; { I = 1 (integer-значення) }

D: = V2; { D = 1234.5678 (real-значення) }

S: = V3; { S = ' Іванов' (string-значення) }

I: = V4; { I = 1000 (integer-значення) }

S: = V5; { S = '2235.5678' (string-значення) }

end;

3.11. Тип "дата - час"

В мові є декілька типів, призначених для роботи з датами і часом. Вони мають вигляд

Type

TDateTime = Double;

TDate = TDateTime;

TTimeStamp = Record

Time: Integer; { час в миллисекундах від півночі }

Date: Integer; { одиниця + число днів з 01.01.0001 м.}

end;

Тип TDateTime призначений для зберігання дати і часу.

Змінна відрізняється від константи або значення тим, що в процесі роботи програми вона може міняти вміст своєї пам'яті. Однак в кожний момент часу вона зберігає тільки одне значення. Всяка змінна має ім'я, тип і свою область видимості. По суті, змінна є контейнером для зберігання значення ідентичного типу. Всяка змінна в блоці опису повинна бути представлена тільки один раз.

Опис змінної або групи змінних починається словом Var. Область видимості змінної буде детально описана нижче.

Загальний вигляд опису змінних одного типу:

< змінні >: < тип >;

Приклад:

Var

t_s1, t_q1: String[255];

rt1, rt2: (Opened, Closed, Unknown);

Re1, Re2, Re3: Real;

i: Integer;

У цьому прикладі змінні t_s1 і t_q1 описані як рядкові змінні типу String[255]. При роботі програма виділить під кожну з них з урахуванням нульового байта по 256 байтів пам'яті для зберігання символьних значень. Змінні rt1, rt2 оголошені як змінні, які можуть приймати в певний момент часу одне з перерахованих значень: Opened, Closed, Unknown. Змінні Re1, Re2, Re3 оголошені речовинними, а змінна i - цілочисельної типу Integer.

Змінними можуть бути оголошені не тільки змінні простих типів. Нижче будуть розглянуті змінні більш складних - структурних - типів. Більш того змінними можуть бути оголошені структури структур, прикладом яких є класи. Наприклад:

type

TKdnClass = class(TObject).

..

End;

Var

Ts: Record

А, N: Integer;

End;

Cl: TKdnClass;

5. Опис констант

В Object Pascal розрізнюється два вигляду констант - звичайні і типизованние. Опис констант слідує після слова Const.

5.1. Звичайні константи

Опис константи будується за правилом

< ім'я константи > = < вираження >;

Приклади:

Const

T_Par = 12899;

M_ArrayCount = 16;

Middle_M_Array = M_ArrayCount div 2;

RealMax = 1.7e38;

StarString = '* * * * * * * * * * * * *';

Log10 = 2.302585;

Log10_Invert = 1/Log10;

LeftArrayBound = -M_ArrayCount;

Тип константи визначається автоматично на вигляд її значення.

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

Pi = 3.1415926536Е+00 (тип Real)

False, True (Boolean)

MaxInt = 32767 (Integer)

MaxLongInt = 2147483647 (LongInt)

Nil (Pointer).

Часто константи використовують для визначення динамічних масивів, динамічних рядків і інших динамічних структур. Наступні описи демонструють приклад такого визначення.

Const

ArrMax = 100;

nSt = 46;

Var

IntArr: Array[1..ArrMax] of Integer;

StrArrr: Array[1..ArrMax] of String[nSt];

Такий спосіб опису дозволяє при необхідності легко змінити розмір масивів, змінивши усього лише значення константи (в цьому випадку константи ArrMax). При цьому стануться автоматичні зміни визначень як в поточному, так і в інших модулях, якщо вони містять визначення, що спираються на цю константу. Явне визначення масивів через значення 100 зажадало б відповідних явних змін цього значення на інше всюди, де такі описи мали б місце. Для великих програм це могло б стати причиною помилок, якщо частина змін не була б виконана через недогляд.

Типизованние константи

Це спеціальний тип констант, які відрізняються від звичайних констант тим, що при їх описі необхідно вказувати тип.

Прості типизованние константи. Загальний вигляд константи:

< ім'я константи >: < тип > = < значення >;

Приклади:

Const

CurrentPosition: Word = 11000;

LastLetter: Char = 'z';

HeadOfModule: String[26] = ' Почало програмного модуля';

Типизованние константи не можна використати для опису динамічних структур. Наступний приклад демонструє недопустимий опис динамічного масиву Arr через типизованную константу ArrMax:

Const

ArrMax: Integer = 100;

Var

IntArr: Array [1..ArrMax] of Integer; { Помилка }

Значення типизованних констант можна змінювати в ході виконання програми, і вони можуть бути використані як Var-параметр процедури або функції. У зв'язку з цим типизованние константи по суті є змінними з початковим значенням.

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

Type

tVotes = (Yes, No, UnDef);

tVoteArr = array [tVotes] of String [7];

Const

Votes: tVoteArr = ('Так', ' Немає', ' Не знаю');

Var

V: tVoteArr;

S: String[20];

...

V:= Votes;

S:=V[UnDef];

...

Тут в секції Type спочатку описаний перелічуваний тип tVote з трьох значень Yes, No, Undef. Потім через цей тип визначений новий тип tVoteArr як тип-масив з трьох елементів, кожний з яких є рядком довжини 7. Далі в секції Const визначена типизованная константа Votes, яка визначена як масив трьох рядкових значень ('Так', ' Немає', ' Не знаю'). Потім в секції Var описані змінні V і S різних типів. Передостанній і останній рядки є операторами привласнення, що виконуються. Спочатку змінної V привласнене початкове значення - константа Votes. Потім змінної S привласнене значення третього елемента масиву V. В результаті значенням рядкової змінної S буде ' Не знаю'.

Типизованние константи типу "запис". Це комбінований тип констант, заснований на конструкціях типу Record (див. параграф 7.1), які складаються з полів. Константи такого типу визначаються за правилом "ім'я поля: значення поля".

Приклад:

Type

tDayOfYear = Record {день року}

Week: (Mon, Tue, Wed, Thu, Fri, Sat, Sun); {день тижня}

Num: 1. . 31; {день місяця}

Month: 1. . 12; {місяць }

Year: 1951. . 2050; {рік}

End;

Const

D1: (Week: Sun; Num: 26; Month: 10; Year: 2001 D1, яка представляє конкретну дату "Воскресіння, 26, жовтень);

Тут в секції Type описаний запис, що складається з чотирьох полів і що характеризує день року. Призначення цих полів зрозуміло з супровідних коментарів. Потім в секції Const описана типизованная константа (Sun; 26; 12; 2001), т. е. " Воскресіння, 26 жовтня 2001 року".

Типизованние константи типу "безліч". Ці константи можуть бути побудовані як підмножини базових або похідних від них типів.

Приклади:

Type

tChildNameSet = set of ['Таня', ' Валячи', ' Володя', ' Гена'];

Const

Girls2Set: tGirlsNamesSet = ['Валячи', ' Гена'];

Indexes: set of integer = [300. . 500, 1777,3700];

Тут в секції Type описана безліч з чотирьох імен дітей. Нижче в секції Const описано дві константи, кожна з яких представляє підмножини. Перша - підмножина імен, оголошених раніше в tChildNameSet, друга - підмножина цілих чисел типу Integer.

6. Опис типів

Раніше вже приводилися приклади опису змінних, в яких їх тип вказувався в Var-секції явно або на основі раніше оголошеного призначеного для користувача типу.

Опис секції типів починається словом Type.

У табл. 4 даний приклад двох ідентичних способів опису змінних t, u, n.

Таблиця 4

Явний спосіб опису

змінних

Опис змінних з попереднім описом їх типу

Var

t, u, n: (Mon, Tue, Wed, Thu, Fri, Sat, Sun);

Type

DaysOfWeek = (Mon, Tue, Wed, Thu, Fri, Sat, Sun);

Var t, u, n: DaysOfWeek;

У тих випадках, коли явний і типизованний способи опису змінних конкурують, потрібно завжди віддавати перевагу способу опису змінних з попереднім оголошенням їх типу в секції Type. Такий спосіб дозволяє:

а) конкретизувати тип;

б) чітко виділити безліч змінних цього типу;

в) підвищити рівень структурированности програми;

г) знизити імовірність плутанини в типах, коли змінні фактично того ж типу оголошені різними способами;

д) зменшити об'єм тексту за рахунок можливості швидкого посилання на раніше певний тип, особливо в тих ситуаціях, коли цей тип використовується для породження нових типів, змінних, функцій і пр. в інших секціях або модулях.

У зв'язку з цим важливо підкреслити, що навіть при збігу базових типів відмінність в призначених для користувача типах може привести до непередбачуваної поведінки програми. Наприклад, в нижченаведеній секції Type два похідних типи t1 і t2 мають однаковий базовий тип byte. Однак оголошені нижче в Var-секції змінні p1 і p2 будуть розцінені системою як змінні різних типів. Ця обставина може послужити причиною непорозумінь в ході складання і/або виконання програми.

Type

t1 = byte;

t2 = byte;

Var

p1: t1;

p2: t2;

Коректним можна вважати наступний аналог:

Type

t1 = byte;

Var

p1, p2: t1;

7. Структурні типи

Структурні типи являють собою сукупність значень одного або декількох різних типів. Їх наявність дозволяє програмісту конструювати похідні типи практично будь-якій складності, що різко розширює можливості мови.

До числа структурних відносяться наступні типи:

множинні типи [Set],

регулярні типи (масиви) [Array],

комбіновані типи (записи) [Record],

файлові типи [File],

класи [Class],

класові посилання [Class reference],

інтерфейси [Interface].

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

Три останніх типи будуть описані окремо в розділах, присвячених об'єктно-орієнтованому програмуванню.

7.1. Регулярні типи (масиви)

Масив - це структура мови Object Pascal, що являє собою впорядковану сукупність елементів одного типу.

Потрібно розрізнювати два вигляду масивів: масив-тип і масив-змінну.

Масив-тип. Синтаксис масиву-типу:

< ім'я масиву > = Array [ < тип індексу >, < тип індексу >,. .., < тип індексу > ]

Of < тип елемента >;

Всякий масив має розмірність. Розмірність визначається кількістю типів індексів, які взяті в квадратні дужки [. . ].

Масив-тип призначений для опису:

структури масиву як типу;

розмірність масиву;

типів індексів масиву;

типу кожного елемента масиву.

Так, в наступному прикладі

Type

tA1: array [1. . 10] of Real;

описана структура одномірного масиву речовинних елементів (Real), в якому індекс може змінюватися в діапазоні цілих значень від 1 до 10. Його елементами є речовинні типи tA1[1], tA1[2], tA1[3],. .., tA1[9], tA1[10].

Інший приклад:

Type

Color: (Red, Green); { перелічуваний тип }

Z: array [1. . 3, Color ] of Boolean; { масив }

В ньому спочатку описаний простий перелічуваний тип Color. Нижче на його основі описаний двумерний масив Z логічних (Boolean) елементів. Перший індекс масиву має цілий тип, а другий - тип Color. Таким чином, масив складається з шести елементів - логічних типів:

Z [1, Red], Z [1, Green], Z[2, Red], Z[2, Green], Z[3, Red], Z[3, Green].

Масив-змінна. Синтаксис масиву-змінної:

< ім'я масиву >: Array[ < тип індексу >, < тип індексу >,. .., < тип індексу > ]

Of < тип елемента >;

Масив-змінна відрізняється від масиву-типу тим, що всі його елементи - це окремі незалежні змінні, які можуть містити різні значення одного типу.

Масив-змінна може бути описаний явно або з допомогою раніше певного в секції Type типу.

У наступному прикладі масиви у, Z описані ідентично, причому у - явно, Z - на основі раніше певного типу в секції Type, т. е. неявно.

Type

tA1: array [1. . 10] of Real;

Var

у: array [1. . 10] of Real; {масив}

Z: tA1; {масив}

Цей приклад демонструє різні способи опису однакових по структурі, але різних по типу масивів. З точки зору коректного програмування він одночасно є прикладом того, як не слід описувати ідентичні змінні. Причина цього полягає в тому, що ідентичні структури щоб уникнути непередбачуваної поведінки програми потрібно описувати одним типом.

У зв'язку з цим коректним буде будь-який з варіантів, приведених в табл. 5.

Таблиця 5

Коректний неявний спосіб

Коректний явний спосіб

Type tA1: array [1. . 10] of Real;

Var Y, Z: tA1;

Var у, Z: array [1. . 10] of Real;

Багатомірні масиви містять два і більше за індекси, наприклад:

Var h: array[1. . 3, boolean, -7. . 7] of Word;

що еквівалентне

Var h: array[1. . 3] of array[boolean] of array[-7. . 7] of Word;

Для упакованих масивів

Var packed array[Boolean, 1..10, TShoeSize] of Char;

що еквівалентне

Var

packed array[Boolean] of packed array[1..10]

of packed array[TShoeSize] of Char;

Маніпуляції з окремими елементами масивів. Звернення до окремого елемента масиву можливе через його індекси. У наступному прикладі в секції Var описані проста змінна i і два одномірних масиви А і V як ціле змінне типу Integer. Потім в блоці begin. .. end розташовані три обчислювальних оператори.

Var

i: Integer;

А, V: array[1..100] of Integer;

...

begin

i:= 5;

V[8]:= i+9;

А[45]:= V[i+3]*2;

end;

При виконанні першого з них змінна i прийме значення 5. При виконанні другого - восьмий елемент масиву V прийме значення 14. У третьому операторі спочатку буде обчислений індекс i + 3 = 8, потім значення восьмого елемента масиву V (значення 14) буде помножене на 2 і отриманий результат - значення 28 - буде привласнено 45-му елементу масиву Мова допускає за допомогою одного оператора привласнення виконати операцію над масивом загалом. Нехай, наприклад, масиви А, V оголошені як квадратні матриці. Тоді оператор

V:= А;

виконає копіювання значень всіх елементів масиву А в масив V, а після виконання оператора

V:= А * V;

буде виконане множення матриці А на матрицю V і результат буде вміщений в матрицю V з попереднім затиранням старих значень.

Упаковані масиви. Елементи упакованого масиву зберігаються в пам'яті максимально щільно. При записі він заздалегідь упаковується з метою економії пам'яті. При читанні, навпаки, розпаковується. Операції упаковки і розпаковування вимагають додаткового часу. Тому використання упакованих масивів дещо вповільнює роботу програми. Від звичайного масиву Array опис упакованого масиву відрізняється тим, що перед цим словом додається слово Pаcked, наприклад:

Var W: packed array [1..100] of Integer;

7.2. Комбіновані типи (записи)

Запис - це об'єднання елементів різних типів. Як і в масивах, потрібно розрізнювати запис-тип і запис-змінну. Один елемент запису називається полем.

Запис-тип. Синтаксис запису-типу:

< ім'я запису > =Record

< ім'я поля 1 >: < тип >;

< ім'я поля 2 >: < тип >;

...

< ім'я поля N >: < тип >;

< варіантна частина >

End;

Записи дуже зручні для опису і зберігання різнотипних даних про які-небудь однотипні структури.

Прикладом можуть служити зведення про студентів. Відомості про будь-яке з них можуть включати поля: Прізвище, Ім'я, По батькові, Рік народження, Група, Рік вступи до вузу, Курс. Такі структури є однотипними і можуть бути описані наступним типом:

Type

TStud = Record { Зведення про студента як запис }

Fio: String[40]; { ФИО як рядок з 40 символів }

Name: String[20]; { Ім'я як рядок з 20 символів }

Otch: String[30]; { По батькові як рядок з 30 символів }

BirthYear: Word; { Рік народження як ціле типу Word }

Group: String[8]; { Група як рядок з 8 символів }

ElectYear: Word; { Рік надходження як ціле типу Word }

Curs: Byte; { Курс як ціле типу Byte }

End;

У цьому прикладі типи полів запису типу tStud призначені з урахуванням максимально можливих значень цих полів. Так, структура може зберігати прізвище з не більш ніж 40 символів. Полю Curs призначений тип Byte, який має діапазон значень 0. . 255, т. до. значенням цього поля може бути одне із значень 1. . 6, які повністю охоплюються діапазоном типу Byte. Цьому полю можна було б призначити будь-який інший цілий тип, наприклад Word. Однак, з метою економії пам'яті, підвищення швидкості читання і запису даних, потрібно призначити саме тип Byte, який займає всього 1 байт пам'яті, а не тип Word, який вимагає 2 байти пам'яті. У той же час, наприклад, для поля ElectYear (рік надходження) тип Byte непридатний, т. до. має недостатній діапазон значень.

Записи з варіантами. Синтаксис запису допускає вариантность опису полів. Варіантна частина містить декілька альтернатив, в кожній з яких в круглих дужках задається список полів, властивих своєму варіанту. Прикладом можуть служити запису про пенсіонерів:

Type

tPensioner =Record{ пенсіонер }

FioIO: String[100]; { Прізвище, ім'я, по батькові одним рядком }

Age: Byte; { Вік }

Case Citizen: boolean of {чи Городянин? }

TRUE: (Town: String[30];) {Місто, в якому проживає}

FALSE: (Address: String[100]; {Повна адреса одним рядком}

Transport: String[200];) {Транспорт, яким можна добратися до міста}

End;

У цьому прикладі запис tPensioner містить зрозумілі поля FioIO і Age, а також поле нового вигляду - логічне поле Citizen варіантного типу. Від значення цього поля залежить поява і непоява деяких потенційних полів запису. Так якщо значення цього поля TRUE (істина), то в записі з'являється (стає доступним) поле Town (місто), при значенні FALSE (брехня) - поля Address і Transport.

При використанні варіантних полів в записах потрібно підкорятися наступним правилам синтаксису:

Варіантна частина повинна починатися з рядка, на початку якої розташовується слово Case, а в її кінці - слово Of. Між ними розташовується підлога-ознака.

Запис повинен містити тільки один варіант, який повинен розташовуватися в кінці всіх описаних полів непосредствено перед словом End.

Імена полів у всіх варіантах повинні бути різними. Вони повинні також відрізнятися від імен полів фіксованої частини.

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

Запис-змінна. Синтаксис запису-змінної:

< ім'я запису >: Record

< ім'я поля 1 >: < тип >;

< ім'я поля 2 >: < тип >;

...

< ім'я поля N >: < тип >;

< варіантна частина >

End;

т. е. синтаксиси змінної і типу відрізняються одним символом (":" і "=").

Приклад:

Type

tMass: Array [1. . 2, 1. . 50] of Real;

tRec: Record

Name: String [10];

Mass2: tMass;

End;

Var

J: Integer;

S: String[70];

F, Gri: Record

a, b, з: Integer;

k: Array [1..10] of String [60];

z: tMass;

r: tRec;

End;

У секції Var описані дві прості змінні J і S і два записи F і Gri, що мають однакову, але досить складну структуру:

перших три поля записів F і Gri мають імена a, b, з і тип Integer;

поле k являє собою одномірний рядковий масив з 10 елементів;

поле z має тип, описаний в секції Type як двумерний речовинний масив, в якому перший індекс може змінюватися в діапазоні 1. . 2, а другий індекс - в діапазоні 1. . 50;

поле r в свою чергу саме є записом, поля якої описані типом tRec в секції Type.

Доступ до полів записів. Змінна, що представляє поле, конструюється з імені запису і поля, відділеного один від одного десятеричною точкою. Така складова змінна називається кваліфікаційної.

Приклади кваліфікаційних полів вищенаведених записів:

F.a Gri.a F.k[6] Gri.z [2, 34] F.r.Name F.r.Mass2[1, 50]

Приклади операторів привласнення з участю полів записів:

S: = ' Иванов Іван Петрович';

J: = 123;

F.a: = J + 9;

Gri.a: = (F.a + J) * (F.c + F.b - Gri.c);

Gri.a: = (F.a + J) * (F.c + F.b - Gri.c);

F.k [1]: = F.z [2,30];

Gri.r.Name: = ' Студент ' + F.k [8];

Gri.a: = 12 * (Gri.a + Gri.b + Gri.c);

Доступ до полів записів за допомогою оператора With. Для спрощення звернення до полів одного і того ж запису можна використати оператор With.

Приклад:

With Gri do

Begin

a:= 12 * (а + b + з + F.a);

b:= 64 * (b - з);

End;

Ці оператори виконують ті ж операції, що і оператори

Gri.a:= 12 * (Gri.a + Gri.b + Gri.c + F.a);

Gri.b:= 64 * (Gri.b - Gri.c);

7.3. Множинні типи

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

Як і в масивах, потрібно розрізнювати безліч-тип і безліч-змінну.

Безліч-тип. Синтаксис безлічі-типу:

< ім'я безлічі > = Set of < базовий тип >;

Приклад:

Type

TSomeInts = 1..250;

TIntSet = set of TSomeInts;

створює тип безлічі з ім'ям TIintSet, яке містить безліч цілих чисел в діапазоні від 1 до 250. Ця ж безліч могла бути описана явно:

type TIntSet = set of 1..250;

Безліч-змінна. Синтаксис безлічі-змінної:

< ім'я безлічі >: Set of < базовий тип >;

Відповідно до вишеописанними типів можна оголосити множини:

Var Set1, Set2: TIntSet;

а потім в операторной частині задати ці множини:

...

Set1: = [1, 3, 5, 7, 9];

Set2: = [2, 4, 6, 8, 10];

Можна оголосити безліч явно, перерахувавши його елементи:

Var

MySet1: set of 'a'. . 'z';

MySet2: set of Byte

MySet3: set of (Club, Diamond, Heart, Spade)

MySet4: set of Char;

...

MySet 1:= ['a','b',' з']; {оператор визначення безлічі}

Операції над множинами. Допустимі операції над множинами приведені в наступній табл. 6:

Таблиця 6

Операція

Найменування операції

Тип операндів

Тип результату

Приклад

+

-

*

< =

> =

=

< >

in

Об'єднання

Віднімання

Перетин

Не менше

Не більше

Рівність

Нерівність

Прінадлежаніє

set

set

set

set

set

set

set

елемент set

set

set

set

boolean

boolean

boolean

boolean

boolean

Set1 + Set2

S - Т

S * Т

Q <= MySet

S1 > = S2

S2 = MySet

MySet < > S1

А in Set1

Об'єднання, віднімання і перетин множин.

Результатом будь-якої з операцій буде також безліч.

Приклад:

Var

S1, S2, S3: set of Byte;

...

S1:= [1, 2, 3, 4]; {оператор визначення безлічі}

S2:= [3, 4, 5, 6, 78]; {оператор визначення безлічі}

S3:= S1 + S2; {об'єднання множин}

{результат S3 = [1, 2, 3, 4, 5, 6, 78] }

S3:= S2 - S1; {віднімання множин}

{результат S3 = [1, 2, 5, 6, 78] }

S3:= S2 * S1; {перетин множин}

{результат S3 = [3, 4] }

Операції порівняння множин.

Результатом будь-якої з операцій буде логічна константа True (істина) або False (брехня).

Приклад:

Var

S1, S2, S3: set of Byte;

У: boolean;

...

S1:= [3, 4]; {оператор визначення безлічі}

S2:= [1, 3, 4]; {оператор визначення безлічі}

S3:= [3, 4, 5, 6, 78]; {оператор визначення безлічі}

В:= S1 < = S3; {True, т. до. S1 є підмножиною S3}

В:= S3 > = S2; {False, т. до. S2 не є підмножиною S2}

В:= S3 = S2; {False, т. до. мн-ва S2 і S3 не рівні один одному }

В:= S3 < > S2; {True, т. до. мн-ва S2 і S3 не рівні один одному }

Перевірка входження елемента у безліч. Результатом операції in буде логічна константа True (істина) або False (брехня). Приклад:

Var

S1: set of Integer;

У: boolean;

...

S1:= [3, 4, 18. . 178, 3101, 4427]; {оператор визначення безлічі}

В:= (4 in S1); {True, т. до. 4 є елементом безлічі S1}

В:= (200 in S1); {False, т. до. 200 не є елементом S1}

7.4. Файлові типи

В мові Object Pascal є три типи файлів:

текстові файли,

файли з типом,

файли без типу.

Зв'язок з файлом може бути встановлений через файлову змінну, яка після опису, але до використання в програмі повинна бути пов'язана із зовнішнім файлом за допомогою процедури AssignFile.

Текстовой файл - це послідовність символьних рядків змінної довжини. Всякий такий рядок завершується маркером кінця рядка CR/LF. Текстові файли можна обробляти тільки послідовно. Введення і висновок не можна проводити для відкритого файла, використовуючи одну файлову змінну. Текстовой файл має тип TextFile, або просто Text. Приклад опису файлової змінної текстового типу:

Var Fi: TextFile;

Файли без типу складаються з компонент однакового розміру, структура яких не відома або не має значення. Допустимо прямий доступ до будь-якої компоненті файла. Приклад оголошення файлової змінної файла без типу:

Var F: File;

Файли з типом складаються з однотипних компонент відомої структури. Допустимо прямий доступ до будь-якої компоненті файла. Приклад оголошення файлових змінних для файлів з типом:

Type

TRec = Record

А: Real;

У: Integer;

З: Char;

End;

Var

F: File of Real;

Q: File of String[100];

Fr: File of TRec;

У цьому прикладі F оголошена як файлова змінна речовинного типу. Це означає, що компонентами файла можуть бути тільки речовинні значення. Файлова змінна Q призначена для доступу до файлів, які складаються з символьних рядків довжини 100. Файлова змінна Fr призначена для роботи з файлами, які складаються із записів типу TRec, оголошеного в секції Type.

8. Сумісність типів

Необхідною умовою коректного обчислення виразів або виконання операторів привласнення є сумісність типів вхідних в них компонент.

Суть сумісності типів зручніше пояснити на прикладі найпростіших виразів, які складаються з одного (для одномісних операцій) або двох (для двомісних операцій) компонент (операндів) і однієї операції.

8.1. Сумісність по обчисленню

Обчислення виразів можливо тільки при дотриманні наступних умов.

Типи операцій і операндів еквівалентні.

Наприклад, не можна застосовувати арифметичні операції до логічних змінних і, навпаки, логічні операції - до арифметичних змінних:

Type

R1, R2: Real;

L1, L2: Integer;

B1, B2: boolean;

...

Not (R1 + R2) B1 + B2 ' Івана' + ' ' + ' Петро' {недопустимі вирази}

Типи операндів еквівалентні.

Типи операндів ціле або речовинні, наприклад:

R1 + R2 L1 + R2 L2 / R1 / L1 {допустимі вирази}

Один тип є базовим, а другий - обмеженим типом цього ж базового типу.

Type

L11, L12: Integer;

K: -199. . 199;

Типи є множинами, причому їх базові типи сумісні.

Type

L: set of 21. . 2141;

K: set of -199. . 199;

Один тип є рядковим, а інший - також рядковим або символьним.

Type

L: String [34]; Q: String [23]; K: Char;

Один тип є посилальний, а інший - також посилальний або безтиповим покажчиком.

Обидва типи є упакованими символьними масивами з однаковим числом елементів.

Один тип є рядковим, а інший - також рядковим типом, або упакованим символьним масивом, або символьним типом.

Один має тип Variant, а інший - тип integer, real, string, character або Boolean.

Обидва типи операндів є процедурними типами з однаковою кількістю параметрів і ідентичними порядковими типами цих параметрів. Для функцій повинні бути ідентичні і типи результату.

8.2. Сумісність по привласненню

Оператор привласнення вважається коректним, якщо тип змінної, розташованої в його лівій частині, сумісний з типом вираження, розташованого в правій частині. Вираження T2 може бути привласнене змінної T1, якщо будуть додержані наступні умови.

Обидва типи T1 і Т2 ідентичні. Недопустимо привласнення файлових типів або структур, вмісних файлові типи (про файлові типи детальніше див. гл. 17).

T1 і Т2 мають сумісні прості типи.

T1 і Т2 мають речовинні типи.

T1 і Т2 мають цілі типи.

T1 і Т2 має тип PChar або інший рядковий тип, і вираження представляє рядкову константу.

T1 і Т2 мають рядкові типи.

T1 має рядковий тип, а Т2 - символ або упакований рядок.

T1 - довгий рядок, а Т2 має тип PChar.

T1 і Т2 мають сумісні типи упакованих рядків..

T1 і Т2 мають сумісні множинні типи..

T1 і Т2 мають сумісні Pointer-типи..

T1 має тип PChar або PWideChar, а T2 є символьний масив вигляду array[0. . n] of Char..

T1 і T2 мають сумісні процедурні типи..

T1 має тип Variant, а T2 - один з типів integer, real, string, character або Boolean..

T1 має тип integer, real, string, character або Boolean, а Т2 - тип Variant.

9. Вираження

Обчислювальна система виконує обчислювальні і керуючі операції по командах, які представлені в програмі за допомогою операторів. Більшість таких операторів будується з використанням виразів, які в практиці програмування грають велику роль, визначаючи спосіб і порядок перетворення даних. Вирази складаються з операндів (значень, констант, змінних, функцій), сполучених за допомогою операцій. Для зміни порядку виконання операцій можуть бути використані круглі дужки. Найбільш важливу роль грають арифметичні, логічні і рядкові вирази.

9.1. Арифметичні вирази

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

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

У мові Object Pascal існує шість арифметичних операцій. Враховуючи, що арифметичні операції утворять підмножину безлічі всіх операцій мови, в табл. 7 показано абсолютне значення пріоритету кожної операції.

Таблиця 7

Операція

Найменування

Пріоритет

+

-

*

/

div

mod

Складання

Віднімання

Множення

Ділення

Ділення без остачі

Залишок від ділення

2

2

1

1

1

1

При обчисленні вираження його тип визначається типами операндів. Операндом називається будь-яка компонента, до якої застосовується операція. Операндом можливо, наприклад, значення, константа, змінна або вираження, взяте в дужки. Типи елементарних виразів показані в табл. 8.

Таблиця 8

Операція

Тип операндів

Тип результату

Приклад

+

-

*

/

div

mod

Integer, real

Integer, real

Integer, real

Integer, real

Integer

Integer

integer, real

integer, real

integer, real

real

integer

integer

X + Y

Result - 1

Р * InterestRate

X / 2

Total div UnitSize

Y mod 6

Приклади:

4*5 = 20, 6/5 = 1.2, 8+7 = 15, 7-3 = 4, 16 div 5 = 3, 16 mod 5 = 2.

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

Приклад:

Вираження:

15 * ((25/5-5*9 + (j-8) * 7.55) / 8.67)

Порядок виконання операцій:

8 2 5 3 6 1 4 7

9.2. Логічні вирази

Результатом обчислення логічного вираження може бути одне з двох логічних значень: True (істина) або False (брехня).

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

У мові існує чотири логічних операцій. Пріоритет операцій показаний в табл. 9.

Таблиця 9

Операція

Найменування

Пріоритет

Not

And

Or

Xor

Заперечення

Кон'юнкция

Діз'юнкция

Спец. дизъюнкция

3

4

5

6

Значення елементарних логічних виразів, що пояснюють призначення цих операцій, приведені в табл. 10.

Таблиця 10

А

В

not А

А and В

А or В

А xor В

True

True

False

False

True

False

True

False

False

False

True

True

True

False

False

False

True

True

True

False

False

True

True

False

В табл. 11 представлені логічні відносини.

Таблиця 11

Відношення

Найменування

>

< > =

<>

Більше

Менше

Більше або одинаково

Менше або одинаково

Одинаково

Не одинаково

Всі відносини равноприоритетни.

Порядок виконання операцій при обчисленні логічного вираження наступний:

спочатку обчислюються арифметичні вирази;

потім - відносини;

в останню чергу обчислюються логічні операції.

Приклади (для х=12, z = 0, у=1):

Таблиця 12

Вираження

Результат

5 > 8

(5 < 3) and (z = 0)

((4 + 8) < 0) or not (у = 0)

not (х < у)>< and (z > у))><

('ab' = 'ac') and (х=z)

(4 in [ 2. ><. 23 ])

True

False

True

True

False

True

Приклад, що демонструє порядок виконання операцій при обчисленні логічного вираження:><

Вираження:><

Not (х > 6 + 8 * 2)( and (у < 7)>< or (z > 7))>< and (х < > у)

Порядок:><

9 3 2 1 6 4 7 5 10 8

9.3.>< Рядкові вирази

Рядкові вирази, окремими випадками яких можуть бути пустою символ '' або одиночний символ (наприклад 'A'), будуються з рядкових або символьних значень, констант, змінних і рядкових функцій за допомогою рядкової операції конкатенації (приєднання).>< Ця операція позначена символом + (плюс).>< Дужки в рядкових виразах не застосовуються.><

Приклад:><

Вираження:><

' Object '+'Pascal '+' для Delphi'

Результат:><

' Object Pascal для Delphi'

10.>< Оператори

Оператор - язикова конструкція, що представляє опис команди або комплексу команд по обробці і перетворенню даних.><

Всі оператори діляться на дві частини - прості оператори і структурні оператори.><

11.>< Прості оператори

До їх числа відносяться:>< оператор привласнення, оператор безумовного переходу, складовий оператор, оператор процедур, спеціальні оператори.><

11.1.>< Оператор привласнення

В параграфі 1.4 було дано коротке визначення цього оператора - одного самих простих і операторів, що найчастіше використовуються. >< Нагадаємо, що його синтаксис має вигляд

х: ><= у;><

де х - ім'я змінної або функції;>< у - сумісне по типу вираження (про сумісність типів див. гл.>< 8)><. Символи ":><=" означають операцію привласнення, відповідно до якої обчислене значення вираження у привласнюється змінної х.><

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

Var

Ch:>< Char;><

S:>< String[5];><

Q:>< String[18];><

L, J:>< Integer;><

Р:>< Byte;><

R:>< Real;><

В:>< Boolean;><

Rec:>< Record

А:>< Word;><

В:>< String[20];><

End;><

...

Таблиця 13

Оператор привласнення

Значення

Q:><= ' d:\Dir1\Word\a.txt';

S:= Q;><

Q:><= S+'r\';

Ch:=Q[2];

L:= 450;><

Р:><= L;><

J:><= 100;><

R:><= - L / J;><

J:><=-L / J;><

J:><=-L - 200;><

В:><= J > L;)(

В:)(= (J < L) and (Q[5] = 'i');)(

Rec.A:)(= J-20;)(

Rec.B:)(= 20;)(

Rec.B:)(= S[1]+S[3]+'\d';

'd:\Dir1\Word\a.txt'

'd:\Di'

'd:\Di т.)( до.)( max Р = 255

100

- 4.5

Помилка.)( Невідповідність типів

250

False

True

230

Помилка.)( Невідповідність типів

' d\\d'

11.2. Оператор безумовного переходу

Цей оператор виконує передачу управління оператору, якому передує мітка.)( Синтаксис оператора:)(

Goto Влучна;)(

Мова допускає як мітки використати ім'я або значення цілого типу з діапазону 1. )(. 9999.

При використанні операторів переходу необхідно дотримуватися наступних правил:)(

Всі мітки, що використовуються в блоці, повинні бути описані словом Label.)(

Приклад оператора опису влучний:)(

Label 1, 2, Met1, Met2, Met3;)(

Мітка повинна розташовуватися в тому ж блоці, що і оператор, який нею помічений.)(

Недопустимо перехід до мітки всередину структурного оператора (наприклад, всередину циклу, минуя його заголовок).)( Компілятор не реагує на цю ситуацію, однак поведінка програми може бути непередбачувана.)( Недопустимі також вхід або вихід по мітці в процедурах або функціях.)(

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

11.3.)( Оператор звернення до процедури

Цей оператор викликає активізацію операторів, розташованих в тілі процедури (див. параграф 15.1).)( Після виконання процедури управління передається до оператора, розташованого услід за оператором процедури.)(

При виклику процедури її формальним параметрам повинні суворо відповідати по сумісності типів і кількості фактичні параметри.)(

Приклади звернення до процедур:)(

Val (s, r, Code);)(

Sort (a, n * 2);)(

SaveParameters;)(

11.4.)( Звернення до функції

Потрібно підкреслити, що не існує спеціального оператора звернення до функції (див. параграф 15.1).>< Звичайно таке звертання проводиться за допомогою іншого оператора, часто оператора привласнення.><

Звернення до функції активізує її внутрішні оператори точно так само, як це відбувається в процедурах.>< Принципова відмінність між виконанням процедури і функції складається в наступному:><

після виконання оператора процедури управління передається до наступного за ним оператора;><

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

Пояснимо це на прикладі оператора привласнення, вмісного звернення до функції Func8:><

G:><= 2 * Pi * Func8(m, n, a) / Sqr (z);><

При виконанні цього оператора спочатку відбувається звернення до функції Func8.>< Після виконання операторів, що становлять тіло цієї функції, обчислене значення повертається в цей оператор, де воно використовується для виконання подальших обчислень всередині оператора.><

12.>< Стандартні процедури і функції

Мова містить ряд процедур і функцій, які в практиці програмування ипользуются найчастіше. >< Розширений список процедур і функцій, які можуть знайти застосування в практиці програмування, приведений в додатку.><

12.1.>< Рядкові процедури і функції

Function Length (St):>< LongInt;><

Повертає довжину рядка символів St, т.>< е.>< кількість символів в ній (не плутати з розміром рядка).><

St:><= '1234abc';

L:><= Length(St);>< {L= 7}

Procedure Delete (St, Pos, Num);><

Видаляє Num символів з рядка St починаючи з позиції Pos, якщо Pos < Length (St).><

St:><= '1234abc';

Delete(St, 4, 2);>< { St= '123bc'}

Delete(St, 3, 120);>< { St= '12'}

Procedure Insert (Obj, Target, Pos);><

Вставляє рядок Obj в рядок Target починаючи з позиції Pos.>< Якщо> Pos > Length (Target), то результат Target + Obj.)(

St1:)(= '***';

St2:)(= '1234abc';

Insert (St1, St2, 3) { St2= '12***34abc'}

Procedure Str (Value, St);)(

Перетворює значення Value числового типу в рядок символів St.)( Value може супроводитися форматом.)(

L:)(=19;)(

Str (L, g);)( {g= '19'}

R:)(= 2.123155;)(

Str (R:)( 8:)(3, h)(; {h= ' 2.123' (лина 8, в дробовій частині 3}

Procedure Val (St, Vr, Code);)(

Перетворює рядок символів St в числову величину Vr цілого або речовинного типу.)( Code = 0, якщо перетворення пройшло успішно, інакше в Code буде записаний номер першого помилкового символа конвертованого рядка, при цьому значення Vr не визначене.)(

St:)(='319';)(

Val (St, k, Cod);)( {k= 319, Cod = 0}

St:)(='81yy9';)(

Val (St, k, Cod);)( {k=? )(, Cod = 3}

Function Copy (St, Pos, Num):)( String;)(

Виділяє з рядка St подстроку символів довжиною Num починаючи з позиції Pos.)( Якщо Pos > Length, то повертає пустий рядок.)(

St1:)(='АБВГДЕ';)(

St2:)(= Copy(St1, 2, 3);)( {St2= 'БВГ'}

St2:)(= Copy(St1, 2, 27);)( {St2= 'БВГДЕ'}

St2:)(= Copy(St1, 44, 2);)( {повертає пустий рядок St2= ''}

Function Concat (St1, St2{,. )(.., StN}): String;

Об'єднує рядки в один рядок.

St:='abc';

St1:=Concat('sss', St, '1234'); {St1= 'sssabc1234'}

St1:=Concat(St, '123'); {St1= 'abc123'}

Function Pos (Obj, Target): Integer;

Повертає номер символа, починаючи з якого рядок Obj перший раз входить в рядок Target. Якщо рядок Obj відсутній в рядку Target, то Pos = 0.

Q:= ' Иванов Сергій Петрович';

Н:= Pos ('Сергій', Q); {Н= 7}

Н:= Pos ('Ігор', Q); {Н= 0}

Function SizeOf (Obj): Integer;

Повертає розмір змінної Obj.

Function FormatFloat(const Format: string; Value: Extended): string;

Повертає форматоване речовинне значення у вигляді рядка. Format - формат числа, Value - число. У табл. 14 дані формати функції FormatFloat.

Таблиця 14

Формат

Опис

0

#.

,

Е+, Е-;

Поле для цифри. Бракуючі позиції замінюються нулями

Поле для цифри. Якщо в позиції є цифра, що означає, то воно виводиться. Нулі не виводяться

Роздільник цілої і дробової частин

Поле роздільника тисяч, мільйонів

Формат представлення чисел з плаваючою точкою. Якщо "+" вказаний, то перед порядком виводиться знак. Якщо вказаний "-", то мінус виводиться тільки для негативних порядків

Роздільник форматів

Приклади дії форматів при конвертації числа в рядок представлені в табл. 15.

Таблиця 15

Формат

Число 1

Число 2

Число 3

Число 4

0

0.00

#.##

#,##0.00

#,##0.00; (#,##0.00)

#,##0.00;;Zero

0.000 Е+00

#.###Е-0

1234

1234

1234.00

1234

1,234.00

1,234.00

1,234.00.

234E+03

1.234E3

- 1234

- 1234

- 1234.00

- 1234

- 1,234.00

(1,234.00)

- 1,234.00

- 1.234 Е+03

- 1.234 E3

0.5

1

0.50.

5

0.50

0.50

0.50

5.000Е-01

5E-1

0

0

0.00

0.00

0.00

Zero

0.000Е+00

0E0

12.2. Стандартні функції

FunctionChar (X: byte): Char;

Повертає символ з номером = Char(74); {Ch= 'J'}

Function Ord (X): LongInt;

Повертає порядковий номер скалярного аргументу.

j:= Ord('J'); {j= 74}

Function Round (X: Real): LongInt;

Повертає округлене до цілого значення речовинного аргументу.

j:= Round(12.8235); {j= 13}

Function Trunc (X: Real): LongInt;

Повертає ціле шляхом відкидання дробової частини речовинного аргументу.

j:= Round(12.8235); {j= 12}

12.3. Арифметичні процедури і функції

Function Frac (X: Extended): Extended;

Повертає дробову частину аргументу, наприклад:

r:= Frac(-12.82); {r = -0.82, Frac(12.82)=0.82 }

Function Abs (X: Extended): Extended;

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

r:= Abs(-12.82); {r = 12.82}

Function ArcTan (X: Extended): Extended;

Повертає арктангенс аргументу.

Function Cos (X: Extended): Extended;

Повертає косинус аргументу.

Function Sin (X: Real): Real;

Повертає синус аргументу.

Function ArcCos(X: Extended): Extended;

Повертає арккосинус аргументу, значення якого повинно належати відрізку [-1, 1]. Повертає значення з відрізка [0, Pi].

Function ArcSin(X: Extended): Extended;

Повертає арксинус аргументу, значення якого повинно належати відрізку [-1, 1]. Повертає значення з відрізка [-Pi/2, Pi/2].

Function ArcTan2(Y, X: Extended): Extended;

Повертає арктангенс аргументів, обчислюючи ArcTan(Y/Х) відповідно до квадрантів координатної площини xOy. Повертає значення з відрізка [-Pi, Pi].

Function Exp (X: Real): Real;

Повертає експоненту аргументу.

Function Sinh(X: Extended): Extended;

Повертає гіперболічний синус аргументу.

Function Cosh(X: Extended): Extended;

Повертає гіперболічний косинус аргументу.

Function Tanh(X: Extended): Extended;

Повертає гіперболічний тангенс аргументу.

Function ArcSinh(X: Extended): Extended;

Повертає гіперболічну арксинус аргументу.

Function ArcCosh(X: Extended): Extended;

Повертає гіперболічну арккосинус аргументу.

Function ArcTanh(X: Extended): Extended;

Повертає гіперболічну арктангенс аргументу.

Function Ln (X: Real): Real;

Повертає натуральний логарифм аргументу.

Function Sqr (X: Real): Real;

Повертає квадрат аргументу.

Function Sqrt (X: Real): Real;

Повертає квадратний корінь аргументу.

FunctionCeil(X: Extended):Integer;

Повертає найбільше ціле аргументу.

Сeil(-2.8) = - 2

Ceil(2.8) = 3

Ceil(-1.0) = - 1

Function Floor(X: Extended): Integer;

Повертає найменше ціле аргументу.

Ceil(-2.8) = - 3

Ceil(2.8) = 2

Ceil(-1.0) = - 1

Function Dec (X, [n]: LongInt): LongInt;

Зменшує значення аргументу на величину другого параметра. Якщо він відсутній, то зменшує на 1.

J:=67;

K:=Dec(J); {j= 66}

K:=Dec(J, 13); {j= 53}

Function Inc (X, [n]: LongInt): LongInt;

Збільшує значення аргументу на величину другого параметра. Якщо він відсутній, то збільшує на 1.

J:=67;

K:=Inc(J); {j= 68}

K:=Inc(J, 13); {j= 81}

12.4. Скалярні функції

Function Odd (X: LongInt): Boolean;

Повертає True, якщо аргумент парний.

J:=67;

K:=Odd(J); {K= False}

Function Pred (X);

Повертає попереднє значення типу аргументу.

Function Succ (X);

Повертає подальше значення типу аргументу.

12.5. Процедури завершення

Procedure Exit; Вихід з процедури.

Procedure Halt[Code:][Word];

Вихід в операційну систему з кодом повернення, якщо він вказаний.

12.6. Процедури і функції для роботи з типами "дата/час"

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

Function Now: TDateTime;

Повертає поточну дату і час.

Function Date: TDateTime;

Повертає поточну дату.

Function Time: TDateTime;

Повертає поточний час.

Function DateToStr (D: TDateTime): String;

Перетворює дату в рядок символів, наприклад:

S:= DateTimeToStr(Date); {поточна дата '26.10.99'}

Function TimeToStr(Т: TDateTime): String;

Перетворює час в рядок символів, наприклад:

S:= TimeToStr(Time); { поточний час '13.58.13'}

Function DateTimeToStr(DateTime: TDateTime): String;

Перетворює дату/часи в рядок символів, наприклад:

S:= DateTimeToStr(Now); { поточні дата і час ' 26.10.99 14.01.51'}

Function DateTimeToTimeStamp(DateTime: TDateTime): TTimeStamp;

Конвертує TDateTime в TTimeStamp, наприклад:

TS:= DateTimeToTimeStamp(Now); {type TS = TTimeStamp}

s:= IntToStr(Ts.Date) + ' ' + IntToStr(Ts.Time); {' 730053 51095810' - (пройшло днів з 00.00.0000 м. і миллисекунд від півночі поточного дня}

FunctionTimeStampToDateTime(const TimeStamp: TTimeStamp): TDateTime;

Конвертує TTimeStamp в TDateTime.

Procedure DecodeDate(Date: TDateTime; var Year, Month, Day: Word);

Раскладивет дату Date на рік, місяць і день, наприклад:

DecodeDate(Now, Y, M, D);

s:= IntToStr(Y) + ' ' + IntToStr(M) + ' ' + IntToStr(M); {' 1999 10 26'}.

Procedure DecodeTime(Time: TDateTime; var Hour, Min, Sec, MSec: Word);

Раскладивет час Time на годину, хвилини, секунди і миллисекунди, наприклад:

DecodeTime(Now, Н, M, S, MS);

ss:= IntToStr(Н) + ' ' + IntToStr(M) + ' ' + IntToStr(S) + ' ' + IntToStr(MS);

{' 14 22 34 567', т. е. 14 ч 22 мін 34 з 567 мс}.

Function EncodeDate(Year, Month, Day: Word): TDateTime;

Протилежна DecodeDate;.

Function EncodeTime(Hour, Min, Sec, MSec: Word): TDateTime;

Протилежна DecodeTime;.

Function FormatDateTime(const Frmt: string; DateTime: TDateTime): string;

Перетворює DateTime в рядок із заданим форматом. Якщо формат пустий, то функція повертає рядок в форматі "c". Наступний оператор привласнить рядкової змінної s значення ' Зустріч відбудеться: п'ятниця, 6 Листопад, 1999, в 10:30 AM'.

s:= FormatDateTime(' "Зустріч відбудеться:" dddd, mmmm d, yyyy, ' +' "в" hh:mm AM/PM', StrToDateTime('6.11.99 10:30am'));

Види форматів дані в табл. 16.

12.7. Інші процедури і функції

Function Hi(X): byte;

Повертає старший байт свого цілочисельного аргументу.

Function Lo(X): byte;

Повертає молодший байт свого цілочисельного аргументу.

Procedure Swap(X);

Міняє старший і молодший байти цілочисельного аргументу місцями.

Procedure Randomize;

Ініціалізує генератор випадкових чисел.

Function Random(N: Integer): Integer;

Повертає випадкове число з інтервалу (0, N).

Function SizeOf(X): Integer;

Повертає число байт, займаних аргументом.

Procedure Move(Var Source, Dest; Count: Integer);

Копіює Count байт із змінної Source в змінну Dest. У разі перекриття областей пам'яті пересилка в область, що перекривається не проводиться.

Function ParamCount: Word;

Повертає число параметрів, переданих в командному рядку.

Procedure Break;

Оператор безумовного завершення циклу, процедури або функцій..

Procedure Continue;

Оператор, що використовується в цикле для передачі управління в його початок.

Таблиця 16

Формат

Опис

З

D

Dd

Ddd

Dddd

Ddddd

Dddddd

M

Mm

Mmm

Mmmm

Yy

Yyyy

h

hh

n

nn

s

ss

t

tt

am/pm

ampm

а/р

/:

Показує спочатку дату в форматі дд. мм. гг, потім час в форматі чч. мм. сс. Не показує час, якщо дробова частина DateTime рівна нулю

Показує день без лідируючого нуля (1 - 31)

Показує день з лідируючим нулем (01 - 31)

Показує день тижня в укороченому форматі (Вос - Суб)

Показує день тижня в повному форматі (Воскресіння - Субота)

Показує дату в форматі дд. мм. рр.

Показує дату в форматі д Місяць рік

Показує місяць без лідируючого нуля (1 - 12)

Показує місяць з лідируючим нулем (01 - 12)

Показує місяць в скороченому вигляді (Янв - Дек)

Показує місяць в повному форматі (Січень - Грудень)

Показує рік у вигляді двох останніх цифр (00 - 99)

Показує рік у вигляді чотирьох цифр (00000 - 9999)

Показує годину без лідируючого нуля (0 - 23)

Показує годину з лідируючим нулем (00 - 23)

Показує хвилину без лідируючого нуля (0 - 59)

Показує хвилину з лідируючим нулем (00 - 59)

Показує секунду без лідируючого нуля (0 - 59)

Показує секунду з лідируючим нулем (00 - 59)

Показує час в форматі чч: мм

Показує час в форматі чч: мм: сс

Показує час в 12-часовому форматі (am - до полудня, pm - пополудні )

Показує час в 12-часовому форматі без покажчика до/після полудня

Використовує Windows-роздільник дати.

Використовує Windows-роздільник часу.

procedure Abort;

Використовується в контексті з іншим оператором; відміняє "заднім числом" оператор у разі його аварійного завершення, блокує видачу повідомлення про помилку, зручний до використання в блоці try. .. finally.

13. Структурні оператори

До їх числа відносяться:

- складовий оператор,

- умовний оператор If,

- оператор варіанту Case,

- оператор циклу For - Do,

- оператор циклу While - Do,

- оператор циклу Repeat - Until,

- оператор запису With,

- оператор Try - Except - End,

- оператор Try - Finally - End,

- оператор On - Do,

- оператор Try - Finally - End.

13.1. Складовий оператор

Це проста структура наступних один за одним операторів, взятих в операторние дужки begin. .. end.

Синтаксис складового оператора:

Begin

Оператор1

Оператор2.

..

ОператорN

End;

Складовий оператор застосовується в тих випадках, коли яку-небудь дію необхідно застосувати не до одного, а відразу до декількох операторів.

Приклад:

Begin

R:= X;

X:= Y;

Y:= R;

End;

13.2. Умовний оператор If

Синтаксис допускає два вигляду оператора:

if логічне вираження then оператор1 else оператор2;

і його усічений варіант:

if логічне вираження then оператор1;

Оператор працює таким чином. Спочатку обчислюється логічне вираження. Якщо воно істинне, то виконується оператор1, інакше - оператор2. Усічений оператор виконує оператор1 тільки у разі істинного значення логічного вираження і не виконує ніяких дій у разі його помилковості.

Приклади:

if (х < 10.7) then a[4]:= 5 else a[4]:= 6;

if (х < 10.7) then a[4]:= 5;

Допустима вкладеність умовних операторів всередині складового умовного оператора. Наприклад, оператору

if L1 then if L2 then St1 else St2 else St3;

еквівалентний оператор

if L1 then

begin

if L2 then St1 else St2;

end

else St3;

У цьому операторі для підвищення структурированности використані операторние дужки begin. .. end. При конструюванні складного умовного оператора щоб уникнути логічних помилок потрібно віддавати перевагу структурному способу запису такого оператора.

13.3. Оператор варіанту Case

Синтаксис оператора:

Case Selector of

Const1: Оператор1;

Const2: Оператор2;

...

ConstN: ОператорN

[else Оператор];

End;

Selector може бути будь-якою простий тип крім Real. Кожна з Const1. .. ConstN може бути значення, трохи перерахованих через кому значень або відрізок типу. Оператор Else, як видно з опису, може бути відсутнім. У тому випадку, якщо він присутній, то діє загальне правило: перед словом Else не повинно бути символа ";" (крапка з комою). Пояснимо роботу оператора Case на прикладі:

Case i of

0: х: = 0;

1,3: х: = 1;

10. . 15: х: = 2

else х: = 3;

End;

При виконанні оператора Case управління буде передане тому оператору, який помічений константою, що є значенням змінної i. Наприклад, якщо до моменту виконання Case-оператора i = 0, то буде виконаний оператор х: = 0. Інакше, якщо i = 1 або i = 3, то буде виконаний оператор х: = 1; інакше, якщо значення i в діапазоні 10. . 15, то буде виконаний оператор х: = 2; нарешті, якщо i не рівне жодній з вищеперелічених констант, то буде виконаний оператор х: = 3, наступний за словом else (інакше).

13.4. Оператор циклу For - Do

Синтаксис оператора має два різновиди:

For лічильник циклу:=нач. знач. To конеч. знач. Do оператор

For лічильник циклу:=нач. знач. Downto конеч. знач. Do оператор

Тут конструкція For. . Do називається заголовком циклу, оператор - тілом циклу.

Для циклів повинні дотримуватися наступні правила і обмеження:

початкове і кінцеве значення лічильника циклу повинні бути однакових простих типів, крім Real;

в тілі циклу лічильник не повинен міняти значення;

вхід в цикл минуя заголовок заборонений;

для першого різновиду початкове значення не повинно бути більше кінцевого;

для другого різновиду початкове значення не повинно бути менше кінцевого.

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

Приклад.

s:= 0;

For i:=1 to 44 do s:= s + z[i];

У результаті в змінної s буде накопичена сума перших 44 елементів масиву z.

Інший різновид оператора For відрізняється лише негативним кроком -1 лічильника.

Приклад.

s:= 0;

For i:=44 Downto 1 do s:= s + z[i];

Буде отриманий той же результат.

13.5. Оператор циклу While - Do

Синтаксис оператора:

While логічне вираження Do оператор;

Цикл виконує оператор, розташований услід за словом Do доти, поки істинне логічне вираження, розташоване за словом While ( "виконуй, поки істинно").

Приклад.

х:= 0;

i:=0;

While (х < 101.667) do

Begin

Inc (i);

X:= X + 5.617;

Y[i]:= Func (i + 6, 9 * i, X);

End;

У цьому прикладі цикл буде виконуватися доти, поки не виконається умова х < 101.667. У тілі циклу змінна X з кожним кроком циклу збільшує своє значення на 5.617 так, що на певному кроці умова х < 101.667 уперше не буде виконана. У цей момент без входу в тіло цикл закінчить роботу.

13.6. Оператор циклу Repeat - Until

Синтаксис оператора:

Repeat

Оператор1;

Оператор2;

...

ОператорN;

Until логічне вираження;

Цикл працює, поки логічне вираження помилкове ( "повторюй, поки не виконається").

Приклад.

s:= 0;

i:=0;

Repeat

Inc (i);

s:= s + z[i];

Until(i = 44);

У цьому прикладі цикл буде виконуватися доти, поки не виконається умова i = 44. Результат буде той же, що в прикладі для For-циклу.

13.7. Оператори Break і Continue

Оператор Break може бути розміщений в тілі циклу. При його виконанні цикл припиняє роботу і вважається виконаним.

Приклад.

s:= 0;

i:=0;

Repeat

Inc (i);

s:= s + z[i];

if (s > 14) then Break;

Until (i = 44);

У цьому прикладі цикл буде виконуватися доти, поки не виконається умова i = 44 або якщо в операторі if змінна s перевищить значення 14.

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

Приклад.

s:= 0;

i:=0;

Repeat

Inc (i);

s:= s + z[i];

if (s > 20) then Continue;

if (s > 14) then Break;

Until(i = 44);

У цьому прикладі якщо в першому операторі if виконається умова s > 20, то спрацює оператор Continue. Він відразу передасть управління на перший оператор в тілі циклу - Inc (i), запобігши тим самим виконанню нижченаведених операторів - другого if і Until.

13.8. Вкладені цикли

В тілі оператора циклу можуть бути розміщені інші оператори циклу. Такі структури називаються вкладеними циклами. Мова допускає будь-яку глибину вкладеності циклів. При використанні вкладених циклів необхідно мати на увазі наступне:

всі вкладені цикли For - Do повинні мати різні лічильники (інакше це суперечило б вимозі на заборону зміни значення лічильника всередині циклу);

немає ніяких обмежень на достроковий вихід з внутрішнього циклу назовні;

недопустимо вхід у внутрішній цикл For - Do, минуя його заголовок, що відповідає загальній вимозі про коректний вхід в цикл.

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

Приклад.

Const

n = 15;

m = 24;

Var

i, j: Byte;

R, Tau, s: Real;

z: array[1..n, 1..m] of Real;

...

{заповнення масиву z з використанням вкладених циклів}

Tau:= Pi/m;

For i:=1 to n do begin

R:=4.0*Pi*Sin(i*Tau); {перший оператор в тілі циклу по i}

For j:=1 to m do z[i, j]: = R+j; {другий оператор в тілі циклу по i}

end {i};

{обчислення суми позитивних елементів масиву z з використанням вкладених циклів }

s:=0;

For i:=1 to n do

For j:=1 to m do

if (z[i, j] > 0) then s:= s + z [i, j];

Приведений приклад містить дві структури вкладених циклів. Перша структура призначена для заповнення елементів двумерного масиву z за допомогою математичної формули

Зовнішній цикл з лічильником i в тілі циклу містить два оператори - оператор привласнення (обчислення значення допоміжної змінної R з метою скорочення часу обчислень) і оператор внутрішнього циклу з лічильником j. Оскільки зовнішній цикл в своєму тілі містить декілька операторів, то вони взяті в операторние дужки begin. .. end.

Ця структура працює таким чином. Після входу в зовнішній цикл змінна i (лічильник цього циклу) прийме значення 1. Далі буде обчислене значення змінної R при i = 1. Після цього буде виконаний внутрішній цикл з лічильником j, де j на кожному кроці буде послідовно приймати значення 1, 2, 3,. .. m (i при цьому залишається незмінним і рівним 1). У результаті будуть обчислені елементи z11, z12,...,z1mпервой рядка масиву. Потім буде виконане повернення до заголовка зовнішнього циклу, де значення лічильника i буде збільшене на 1 (т. е. i стане дорівнює 2) і знову будуть виконані оператори, розташовані в його тілі. У результаті будуть визначені елементи z21, z22,...,z2mвторой рядка масиву і т. д.

Друга структура вкладених циклів призначена для обчислення суми позитивних елементів масиву z. Для цього спочатку змінної s буде привласнене значення 0, а потім у вкладених циклах буде накопичена необхідна сума в осередок s.

13.9. Оператор запису With

В ранніх версіях мови оператор використовувався для більш зручного доступу до полів запису.

Приклад:

Var

Student: Record

Fam: String[30];

Name: String[20];

Age: Word;

End;

...

Student.Fam:= ' Колокольников';

Student.Name:= ' Павло';

S:=Student.Fam + ' '+Student.Name;

{попередніх три оператори еквівалентні наступним}

WithStudent do

Begin

Fam:= ' Колокольников';

Name:= ' Павло';

S:= Fam + ' '+ Name;

End;

13.10. Оператор Try - Except - End

Цей новітній засіб мови. Блок Try - Except - End використовується для запобігання винятковим ситуаціям (ИС), які можуть виникнути при виконанні програми. До їх числа відносяться збої в роботі апаратури, помилки обчислень (наприклад ділення на нуль), спроби привласнити значення, що виходить за межі типу і т. д.

Синтаксис:

Try

{оператори, здатні генерувати ИС}

Except

{оператори, що обробляють генерированние ИС}

end;

Блок Try - Except - End працює таким чином. Виконання починається з операторів, розташованих в блоці Try - Except. Якщо в якому-небудь операторі виникає ИС, то вона придушується і потім виконуються всі оператори, розташовані в блоці Except - End. У результаті запобігається аварійне переривання програми. Використання блоку Try - Except - End відкриває можливість програмного контролю за ИС.

Приклад.

i:= 0;

n:= 8;

Try

i:= n div i; {Ділення на нуль. Оператор генерує ИС}

n:= i + 9;

Except

ShowMessage(' Помилка. Ділення на нуль в операторі i: = n / i');

End;

Результатом виконання блоку операторів буде поява на екрані форми з повідомленням "Помилка. Ділення на нуль в операторі i: = n / i", після чого програма продовжить роботу з оператора, наступного за словом End, а не з оператора n: = i + 9.

Якби оператор i: = n div i не був захищений блоком Try - Except - End, то виникла при його виконанні ИС привела б до небажаного аварійного завершення програми.

13.11. Оператор On - End

При виникненні ИС мова дозволяє не тільки запобігти перериванню програми, але і визначити, якого саме вигляду була ИС. Для цього в блоці Except - End можна використати оператор On -Do.

Приклад

i:= 0; n:= 8;

Try

i:= n div i; {Ділення на нуль. Оператор генерує ИС}

n:= i + 9;

Except

On Ex: EdivByZero do ShowMessage('Ділення на нуль');

End;

У цьому прикладі повідомлення про виникнення ИС буде видане тільки у випадку, коли ИС буде тільки ділення на нуль (EdivByZero). У всіх інших випадках ИС буде відвернена, однак ніякого повідомлення про її виникнення видано не буде. Оголошена в блоці Except - End змінна Ex може бути будь-яким ім'ям (тут Ex використовується тільки для прикладу).

13.12. Оператор Try - Finally - End

Блок Try - Finally - End також використовується для запобігання ИС, які можуть виникнути при виконанні програми. На відміну від блоку Try - Except - End блок Try - Finally - End використовується для звільнення ресурсів пам'яті, закриття файлів і пр. у разі виникнення ИС.

Синтаксис:

Try

{оператори, здатні генерувати ИС}

Finally

{оператори звільнення ресурсів пам'яті }

end;

Блок Try - Finally - End працює таким чином. Виконання починається з операторів блоку Try - Finally, які в правильно написаній програмі повинні містити оператори виділення ресурсів пам'яті. Якщо в якому-небудь операторі виникає ИС, то управління відразу передається до операторів блоку Finally - End, де проводиться звільнення пам'яті, закриття файлів і пр. У результаті, з одного боку, запобігається аварійне переривання програми і, у других, коректно звільняється раніше зарезервована пам'ять, виконується ряд інших необхідних операцій.

Відмітимо, що блок Finally - End виконується завжди незалежно від того, була або не була сгенерирована ИС.

Приклад.

i:= 0;

n:= 8;

Try

GetMem (р, 8000); {виділення пам'яті}

i:= n div i; {Ділення на нуль. Оператор генерує ИС}

n:= i + 9;

Finally

FreeMem (р, 8000); {звільнення пам'яті}

End;

14. Покажчики

У мові є засіб, що дозволяє запитувати пам'ять динамічно, т. е. з потреби. Це дозволяє зменшити об'єм коду програми і економно витратити оперативну пам'ять. Такий засіб являє собою спеціальний тип, званий покажчиком. Є два типи покажчиків: покажчик на об'єкт деякого типу і покажчик без типу.

Тип Pointer утворить покажчик без типу. Покажчик на тип має синтаксис:

^ Ім'я типу

Приклади оголошення покажчиків:

Type

tDinArr = Array[1. . 1000, 100] of String[255]; {звичайний тип}

tDinArrPtr = ^tDinArr; {покажчик на тип tDinArr}

tRecPtr = ^tRec; {покажчик на тип запису, який описаний нижче}

за tTRec = Record {звичайний тип-запис}

А: Integer;

У: Real;

З: String[255];

End;

Var

DinArr: tDinArr; {звичайний запис}

DinArrPtr: tDinArrPtr; {покажчик на тип}

RecPtr: tRecPtr; {покажчик на тип-запис}

Pn1, Pn2: Pointer; {покажчики без типу}

Модулі System і SysUtils містять велику кількість типів для роботи з покажчиками. Ці типи можуть бути використані для підвищення ефективності призначених для користувача програм, в яких використовуються покажчики. До їх числа відносяться: PAnsiString, PString, PByteArray, PCurrency, PExtended і ряд інших покажчиків. Проте, ці типи можуть бути легко замінені стандартними типами. Наприклад PString еквівалентний ^String і т. д.

14.1. Операції з покажчиками

Для покажчиків допустимі операції привласнення і порівняння. Покажчику можна привласнювати:

вміст покажчика такого ж типу;

константу Nil (пустий покажчик);

адреса об'єкта за допомогою функції Addr;

адреса за допомогою оператора @;

адрес, побудований функцією Ptr.

Приклад:

TrPt:= Nil;

Klo1Ptr:= Klo2Ptr;

P1:=@Pp; {еквівалентне P1:= Addr(Pp);}

P2:= Ptr($B701);

14.2. Стандартні процедури і функції для роботи з покажчиками

Procedure GetMem(Var: Р: Pointer; Size: Word);

Виділяє блок пам'яті розміру Size і привласнює адресу початку блоку покажчику Р: Pointer; Size: Word);

Звільняє блок пам'яті розміру Size, адресований покажчиком

Var

F1, F2: file; {оголошення файлових змінних}

Buffer: PChar; {оголошення покажчика на рядок }

begin

AssignFile(F1, ' t1.txt'); {скріплення F1 з файлом ' t1.txt'}

Reset(F1, 1); {файл відкритий для введення/висновку}

AssignFile(F2, ' t2.txt'); {скріплення F2 з файлом ' text.txt'}

Rewrite(F2, 1); {файл відкритий для висновку}

try

Size: = FileSize(F1); {обчислення розміру файла}

GetMem(Buffer, Size); {виділення пам'яті під читання файла}

try

BlockRead(F1, Buffer^, Size); {лічення всього файла ' t1.txt'}

BlockWrite(F2, Buffer^, Size); {запис в файл ' t2.txt'}

finally

FreeMem(Buffer); {звільнення пам'яті}

end;

finally

CloseFile(F1); {закриття файла F1}

CloseFile(F2); {закриття файла F2}

end;

end;

У цьому прикладі оголошений покажчик на рядок Buffer із завершальним нулем, який буде використана для копіювання файла ' t1.txt' в файл ' t2.txt'. Для цього оператором GetMem для змінної Buffer^ буде динамічно виділений блок пам'яті розміром, рівним розміру файла. Далі оператором BlockRead файл ' t1.txt', пов'язаний файлової змінної F1, буде прочитаний в Buffer^ і потім оператором BlockWrite змінна Buffer^ буде записана в файл ' t2.txt', пов'язаний з файлової змінної F2. Для запобігання винятковим ситуаціям приклад містить два вкладених блоки try - finally - end. Внутрішній блок обслуговує можливий збій в ситуації, коли по якій-небудь причині файл не вдалося прочитати або записати операторами BlockRead або BlockWrite. Такий спосіб гарантує звільнення пам'яті оператором FreeMem як у разі успішного копіювання, так і у разі можливого збою. Зовнішній блок обслуговує ситуацію, коли у системи можливо немає того об'єму пам'яті, який запитує оператор GetMem. У будь-яких варіантах - при успішному або безуспішному копіюванні файла - наступні за останнім finally оператори CloseFile закриють відкриті операторами Reset і Rewrite файли F1 і F2 і дозволяє програмі продовжити роботу.

Procedure New(Var: Р: Pointer);

Створює нову динамічну змінну того типу, на який посилається покажчик. Еквівалентна оператору GetMem(Р, SizeOf(Р^));

Procedure Dispose(Var: Р: Pointer);

Знищує динамічну змінну, на яку вказує P. Еквівалентна оператору FreeMem(Р, SizeOf(Р^));

Procedure ReallocMem(var Р: Pointer; Size: Integer);

Процедура працює таким чином:

якщо Р= Nil і Size = 0, то оператор не виконає ніяких дій;

якщо Р= Nil і Size > 0, то оператор спрацює аналогічно GetMem;

якщо Р < > Nil і Size = 0, то оператор спрацює аналогічно FreeMem.

Function Addr(X): Pointer;

Адреса вказаного імені.

14.3. Інші процедури і функції для роботи з покажчиками

В модулях System і SysUtils оголошені процедури і функції, які можуть знайти застосування в призначених для користувача програмах. Нижче даний опис деяких функцій і процедур.

Function GetHeapStatus: THeapStatus;

Розташована в модулі System. Дає зведення про стан розподіленій і доступній програмі пам'яті. Тип функції має вигляд

THeapStatus = record

TotalAddrSpace: Cardinal;

TotalUncommitted: Cardinal;

TotalCommitted: Cardinal;

TotalAllocated: Cardinal;

TotalFree: Cardinal;

FreeSmall: Cardinal;

FreeBig: Cardinal;

Unused: Cardinal;

Overhead: Cardinal;

HeapErrorCode: Cardinal;

end;

Function AllocMem(Size: Cardinal): Pointer;

Виділяє блок пам'яті і встановлює кожний байт "в нуль". Звільнення пам'яті можна виконати за допомогою процедури FreeMem.

Procedure GetMemoryManager(var MemMgr: TMemoryManager);

Дає поточний стан менеджера пам'яті - спеціального запису з типом:

TMemoryManager = record

GetMem: function(Size: Integer): Pointer;

FreeMem: function(Р: Pointer): Integer;

ReallocMem: function(Р: Pointer; Size: Integer): Pointer;

end;

Procedure SetMemoryManager(var MemMgr: TMemoryManager);

Встановлює менеджер пам'яті - виконує операції виділення і звільнення пам'яті відповідно до заздалегідь встановлених в менеджерові пам'яті значеннями.

14.4. Глобальні змінні AllocMemCount і AllocMemSize

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

AllocMemCount - кількість блоків виділеної пам'яті.

AllocMemSize - розмір блоків виділеної пам'яті.

15. Підпрограми

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

У мові Object Pascal є два вигляду підпрограм - процедури і функції. Структура всякої підпрограми багато в чому нагадує структуру початкового модуля. Кожна така підпрограма перед її використанням повинна бути описана. Описом підпрограми називається її початковий код, а зверненням до підпрограми є оператор або його частина, які містять код виклику такої підпрограми. Таким чином, опис - це технологія, а звертання - це дії по наказаній технології.

Всяка підпрограма може мати локальні і глобальних по відношенню до неї параметри. Локальним є параметр, дія якого обмежена тільки підпрограмою, в якій він описаний. Всякий інший параметр буде глобальним. Всі глобальні параметри завжди описані за межами підпрограми, в якій вони використовуються.

15.1. Процедури

Всяка процедура має заголовок і тіло. Тіло процедури складається з операторів, призначених для опису імен і дій над даними. Синтаксис процедури має вигляд

Procedure procedureName(parameterList); directives;

localDeclarations;

begin

statements;

end;

Тут

Name - ім'я процедури,

parameterList - список формальних параметрів,

directives - директиви,

localDeclarations - внутрішні описи,

statements - оператори тіла процедури.

procedureName - ім'я процедури. Ім'ям процедури може бути будь-яке ім'я, не співпадаюче ні з яким іншим описаним в тому ж, що і процедура, блоці, ім'ям.

parameterList - список формальних параметрів може бути або пустий (у цьому разі дужки можна не використати), або повинен містити послідовність вхідних і/або вихідних величин. Окрема величина в описі заголовка може бути:

оголошеної за допомогою слова var змінної з типом або без типу;

константою;

вихідною величиною (т. н. out-параметром).

Приклад опису процедури.

procedure ByRef(var X: Integer; L, K: Integer);

begin

X: = X * 2 * L; {правильне}

K: = 2 + L; {помилка}

end;

Процедура з ім'ям ByRef містить три параметри - змінну X і дві константи L і K. Тело процедури складається з операторів, укладених в операторних дужках begin - end. Змінні L, K є тільки вхідними і не можуть бути змінені в тілі процедури. З цієї причини оператор K:= 2 + L не дасть результату і значення До залишиться таким же, яким воно було до звернення до процедури. Навпаки, змінна X, оголошена за допомогою слова var, буде обчислена і на виході буде мати те значення, яке буде обчислене всередині процедури ByRef.

Out-параметр виявляє пряму протилежність константі, він повинен бути тільки вихідною, визначуваною всередині процедури, величиною. Наприклад, в наступному коді

procedure GetInfo(out Info: SomeRecordType);

var MyRecord: SomeRecordType;

...

Proc1(MyRecord);

...

змінна MyRecord не може передавати дані в процедуру Proc1. Навпаки, тільки Proc1 може сформувати дані і передати їх в MyRecord.

Тип параметра може бути будь-яким. Однак не можна оголошувати новий тип прямо в заголовку підпрограми. Такий тип повинен бути оголошений раніше і тільки після цього може бути використаний в заголовку підпрограми.

localDeclarations - внутрішні описи можуть містити опис локальних імен типів або змінних. У попередньому прикладі змінна MyRecord типу SomeRecordType, оголошена всередині процедури GetInfo, є зразком такого опису.

directives - директиви використовуються для того, щоб дати компілятору деякі додаткові вказівки про процедуру, що описується. Директиви описані в параграфі 15.3.

Для виклику процедури, т. е. для звернення до закладеного в ній алгоритму, потрібно записати оператор, в якому на місце формальних параметрів повинні бути підставлені фактичні параметри. Наступний приклад містить як опис процедури MatrMult, так і звернення до неї.

Program {почало програми}.

..

Const n = 10; {розмір матриць}

Type tMatr = array[1.. n, 1.. n] of Real; {тип матриць}

Var Q1, Q2, Q3: tMatr; {опис матриць}

Procedure MatrMult(M1, M2: tMatr; Var M3: tMatr); {заголовок}

Var i, j, k: Integer;

Begin

For i:= 1 to n do

For j:= 1 to n do

Begin {блок визначення одного елемента матриці M3}

M3[i, j]:=0;

For k:=1 to n do

M3[i, j]:= M3[i, j] + M1[i, k] * M2[k, j];

End;

End; {кінець опису процедури MatrMult}

Procedure Prim; {заголовок процедури Prim}

Var i, j: Integer;

Begin

For i:= 1 to n do {блок завдання елементів матриць Q1, Q2}

For j:= 1 to n do

Begin

Q1[i, j]:=i + j;

Q2[i, j]:=i - j;

End;

MatrMult(Q1, Q2, Q3); {оператор звернення до процедури MatrMult}

End; {кінець опису процедури Prim}.

.. {текст головної програми}

Prim; {звернення до процедури Prim}

Q3[2, 3]:= 1;

...

Приведений в даному прикладі текст програми можна розділити на чотири частини:

опис глобальних констант і змінних;

текст процедури MatrMult;

текст процедури Prim;

текст головної програми.

У верхній частині описана глобальна константа n = 10, яка використовується у всіх наступних за цим структурах. Так, в секції Type оголошений тип речовинного квадратного масиву tMatr. Далі в секції Var оголошені три змінні - матриці Q1, Q2, Q3 типи tMatr.

Далі даний текст процедури MatrMult, яка представляє алгоритм перемноження матриць M1 і M2 із записом результату в змінну M3. Матриці M1, M2 в процедурі не міняються, тому їх необов'язково оголошувати змінними (з позицій процедури MatrMult змінні M1, M2 виступають як константи). Навпаки, матриця M3 виходить як результат, визначуваний всередині процедури MatrMult, тому вона оголошена в заголовку словом Var. Неоголошення M3 як змінної привело б до помилки: змінені всередині процедури значення цієї матриці не були б зафіксовані. Змінні i, j, k, оголошені всередині процедури, є локальними і діють тільки в межах цієї процедури.

Опис процедур закінчується процедурою Prim. У тілі цієї процедури оголошено дві локальні змінні i, j, що виконують допоміжну роль лічильників циклів. Далі розташоване два вкладених один в одну циклу, за допомогою яких визначаються елементи матриць Q1 і Q2. По відношенню до процедури Prim ці матриці є глобальними змінними і, отже, вони доступні не тільки у зовнішньому блоці, але і всередині процедури Prim. І нарешті, в нижній частині розташований оператор звернення до процедури MatrMult, який призначений для виклику алгоритму перемноження матриць.

У нижній частині програми даний фрагмент тексту головної програми, вмісної виклик процедури Prim.

Опишемо механізм обчислень, який запускається приведеною програмою. Спочатку буде виконана процедура Prim (звернення до неї міститься в самої нижній частині тексту прикладу). Ця процедура без параметрів, тому управління буде відразу передане в тіло процедури, де почнеться послідовне виконання операторів, що містяться в йому. Спочатку будуть виконані два вкладених цикли For, де елементи матриць Q1, Q2 будуть заповнені значеннями (наприклад Q1[1, 1] = 2, Q2[1, 1] = 0 і т. д.). Далі вже всередині Prim станеться звернення до процедури MatrMult. При цьому спочатку станеться підстановка фактичних параметрів Q1, Q2, Q3 на місце відповідних формальних параметрів M1, M2, M3. Далі управління буде передане всередину процедури MatrMult, де аналогічно послідовним виконанням її операторів станеться перемноження матриць. Після виконання процедури MatrMult управління буде передане в ту ж точку, з якою проводився її виклик. Оскільки виклик MatrMult проводився з Prim, то управління буде знову повернене в процедуру Prim до оператора, розташованого услід за оператором виклику MatrMult. Оскільки в Prim більше немає невиконаних операторів, то вона також закінчує свою роботу і управління передається в ту алгоритмічну одиницю, яка і викликала Prim, а саме в головну програму, до оператора Q3[2, 3]: = 1.

15.2. Функції

На відміну від процедури функція призначена для обчислення одного значення будь-якого типу. Тип функції вказується в кінці її заголовка. Тип значення, що повертається відділяється від списку формальних параметрів символом ":" (двокрапка). Крім того, в тілі функції, принаймні, один раз повинне бути визначене значення функції. Це значення привласнюється імені функції або змінній Result.

Синтаксис функції має вигляд

function functionName(parameterList): returnType; directives;

localDeclarations;

begin

statements;

end;

Тут functionName - ім'я функції; ParameterList, directives, localDeclarations, statements мають те ж значення, що і в процедурі; ReturnType - тип результату, що повертається.

Приклад.

Function Fact(n: Word): LongInt; {заголовок функції Fact}

Var i: Word; j: LongInt;

Begin

j:=1;

if (n > 1) then

For i:= 2 to n do j:= j * i;

Result:= j;

End; {кінець опису функції Fact }.

.. {текст головної програми}

Var r: Real;

...

r:= 3.4 * Fact(3) / 2.5 / (122 - Fact(5)); {звернення до функції Fact}.

..

У цьому прикладі описана функція з ім'ям Fact обчислення факторіала n! ненегативного цілого числа. Тип функції визначений як LongInt. У тілі функції розміщений оператор Result:= j, який визначає результат, що повертається функцією. Спосіб звернення до функції демонструє останній оператор прикладу. Видно, що спосіб звернення до функції має істотну відмінність від способу звернення до процедури. Так, в цьому операторі звернення до функції Fact проводиться двічі - один раз з фактичним параметром 3, інший - з параметром 5. Далі повернені результати (відповідно, 6 і 120) будуть підставлені у вираження правої частини оператора, після чого останній буде обчислений і змінна r набуде речовинного (Real) значення 4.08.

15.3. Параметри без типу

Це особливий вигляд параметрів, який може бути використаний тільки в заголовках імен процедур і функцій. Кожний параметр без типу повинен бути описаний як var, const або out-параметр. Наприклад:

procedure TakeAnything(const З);

описує З як константу без типу.

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

Однак є одне виключення: при зверненні до підпрограм, вмісних параметри без типу, не можна використати числові значення або нетипізовані числові константи.

Наступний приклад використовує параметри без типу в функції Compare, яка порівнює розміри двох змінних V1 і V2 і повертає відповідь у вигляді константи -1, якщо розмір V1 менше розміру V2, нуль - якщо розміри однакові, 1 - якщо розмір V1 менше розміру V2.

function Compare(var V1, V2): ShortInt;

Var i, j: LongInt;

Begin

I:=SizeOf(V1);

J:=SizeOf(V2);

If (I < J) then Result:= - 1

Else

If (I > J) then Result:= 1

Else Result:= 0;

End;

Приклади звернень до функції Compare:

type

TVector = array[1..10] of Integer;

TPoint = record

X, Y: Integer;

end;

var

Vec1, Vec2: TVector;

N, i: Integer;

Р: TPoint;

...

i:= Compare(Vec1, Vec2); {0, розміри однакові}

Vec[1]:= Compare(i, Vec1); {- 1, розмір i менше розміру Vec1}

P.X:= Compare(Vec1, Р); {1, розмір Vec1 більше розміру Р}

P.Y:= Compare(i, Р); {- 1, розмір i менше розміру Р}

Vec2[8]:= Compare(i, P.X); {0, розміри i і поля P.X однакові}.

..

15.4. Декларації процедур і функцій

Заголовок процедури або функції може містити декларацію. Декларація вказується відразу услід за списком параметрів в процедурі або за типом результату, що повертається в функції.

1. Декларації про виклик по угоді (calling convention). До їх числа відносяться декларації register, pascal, cdecl, stdcall і safecall, наприклад:

function MyFunction(X, Y: Real): Real; cdecl;

Цей вигляд декларацій призначений для завдання способу передачі параметрів в процедуру. Декларації register, pascal передають параметри зліва направо, cdecl, stdcall і safecall - навпаки, праворуч наліво.

Директиви near, far і export призначені для розмежування способів звертання в 16-розрядних додатках. Для сучасних 32-розрядних додатків вони не мають значення.

Відмітимо, що згадані декларації використовуються в складних, вельми тонких ситуаціях і для початківця програміста не представляють великого інтересу.

2. Директива Forward вказує на те, що заголовок процедури або функції оголошений раніше, ніж описана сама підпрограма, наприклад:

function Calculate(X, Y: Integer): Real; forward;

...

function Calculate;

...

begin.

..

end;

3. Директива External вказує на те, що текст процедури міститься в окремому об'єктному (відкомпілювати) модулі. Такий спосіб дозволяє приєднати об'єктний код до програми, що компілюється з вказаного модуля. Для цього необхідно указати директиву компілятора з посиланням на модуль, в якому міститься об'єктний код процедури, що декларується, наприклад:

{$L BLOCK.OBJ}.

..

procedure MoveWord(var Source, Dest; Count: Integer); external;

procedure FillWord(var Dest; Data: Integer; Count: Integer); external;

Цей приклад показує, що при компіляції коди процедур MoveWord і FillWord потрібно шукати в об'єктному коді BLOCK.OBJ.

4. Директива OverLoad дозволяє використати одне ім'я для декількох підпрограм, наприклад:

function Divide(X, Y: Real): Real; overload;

begin

Result: = X/Y;

end;

function Divide(X, Y: Integer): Integer; overload;

begin

Result: = X div Y;

end;

У цьому прикладі описані дві функції з одним ім'ям Divide. При зверненні до функції з таким ім'ям викликана буде та функція, фактичні параметри якої відповідають формальним параметрам. Так, при звертанні у вигляді Divide (6.8, 3.2) буде викликана перша функція, т. до. її формальні параметри також речовинні, а при звертанні Divide(6, 8) буде викликана друга функція.

Директива Overload дозволена для підпрограм, в яких можуть розрізнюватися тільки типи параметрів, тому недопустимі описи вигляду

function Cap(S: string): string; overload;

procedure Cap(var Str: string); overload;

15.5. Процедурні типи

Процедурні типи допускають використання процедур і функцій у вигляді значень, які можуть бути привласнені змінним або передані в інші процедури або функції. Наприклад, в нижченаведеному прикладі визначена функція Calc з двома цілочисельними формальними параметрами X, Y, що повертає цілий тип:

function Calc(X, Y: Integer): Integer;

Ця функція може бути визначена як тип для змінної F:

var F: function(X, Y: Integer): Integer;

і пов'язана з цією змінною оператором привласнення:

F: = Calc;

Точно так само можна визначити будь-який інший новий процедурний тип і змінну:

Type {оголошення процедурних типів}

TIntegerFunction = function: Integer;

TProcedure = procedure;

TStrProc = procedure(const S: string);

TMathFunc = function(X: Double): Double;

Var {оголошення процедурних змінних}

F: TIntegerFunction; {F функція без параметрів, повертаюча ціле}

Proc: TProcedure; {Proc - процедура без параметрів}

SP: TStrProc;

M: TMathFunc;

При використанні операторів над процедурними типами і процедурами або функціями необхідно розрізнювати скріплення процедурної змінної і звернення до процедури або функції. Так в нижченаведеному прикладі появляються змінна F типу функції, а змінна I - простого цілочисельного типу, потім слідує текст процедури SomeFunction:

F: function(X: Integer): Integer;

I: Integer;

function SomeFunction(X: Integer): Integer;

...

У операторной частині перший оператор зв'язує F з конкретною функцією, не виконуючи над нею ніяких дій:

F: = SomeFunction;

навпаки, оператор

I: = F(4);

викликає цю функцію (запускає її алгоритм) і після обробки повертає результат обчислень змінної 15.6. Формальні і фактичні параметри

В Object Pascal є поняття формального і фактичного параметрів. Формальним називається параметр, який міститься в заголовку опису підпрограми, а фактичним - параметр в зверненні до підпрограми. Так, у вищенаведеному прикладі параметр X є формальним, а значення 4 - фактичним.

При виклику підпрограм необхідно мати на увазі наступне:

фактичні значення або константи повинні бути сумісні по типу з оголошеними формальними параметрами;

фактичні var або out-параметри повинні бути ідентичні по типу оголошеним формальним параметрам, виключенням є тільки нетипізовані параметри;

формальним параметрам без типу не можуть відповідати такі фактичні параметри, як числові значення і нетипізовані числові константи.

Приведемо ще один приклад, що демонструє способи звернення до підпрограм.

Const

IntCount = 1200;

Type

TFunc12 = Function(c1, c2: Integer): Integer;

Function Func12_1(k1, k2: Integer): Integer;

Begin

Result:= k1 + k2;

End;

Function Func12_2(g1, g2: Integer): Integer;

Begin

Result:= g1 - g2;

End;

Procedure AnyPro(u1: Real; Var u2: Real; Var u3; Const u4: Integer; F: tFunc12);

Begin

u2:= u1 + u4 + F(u4, Round(u4 * 3.14));

u3:= u1 - u4 - F(u4, Round(u4 * 3.14));

End;

Var

k: Integer;

v1, v2: Real;

ss: String;

...

{приклади звернення до процедури AnyPro:}

AnyPro(v1, v2, v1, v2, Func12_1);

AnyPro(v1, v2, ss, v1, Func12_2);

AnyPro(k, v1, ss, v2, Func12_1);

AnyPro(k + 8, v2, ss, IntCount, Func12_1);

AnyPro(8, v2, ss, v1+6.7, Func12_2);

Параметри u1, u2, u3, u4, F в заголовку процедури AnyPro, є формальними параметрами: u1 - константа типу Real; u2 - змінна типу Real; u3 - змінна без типу; u4 - константа типу Integer; F - параметр-функція типу TFunc12, який оголошений вище в секції Type.

Параметри, взяті в дужки в прикладах звернення до процедури AnyPro, є фактичними параметрами. Такі параметри можуть бути значеннями (8), константами (IntCount), змінними (v1), виразами (k + 8), іменами процедур або функцій (Func12_1) і інш.

15.7. Область дії імен

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

Глобальні параметри можуть бути описані в тому ж модулі, який містить використовуючу їх підпрограму, або в іншому модулі, на який є посилання в списку uses. Якщо два параметри мають однакове ім'я і один з них описаний всередині підпрограми, а іншої - поза нею, то діє той параметр, який описаний в підпрограмі. Аналогічно визначається область доступності параметрів описаних в різних модулях. Таким чином, при описі імен діє наступний принцип: більш пізнє оголошення відміняє область дії раніше описаних імен. Всередині однієї підпрограми не можна оголошувати двох і більш однакових імен.

Пояснимо область дії імен на прикладі наступного модуля

Unit Mod4;

interface

uses Mod1, Mod2, Mod3;

...

Type

Vr = Integer; {допустимо}.

..

Var

Vr: Real; {недопустимо}.

..

implementation

Var Vr: Char; {недопустимо}.

..

procedure Pro1; {не містить внутрішнього оголошення імені Vr}.

..

procedure Pro2; { містить внутрішнє оголошення імені Vr}

Var

Vr: String; {допустиме}

Vr: Real; {недопустимо}.

..

У приведеному тексті модуля Mod4 міститься декілька описів імені Vr, частина яких допустима, інша частина помилкова. Недопустимий опис цього імені:

в var-секції в розділі interface, оскільки воно вже використане в цьому ж розділі вище - в секції type;

в var-змінній в розділі implementation, оскільки воно вже використане в цьому ж модулі в розділі interface;

як змінної типу Real в тілі процедури Pro2, т. до. воно вже використане в цій же процедурі при описі String-змінної.

Більш пізнє оголошення відміняє дію раніше описаного імені. Так, всередині процедури Pro2 ім'я Vr представляє змінну типу String, а всередині процедури Pro1 ім'я Vr діє як глобальний тип Integer, оголошений вище - в секції type.

Якби це ім'я взагалі не було описане в модулі Mod4, але було б оголошено в одному або декількох модулях, вказаних в посилальний списку uses, то воно могло б бути використане як глобальний параметр всередині цього модуля (Mod4). При цьому діяло б те ім'я, яке оголошене в розділі interface самого останнього вмісного його модуля списку uses. Наприклад, якщо є опис імені Vr в модулях Mod1 і Mod2, то діяв би опис з Mod2. Якщо в списку uses поміняти Mod1 і Mod2 місцями, то буде діяти опис, який виконаний для цього імені в модулі Mod1.

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

Function Deccy(х: Integer): Integer;

Begin

d:= d - х;

Deccy:= Sqr(х);

End;

...

d:= 3; a:= Deccy(3) * Deccy(d); {а= 0, d= 0}

d:= 3; a:= Deccy(d) * Deccy(3); {а= 81, d= -3}

Приклад показує, що два, здавалося б, коректних способу звернення до функції дають проте різні результати обчислень.

15.8. Рекурсивні процедури і функції

В Object Pascal допустимо звертання підпрограми до самої собі (рекурсивне звертання). При такому звертанні параметри, які використовує підпрограма, заносяться в стек і зберігаються там до кінця роботи підпрограми. Рекурсивні підпрограми є виключно зручним, нерідко незамінним інструментом побудови ефективних алгоритмів. Оборотною стороною рекурсивних процедур є небезпека переповнення стека, що часто обмежує можливість написання таких алгоритмів.

Як ілюстрація приведемо приклад простій і надзвичайно ефективної процедури сортування (розставляння елементів в порядку неубування) фрагмента цілочисельного одномірного масиву А:

procedure QuickSortPart(var А: array of Integer; iLo, iHi: Integer);

var

Lo, Hi, Mid, Т: Integer;

begin

Lo: = iLo;

Hi: = iHi;

Mid: = А(Lo + Hi)[ div 2]; {середній елемент фрагмента}

repeat {ділення фрагмента на ліву і праву частини}

while А[Lo] < Mid do Inc(Lo);

while А[Hi] > Mid do Dec(Hi);

if Lo < Hi then

begin

Т: = А[Lo];

А[Lo]: = А[Hi];

А[Hi]: = Т;

Inc(Lo);

Dec(Hi);

end;

until Lo > Hi;

if Hi > iLo then QuickSortPart(А, iLo, Hi); {сортування лівої частини}

if Lo < iHi then QuickSortPart (А, Lo, iHi); {сортування правої частини}

end;

Процедура QuickSortPart сортує фрагмент одномірного масиву А, що починається індексом iLo і що закінчується індексом iHi. Процедура заснована на методі половинного ділення. Відповідно до цього методу спочатку вибирається елемент, розташований в середині фрагмента, що сортується, потім елементи менші його відправляються в ліву частину фрагмента, інші - в праву частину. Далі сортуються ліва і права частини розділеного масиву як окремі фрагменти по тій же схемі, т. е. до кожної з них застосовується та ж процедура QuickSortPart. Саме звертання процедури до самої собі і робить її рекурсивної.

Нижче приведена звичайна (нерекурсивна) процедура QuickSort сортування всіх елементів масиву, яка виконується зверненням до рекурсивної процедури QuickSortPart, де фрагмент - весь масив A.

procedure QuickSort (var А: array of Integer);

begin

QuickSortPart(А, Low(А), High(А));

end;

15.9. Параметри і конструктори відкритих масивів

Відкриті масиви допускають передачу масивів різного розміру як параметри в процедурах і функціях. У цьому випадку можна оголосити масив у вигляді

array of type (переважніше за array[X. . Y] of type)

Наприклад, оператори

procedure NullChar(А: array of Char);

begin

for i:= Low(А) to High (А) do А[i]:= '0';

end;

оголошують процедуру NullChar, яка містить один параметр - відкритий символьний масив А будь-якого розміру. У тілі процедури використовується оператор циклу, який заповнює кожний елемент масиву символом '0'. Для визначення нижньої межі індексу використана стандартна функція Low, для верхньої - High.

Якщо до такої процедури звернутися оператором NullChar(z), де тип змінної z = array[5. . 55] of Char, то весь масив z буде заповнений символами "нуль".

Конструктори відкритих масивів допускають конструювання значень таких масивів прямо всередині оператора звернення до підпрограми.

Приклад:

var I, J: Integer;

procedure Add (А: array of Integer);

У цьому випадку можна звернутися до процедури Add, наприклад, так:

Add [5, 7, I, I + J];

16. Структура програми

В середовищі Delphi програма як єдине ціле представляється у вигляді проекту. У новій версії мови Object Pascal для представлення проекту використовується п'ять основних типів файлів:

dpr-файл головної програми;

текстові pas-файли;

відкомпілювати dcu-файли;

res-файли ресурсів;

dfm-файли ресурсів екранних форм;

готові до використання програмні ехе-файли.

Початкова програма, написана в середовищі Delphi на мові Object Pascal завжди складається з декількох модулів, кожний з яких розміщується в окремому текстовому файлі. Один модуль є головною програмою. Він починається словом Program і розміщується в файлі з розширенням. dpr. Всі інші модулі є підлеглими і починаються словом Unit. Такі модулі розміщуються в файлах з розширенням. pas. Всі модулі закінчуються оператором End, після якого ставиться символ "точка".

Всякий модуль може використати інші модулі, до числа яких можуть відноситися текстові файли, res- і dfm-файли ресурсів або відкомпілювати файли Unit-модулів. Посилання на необхідні до використання модулі міститься в секціях Uses. Текстові або скомпільовані файли звичайно містять необхідні для використовуючого їх модуля величини - константи, типи, змінні, процедури і функції. Файли ресурсів необхідні для підключення констант, що описують зовнішні ресурси, що використовуються.

Вищеперелічені модулі, розміщені в *.pas-, *.dcu-, *.res-, *.dfm-файлах, грають допоміжну роль: вони призначені для компіляції і подальшої зборки в повноцінний програмний модуль - ехе-файл, готовий до виконання на комп'ютері.

Нижче приведений приклад початкових текстів головної програми KdnBread і одного підлеглого (що використовується) нею модуля Main.

Program KdnBread; {початок тексту головної програми}

{текст міститься в файлі ' c:\Borland\Projects\KdnBread.pas'}

uses{ссилки на модулі типу unit }

Forms, {посилання на модуль Forms }

main in 'main.pas' {Form1}; {посилання на модуль main }

{$R *.RES}

begin

Application.Initialize;

Application.CreateForm(TForm1, Form1);

Application.Run;

end. {кінець тексту головної програми}

unit Main; {початок тексту модуля Main}

{ текст модуля міститься в файлі ' c:\Borland\Projects\Main.pas' }

interface{почати інтерфейсної частини модуля}

uses

Windows, Messages, SysUtils, {посилання на інші модулі }

Graphics, Controls, Forms, StdCtrls;

Type{опис типів}

TForm1 = class(TForm)

Button1: TButton;

L1: TLabel;

procedure Button1Click(Sender: TObject);

private

{ Private declarations }

public

{ Public declarations }

end;

Var{опис змінних}

Form1: TForm1;

b: boolean;

i: Integer;

IterationPar: Word;

function OneSymbString(з: Char; d: byte): String; {заголовок функції}

implementation {початок процедурного блоку модуля}

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject); {заголовок процедури}

begin

if (i > 12) and b then

L1.Caption:='Студент:'+AnsiUpperCase ('Иванов Володимир Іванович');

end; {кінець процедури}

function OneSymbString(з: Char; d: byte): String; {заголовок функції}

begin

Result:=CharStr(з, d);

end; {кінець функції}

initialization

IterationPar:= 0;

end. {кінець тексту модуля Main}

Виконання програми завжди починається з модуля Program, т. е. з головної програми. Program активізує виконання процедур і функцій в модулях, що використовуються нею Unit.

16.1. Структура модуля

Модуль має наступну структуру:

Unit < ім'я >;

interface

< інтерфейсна частина >

implementation

< частина, що виконується >

initialization

< блок ініціювання >

finalization

< блок завершення >

end.

16.2. Розділ Interface

Розділ Interface модуля Unit призначений для опису зовнішніх компонент: модулів, що використовуються, типів, констант, змінних, заголовків процедур і функцій. Так, у вищенаведеному прикладі в розділі Interface містяться:

в списку Uses - посилання на модулі Windows, Messages, SysUtils, Graphics, Controls, Forms, StdCtrls;

в секції Type - опис типу екранної форми - клас TForm1;

в секції Var - опис змінних Form1, b, i і опис заголов-ка функції OneSymbStr, призначеної для створення рядка d разів символів, що повторюються Ch.

16.3. Розділ Implementation

Розділ Implementation модуля Unit призначений для опису внутрішніх, т. е. доступних до використання тільки всередині даного Unit, компонент: типів, констант, змінних, процедур і функцій. Так, у вищенаведеному прикладі в розділі Implementation міститься опис процедури TForm1.Button1Click(Sender: TObject) і функції OneSymbStr.

16.4. Ініціювання і завершення модуля

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

Блок ініціювання initialization закінчується останнім оператором end модуля або, при наявності блоку завершення, продовжується до слова finalization.

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

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

Наприклад, модуль може закінчуватися наступними операторами:

...

Initialization {ініціювання}

Ga:= 0;

AssignFile(f, ' c:\Projects\BreadPro\First.dat');

Reset(f, SizeOf(Rec1));

New(AppMem);

Finalization {завершення}

Dispose(AppMem);

CloseFile(f);

End. {останній оператор модуля}

Якщо декілька модулів мають блоки ініціювання, то вони виконуються в тому порядку, в якому імена модулів розташовуються в списку Uses головної програми. Якщо декілька модулів містять блоки завершення, то вони виконуються в порядку, протилежному порядку переліку модулів в списку uses головної програми.

17. Файли

Файлом називається область даних на зовнішньому носії - жорсткому диску, дискеті і пр. Всякий файл має ім'я, що являє собою рядок символів. Розрізнюють звичайне ім'я (або просто ім'я) і повне ім'я. Під повним ім'ям розуміється абсолютна адреса файла, що складається з шляху і імені файла. Наприклад, рядок ' C:\Program Files\Folder1\Students.dat' є повним ім'ям. Воно складається з шляху ' C:\Program Files\Folder1' до файла і власне імені файла ' Students.dat'. Це означає, що файл ' Students.dat' розташований на диску З в папці (директорія) Program Files безпосередньо в подпапке (субдиректорії) Folder1.

Раніше згадувалося, що в мові Object Pascal існує три типи файлів:

< ім'я > = TextFile; {текстові файли}

< ім'я > = File; {файли без типу}

< ім'я > = File of < тип даних >; {файли з типом}

17.1. Файлова змінна

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

Скріплення файла з файловою змінною проводиться за допомогою стандартної процедури AssignFile, яка має заголовок:

AssignFile( < файлова змінна >, < ім'я файла > );

Наприклад, фрагмент

Var

f1: TextFile;

FullPath: String[60];

...

FullPath:= ' a:\a1.res';

AssignFile(f1, FullPath);

містить оголошення файлової змінної f1 текстового типу і рядка FullPath, які потім використовуються у виконавчій частині для вказівки повного імені файла і скріплення його з файлової змінної f1.

17.2. Текстові файли

Текстової файл - це послідовність символьних рядків змінної довжини. Всякий рядок завершується маркером кінця рядка, всякий текстовой файл завершується маркером кінця файла. Такі файли можна обробляти тільки послідовно. Один і той же текстовой файл не може бути відкритий одночасно для введення і висновку. Файлова змінна цього файла має тип TextFile або просто Text.

Для текстових файлів є дві стандартні файлові змінні - Input і Output, які не треба оголошувати окремо.

17.2.1. Процедури і функції для роботи з текстовим файлом

Procedure AssignFile(f: TextFile; FileName: String);

Зв'язує файлову змінну f з дисковим файлом FileName.

Procedure Append(f: TextFile);

Відкриває існуючий файл для додавання рядків в кінець файла. При відсутності файла виникає помилка введення/висновку.

Procedure Rewrite(f: TextFile);

Створює новий файл і відкриває його для висновку. Якщо файл існує, то він знищується і створюється як новий. Коли новий текстовой файл закривається, до нього автоматично додається маркер кінця файла.

Procedure Reset(f: TextFile);

Відкриває існуючий файл для читання і встановлює покажчик на перший рядок файла. При його відсутності виникає помилка введення/висновку.

Procedure Read(f: TextFile[; v1, v2,. .., vN]);

Читає дані з файла і заносить їх в змінні v1, v2,. .., vN. Змінні можуть мати символьний, рядковий або арифметичні типи.

Procedure Readln(f: TextFile[; v1, v2,. .., vN]);

Читає дані з файла цілими рядками і заносить їх в змінні v1, v2,. .., vN. Якщо список змінних пустий, то відбувається переміщення покажчика на наступний рядок.

Procedure Write(f: TextFile[; v1, v2,. .., vN]);

Записує дані із змінних v1, v2,. .., vN в файл в символьному вигляді.

Procedure SetTextBuf (f: TextFile; Var Buf[; Size: Integer]);

Встановлює буфер читання текстового файла. Процедура повинна бути викликана після AssignFile, але до першого виклику процедур читання. Буфер використовується для читання великих фрагментів файла, включаючи символи кінця рядків. Якщо розмір буфера не вказаний, то за умовчанням він приймається рівним 128.

Procedure CloseFile(f: TextFile);

Закриває текстовой файл.

Procedure Flush(f: TextFile);

Виводить вміст внутрішнього буфера в файл.

FunctionEof(f: TextFile): boolean;

Повертає True, якщо досягнуть кінець файла.

Function Eoln(f: TextFile): boolean;

Повертає True, якщо досягнуть кінець поточного рядка.

Function SeekEof(f: TextFile): boolean;

Повертає статус кінця файла.

Function SeekEoln(f: TextFile): boolean;

Повертає статус кінця рядка.

Приклад:

Var

F1, F2: TextFile;

Ch: Char;

St: String[255];

Buf: array[1..4096] of Char; { текстовой буфер розміром 4K}

begin

AssignFile(F1, ' T1.TXT');

SetTextBuf(F1, Buf); { великий буфер для прискорення читання}

Reset(F1); {F1 відкритий для читання}

AssignFile(F2, ' WOOF.DOG');

Rewrite(F2); {F2 створений як новий для висновку }

while not Eof(F1) do {поки не досягнуть кінець файла - виконувати}

begin

Read(F1, Ch); {читає один символ з файла F1}

Write(F2, Ch); {пише один символ в файл F2}

end;

CloseFile(F1); {файл F1 закритий}

CloseFile(F2); {файл F2 закритий}

Reset(F1); {F1 знов відкритий для читання}

Rewrite(F2); {F2 знов створений для висновку }

while not Eof(F1) do {поки не досягнуть кінець файла - виконувати}

begin

Readln(F1, St); {читає рядок з файла F1}

Write(F2, St); {пише рядок в файл F2}

end;

CloseFile(F1); {файл F1 закритий}

CloseFile(F2); {файл F2 закритий}

end;

Приведений фрагмент модуля є демонстраційним і призначений для копіювання файла ' T1.TXT' в файл ' WOOF.DOG'. У першому циклі While - do копіювання ведеться посимвольно, у другому циклі - порядково.

Приклад процедури, що записує в кінець текстового файла рядок символів:

Procedure AddStrToTextFile(nF, St:)(String);

Varf: Text;

Begin

AssignFile(f, nF);

If not FileExists(nF) then Rewrite(f) {не існує, створити і відкрити}

Else {інакше}

Begin

Reset(f); {існує, відкрити }

WhilenotEof(f)doReadln(f); {пересунути покажчик в кінець файла}

End;

Writeln(f, St); {записати рядок }

CloseFile(f); {закрити файл}

End;

До процедури можна звернутися, наприклад, так:

Var

S1: String[58];

S2: String[189];

...

AddStrToTextFile('c:\Files\ring.txt', ' Рядок символів');

AddStrToTextFile('ring.txt', S1);

AddStrToTextFile('ring.txt', S2);

17.3. Файли з типом

Файл складається з будь-яких однотипних компонент. Доступ до даних здійснюється через файлову змінну. На відміну від текстового файла в такому файлі допустимо прямий доступ до будь-якого запису, причому в рамках відкритого файла допустимо як записувати, так і читати записи.

Приклади оголошення файлової змінної для файлів з типом:

Var

F1: File of String[45];

F2: File of Real;

F3: File of tRecord24;

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

17.3.1. Процедури і функції для роботи з типізованим файлом

Procedure AssignFile(f: File of Type; FileName: String);

Зв'язує файлову змінну f з дисковим файлом FileName.

Procedure Rewrite(f: File of Type);

Створює новий файл і відкриває його. Якщо файл існує, то він знищується і створюється як новий.

Procedure Reset(f: File of Type);

Відкриває існуючий файл і встановлює покажчик на перший запис. При відсутності файла виникає помилка введення/висновку.

Procedure Read(f: File of Type[; v1, v2,. .., vN]);

Читає записи з файла і заносить їх в змінні v1, v2,. .., vN. Читання починається з того запису, на який встановлений покажчик. Типи файла і змінних повинні бути однакові.

Procedure Write(f: File of Type[; v1, v2,. .., vN]);

Записує дані із змінних v1, v2,. .., vN в файл. Виведення починається з того запису, на який встановлений покажчик. Якщо покажчик встановлений на існуючий запис, то при висновку вона буде заміщена новим записом. Якщо одночасно виводиться декілька записів, то буде заміщена така ж кількість існуючих записів. Типи файла і змінних повинні бути однакові.

Procedure Seek(f: File of Type; N: LongInt);

Переміщує покажчик на запис з номером N. Первая запис має порядковий номер 0.

Function FilePos(f: File of Type): LongInt;

Повертає номер запису, на який встановлений покажчик.

Procedure CloseFile(f: File of Type);

Закриває файл.

Function Eof(f: File of Type): boolean;

Повертає True, якщо досягнуть кінець файла.

Function FileSize(f: File of Type): LongInt;

Повертає кількість записів в файлі. Наприклад, Seek(f, FileSize(f)) встановить покажчик в кінець файла (після останнього запису).

Procedure Truncate(f: File of Type);

Знищує (відрубує) кінець файла починаючи із запису, на який встановлений покажчик.

17.4. Файли без типу

Файл складається з компонент однакового розміру. Тип даних не має значення. Доступ до даних здійснюється через файлову змінну. Як і в файлах з типом, в такому файлі допустимо прямий доступ до будь-якого запису, причому в рамках відкритого файла допустимо як писати, так і читати записи.

Файлова змінна може бути оголошена так:

Var F: File;

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

Відсутність типу запису дозволяє виконувати обробку файлів різних типів за допомогою універсальних процедур і функцій.

17.4.1. Процедури і функції для роботи з файлом без типу

Procedure AssignFile(f: File; FileName: String);

Зв'язує файлову змінну f з дисковим файлом FileName.

Procedure Rewrite(f: File);

Створює новий файл і відкриває його. Якщо файл існує, то він знищується і створюється як новий.

Procedure Reset(f: File[; Size: Word]);

Відкриває існуючий файл і встановлює покажчик на перший запис. При відсутності файла виникає помилка введення/висновку. Параметр Size вказує розмір запису файла, що відкривається. При його відсутності розмір запису за умовчанням рівний 1.

Procedure BlockRead(f: File; Var Buf; Count: Word[; Var Result: Word]);

Читає з файла Count записів в змінну Buf. Result - реально прочитана кількість записів.

Procedure BlockWrite(f: File; Var Buf; Count: Word[; Var Result: Word]);

Пише в файл перших Count записів із змінної Buf. Result - реально записана кількість записів.

Procedure Seek(f: File; N: LongInt);

Переміщує покажчик на запис з номером N. Первая запис має порядковий номер 0.

Function FilePos(f: File): LongInt;

Повертає номер запису, на який встановлений покажчик.

Procedure CloseFile(f: File);

Закриває файл.

Function Eof(f: File): boolean;

Повертає True, якщо досягнуть кінець файла.

Function FileSize(f: File): LongInt;

Повертає кількість записів в файлі. Наприклад, Seek(f, FileSize(f)) встановить покажчик в кінець файла (після останнього запису).

Procedure Truncate(f: File of Type);

Знищує (відрубує) кінець файла починаючи із запису, на який встановлений покажчик.

Мова Object Pascal не накладає ніяких обмежень на довжину запису (теоретично вона може мати розмір до 2 Гб).

Приклад опису і звернення до функції ReadFromFile, що читає з файла nF в позиції Pos запис r розміром Sz.

function ReadFromFile(nF: String; Pos: Word; Var r; Sz: Word): boolean;

Var

g: File;

Recs, ReadReal: Integer;

RecRead: boolean;

Begin

Assign(g, nF);

Recs:= FileSize(g) div Sz; {кількість записів в файлі}

RecRead:= (Pos < Recs); {запис з номером Pos є? }

if RecRead then begin {якщо запис є}

Reset(g, Sz); {відкрити файл}

try

Seek(g, Pos); {встановити покажчик на запис}

BlockRead(g, r, 1, ReadReal); {прочитати запис}

RecRead:= (ReadReal = 1); {прочитано успішно? }

finally

Close(g); {закрити файл}

end;

end;

Result:= RecRead;

end {ReadFromFile};

...

Type

tStud = Record

Fio: String [60];

Curs: byte;

Stipendiya, Room: boolean;

End;

Var Stud: tStud;

...

if ReadFromFile('base2.ff1', 12, Stud, SizeOf(Stud))

then Writeln('Запис з 12-й позиції прочитаний');

Приведемо ще приклад. У директорія ' c:\Bases\SdudBase' знаходиться файл ' AllStuds.bs', в якому зберігаються дані про студентів у вигляді записів типу

Type

TStud = Record {студент}

Fio: String[50]; {' Прізвище Ім'я По батькові'}

Born: byte; {Рік народження, наприклад, 1979}

Faculty: String[4]; {Факультет, наприклад, ' МТФ'}

Group: String[8]; {Група, наприклад, ' МТ 17-2'}

End;

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

Procedure StudsCopy(nF1, nF2: ShortString; BornYear: byte;

Var Count: Word; Var: Ind: ShortInt);

{nF1 - файл-джерело, nF2 - файл-приймач,

BornYear - необхідний рік народження,

Count - скопійовано записів,

Ind - індикатор контролю:

0 - нормально, 1 - було невірне читання, був невірний запис}

Var

g: tStud;

K, Sz, i, j: Word;

f1, f2: File;

Begin

Count:= 0; {ініціалізація лічильника}

Ind:=0; {спочатку передбачуваний нормальний процес, інакше Ind змінимо}

Sz:= SizeOf(g); {розмір одного запису}

K:= KdnFileSize(nF1, Sz); {кількість записів в файлі-джерелі}

If (K > 0) then {якщо в файлі-джерелі є запису }

Begin

Assign(f1, nF1); {файл-джерело зв'язуємо змінної f1}

Reset(f, Sz); {відкриваємо файл-джерело із записами розміру Sz}

Assign(f2, nF2); {файл-приймач зв'язуємо змінної f2 }

Rewrite(f2, Sz); {створюємо новий файл-приймач під записи розміру Sz}

try

For j:=1 to K do

Begin

BlockRead(f1, g, 1, i); {читання запису}

Case i of

1: {запис прочитаний}

if (g.Born = BornYear) then { студент має необхідний рік народження}

begin

BlockWrite(f2, g, 1, i); {запис в файл-приймач}

If (i > 0) then Inc(Count) {якщо записано правильно}

else

begin Ind:= 1; Break; End; {записано невірно, відразу вихід з циклу}

end; {if}

0: begin Ind:= - 1; Break; end; {запис не прочитаний, відразу вихід з циклу}

end; {Case}

end; {циклу For}

finally

CloseFile(f1); {закриваємо файл-джерело}

CloseFile(f2); {закриваємо файл-приймач}

end; {блоку try - finally - end}

End {If };

End {StudsCopy};

Оператори, реалізуючий копіювання необхідних даних в файл ' 1979.bs':

StudsCopy ('AllStuds.bs', ' 1979.bs', 1979, Count1979, Ind1979);

Case Ind1979 of

- 1: Writeln('Зафіксована помилка читання');

1: Writeln('Зафіксована помилка запису');

0: Writeln('Процес пройшов нормально');

end; {Case}

Writeln(' Скопійоване записів: ' + IntToStr(Count1979));

У цьому прикладі використана зовнішня процедура KdnFileSize {кількість записів в файлі }. Приведемо її текст:

function KdnFileSize(nF: ShortString, Siz: Word): LongInt;

{nF - ім'я файла, Siz - розмір одного запису }

Var

F: File;

L: LongInt;

Begin

L:=0;

If FileExists(nF) then

begin

Assign(f, nF);

Reset(f, 1);

L:= SizeOf(f);

If not (L mod Siz = 0) then Writeln('Файл ' + nF + має інший тип');

L:= L div Siz;

CloseFile(f);

End;

Result:= L;

End;

17.5. Процедури і функції для роботи з файлами

Ці підпрограми призначені для роботи з файлами, папками (директорія) і дисками.

Procedure ChDir(Dir: String);

Робить папку Dir поточною. Приклад: ChDir('c:\');

Procedure GetDir(D: Byte; Var Dir: String);

Повертає поточну папку на заданому пристрої. (D= 0 - поточний диск, 1 - диск А, 2 - диск В і т. д.). Приклад: GetDir(0, s);

Procedure RmDir(Dir: String);

Знищує задану папку. Папка не повинна містити вкладених папок або файлів. Приклад: RmDir('Folder66');

Procedure Erase(f);

Видаляє файл, пов'язаний з файлової змінної f. Файл повинен бути закритий.

Procedure Rename(f, FileName: String);

Перейменовує файл, пов'язаний з файлової змінної f. Файл повинен бути закритий. Приклад: Rename(g, ' studs.txt');

Function DiskFree(D: byte): LongInt;

Повертає кількість вільної пам'яті в байтах на пристрої D. Код драйвера задається так само, як в процедурі GetDir. Якщо код вказаний невірно, то повертає -1.

Function DiskSize(D: byte): LongInt;

Повертає кількість вільної пам'яті в байтах на пристрої D. Код драйвера задається так само, як в процедурі GetDir. Якщо код вказаний невірно, то повертає -1.

FunctionFindFirst(const Path: string; Attr: Integer;

var F: TSearchRec): Integer;

Знаходить ім'я першого файла із заданими атрибутами Attr в папці Path. Результат пошуку виводить в змінну F. Еслі пошук успішний, то функція поверне 0, інакше поверне код помилки Widows. До FindFirst можна звертатися не тільки як до функції, але і як до процедури.

Атрибути файла приведені в табл. 17.

Таблиця 17

Атрибут

Опис файлів

faReadOnly

faHidden

faSysFile

faVolumeID

faDirectory

faArchive

faAnyFile

Файли "Тільки для читання"

Приховані файли

Системні файли

Файл ID-значень

Папки (директорія)

Архіви (файли)

Всі файли

Тип, що характеризує знайдений файл, представляє запис вигляду:

type

TSearchRec = Record

Time: Integer; {час}

Size: Integer; {розмір файла в байтах}

Attr: Integer; {атрибути файла}

Name: TFileName; {DOS-шлях файла}

ExcludeAttr: Integer;

FindHandle: THandle;

FindData: TWin32FindData; {додаткова інформація про файл}

end;

Приклад:

Var

SR: TSearchRec;

S: String;

...

FindFirst('c:\Program Files\delphi4\bin\*.*', faAnyFile, SR);

if (SR.Attr = faArchive) then

S:= ' Файл ' + SR.Name + ' має розмір ' + IntToStr(SR.Size) + ' байт';

У даному прикладі процедура FindFirst шукає перший файл по масці '*.*' (всі файли) в папці ' c:\Program Files\delphi4\bin'. Атрибут faAnyFile означає, що пошук проводиться по всіх видах файлів, під якими розуміються папки (директорія), '.', '..' - посилання на поточну і батьківську папку, внутрішні папки і власне файли. Останні в термінології файлової атрибутики називаються архівами. Далі, якщо знайдений файл є архів, т е. файл в загальноприйнятій термінології, то в рядок S буде вміщене повідомлення. Наприклад, якщо знайдений файл має ім'я Ig.ttg і його розмір рівний 15899, то S= ' Файл Ig.ttg має розмір 15889 байтів'.

Function FindNext(var F: TSearchRec): Integer;

Знаходить наступний файл, атрибути якого вказані в FindFirst.

Procedure FindClose(var F: TSearchRec);

Закриває дію FindFirst/FindNext.

Function DeleteFile(const FileName: string): Boolean;

Видаляє файл на ім'я. Якщо файл не може бути видалений або не існує - повертає False.

Function CreateDir(const Dir: string): Boolean;

Створює нову папку.

FunctionGetCurrentDir: string;

Повертає поточну папку.

Function GetCurrentDir: string;

Повертає поточну папку.

Function SetCurrentDir(const Dir: string): Boolean;

Установка нової поточної папки.

Function RemoveDir(const Dir: string): Boolean;

Видалення папки. Перед видаленням папка повинна бути пустою.

Function ExtractFileDir(const FileName: string): string;

Виділяє з повного імені файла FileName папку, в якій міститься це файл.

Function ExtractFilePath(const FileName: string): string;

Виділяє з повного імені файла FileName шлях до файла.

Function ExtractFileExt(const FileName: string): string;

Повертає розширення файла FileName.

Function ExtractFileName(const FileName: string): string;

Повертає ім'я файла FileName (без розширення).

Function DirectoryExists(Dir: string): boolean;

Перевіряє існування директорія. Приклад:

if DirectoryExists('C:\APPS\SALES\LOCAL') then;

Function FileExists(FileName: string): boolean;

Перевіряє існування файла. Приклади:

У:= FileExists('C:\APPS\SALES\LOCAL\Fort.pas'); {повне ім'я}

В:= FileExists('Fort.pas'); {вказано усічене ім'я файла, перевірка його існування тільки в поточного директорія}

Procedure ForceDirectories(Dir: string);

Створює нового директорія.

Procedure ForceDirectories(C:\APPS\SALES\LOCAL).

П р і м е ч а н і е. До моменту звернення до процедури директорія APPS і SALES повинні існувати.

Приклад процедури видалення даних з поточного директорія, включаючи файли і вкладені папки.

Procedure DelInsideDir(FullDir: tPathStr);

Var

L: Integer;

Sr: TSearchRec;

dr, q: tPathStr;

begin

if ExistDir(FullDir) then {такого директорія є}

begin

GetDir(0, dr); {запам'ятати поточного директорія}

ChDir(FullDir); {поточним стає директорія},

що видаляється L:=FindFirst(Slash(FullDir)+'*.*', faAnyFile, Sr);{пошук першого файла}

try

While (L = 0) do begin {поки файли знаходяться}

Case Sr.Attr of

faDirectory:{знайдений файл - внутрішнього директорія}

if (Sr.Name < > '.') and (Sr.Name < > '..') then {це не посилання, директорія}

begin

{видалення внутрішнього вмісту директорія}

DelInsideDir(Slash(FullDir)+Sr.Name);

q:= Slash(FullDir)+Sr.Name;

ChDir(ExtractFilePath(q));

{видалення самого директорія (можна, т. до. вона тепер пуста)}

if NotEmpStr(ExtractFileName(q)) then RmDir(ExtractFileName(q));

end;

faArchive: DeleteFile(Sr.Name); {це файл, віддаляється}

end; {Кінець Case-оператора}

L:= FindNext(Sr); {наступний файл директорія}

end; {циклу While}

finally

FindClose(Sr); {закрити пошук файлів}

end; {try - finally - end}

ChDir(dr); {повернутися в поточного директорія}

end; {if}

end;{процедури}

Наприклад, якщо необхідно стерти дані з дискети, то це можна зробити за допомогою оператора: DelInsideDir('A:\');

18. Класи і об'єкти

В Object Pascal класами називаються спеціальні типи, які містять поля, методи і властивості. Попередником класу є застарілий нині тип мови Turbo Pascal, званий об'єктом. Об'єкт був введений в Turbo Pascal до створення Delphi. З появою Delphi в новій версії мови Object Pascal об'єкти, для сумісності зі старим програмним продуктом, збережені. Однак нині використання об'єктів не актуальне.

Клас являє собою покажчик. Однак на відміну від традиційних покажчиків це покажчик особливого типу: в ньому не можна використати символ "^" при зверненні до класу.

18.1. Инкаспуляция, успадкування і поліморфізм

Клас, об'єднуючи в собі поля, методи і властивості в єдине ціле, є закінченою структурною одиницею, призначеною для рішення окремої задачі. Звичайно такою задачею є задача дозволу деякого кола супутніх проблем. Так, клас TRichEdit являє собою могутній текстовой редактор rtf-файлів (файлів в форматі Rich Text Format), який призначений для організації перегляду і редагування файла, збереження і зміни розмірів і типів шрифтів, пошуку рядків символів і багато чого іншого. Таке об'єднання полів, методів і властивостей в єдине ціле називається инкаспуляцией.

У мові існує безліч класів (біля 300), які створені розробниками мови Object Pascal - співробітниками фірми Inprise International - для програмістів, що використовують середу Delphi. Такі класи можна назвати фірмовими.

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

Новий клас будується на основі іншого, більш простого, класу. Для цього в заголовку класу вказується його клас-родитель. Синтаксис заголовка нового класу має вигляд

type className = class (ancestorClass)

Тут className - ім'я нового класу; ancestorClass - ім'я класу-родителя. Новий клас автоматично успадковує поля, методи і властивості свого родителя і може поповнитися своїми полями, методами і властивостями. Ця властивість класів називається успадкуванням. Можливість успадкування дозволяє, слідуючи методу від простого до складного, створювати класи якої бажано міри складності. НайПростішим класом є клас TObject, який не містить полів і властивостей, однак має деяку безліч методів, що забезпечують створення, знищення і обслуговування цього класу і необхідних для нормального функціонування програми. Саме на основі цього загального для всіх класів прародителя будується дерево успадкування класів. Наприклад:

type TPersistent = class (TObject),

type TComponent = class (TPersistent),

type TControl = class (TComponent).

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

18.2. Синтаксис класу

Синтаксис всякого класу має вигляд

typeclassName = class (ancestorClass)

memberList

end;

Тут className - ім'я класу; class - ключове слово; ancestorClass - тип класу-родителя; memberList - список полів, методів і властивостей. Нижче приведений текст модуля main, вмісний клас TForm1.

unit main;

interface

uses

Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms;

type

TForm1 = class(TForm) {оголошення класу TForm1}

Button1: TButton; {поле}

L1: TLabel; {поле}

L2: TLabel; {поле}

Button2: TButton; {поле}

procedure Button1Click(Sender: TObject); {метод}

procedure FormActivate(Sender: TObject); {метод}

end;

Var i: Integer;

implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject); {опис методу}

begin

L1.Caption:= DateTimeToStr(Date);

L2.Caption:= TimeToStr(Time);

end;

procedure TForm1.FormActivate(Sender: TObject); {опис методу}

begin

i:=125;

end;

end.

18.3. Поля класу

Полем може бути будь-якою инкаспулированний в клас тип або інший клас, наприклад:

type

TKdnClass = class(TObject)

i, j: integer;

s: String;

TKdn1: TKdn0;

End;

Якщо нащадком є TObject, то в заголовку його можна опустити.

Клас-нащадок має доступ до всіх полів своїх предків, але не може їх перевизначити, т. до. він стане недоступний. Приклад:

type

TPredok = class {оголошення класу-предка}

Value: Integer;

end;

TPotomok = class(TPredok) {оголошення класу-нащадка}

Value: string; {перекриття успадкованого поля}

end;

var

My1: TPredok; {оголошення змінної класу}

My2: TPotomok; {оголошення змінної-класу}

begin

My1: = TPotomok.Create; {створює клас типу TPredok !}

My2: = TPotomok.Create; {створює клас типу TPotomok}

My1.Value: = ' Hello!'; {помилка, не той тип поля TPredok}

My2.Value: = ' Hello!'; {правильно, працює поле Value: String}

My2.Value: = 8; {помилка: поле Value: Integer перекрите}

end;

У цьому прикладі описано два класи: TPredok - предок і TPotomok - нащадок. Кожний з класів містить однойменні поля Value різних типів.

Далі в var-секції оголошені дві різні змінні My1 і My2 типи class. На перший погляд може показатися, що оператор-конструктор об'єкта My1:= TPotomok.Create створить об'єкт My1 (виділить під нього пам'ять) типу TPotomok. Однак це не так, оскільки My1 має інший тип. З цієї причини конструктор створить об'єкт батьківського типу, т. е. об'єкт типу TPredok. Тепер стає зрозуміле джерело помилок, які мають місце в декількох операторах приведеного прикладу.

18.4. Методи класу

Методом класу є инкаспулированная процедура або функція. Ці подрограмми появляються так само, як звичайні підпрограми. Метод повинен бути оголошений в описі класу у вигляді окремого заголовка, а код методу - описаний в секції implementation з вказівкою через символ "." приналежності методу до свого класу, наприклад:

type

TMyClass = class(TObject){оголошення класу}.

..

procedure DoSomething; {оголошення методу DoSomething}.

..

end;

Опис для DoSomething повинен бути приведений пізніше в секції implementation модуля:

procedure TMyClass.DoSomething;{вигляд заголовка клас. метод}

begin.

..

end;

При зверненні до методу можливе використання складового імені або оператора With, наприклад:

Var KdnClass: TKdnClass;

...

KdnClass.MyProc1; // два приклади звернення до методів

X:= KdnClass.MyFunc2; // за допомогою складових імен

...

With KdnClass do // ті ж звертання

Begin // за допомогою оператора With

MyProc1;

X:=MyFunc2;

End;

Однойменні методи можуть перекриватися в нащадках точно так, як це показане в прикладі перекриття полів. Таке перекриття називається статичним.

Для розширення можливостей частіше використовується динамічне перекриття. Для цього батьківський метод повинен мати директиву dinamic (динамічний метод) або virtual (віртуальний метод), а перекриваючий метод - директиву override. Приклад:

type

TFigure = class

procedure Draw; virtual; {віртуальний метод}

end;

TRectangle = class(TFigure)

procedure Draw; override; {перекриваючий метод}

end;

TEllipse = class(TFigure)

procedure Draw; override; {перекриваючий метод}

end;

У цьому прикладі оголошений віртуальний метод Draw батьківського класу TFigure і два однойменних методи в класах-нащадках TRectangle і TEllipse. Останні оголошені що перекривають (override).

Таке оголошення дозволяє перекривати методи з метою досягнення потрібних цілей:

var

Figure: TFigure;

begin

Figure: = TRectangle.Create; //створення класу

Figure.Draw; // виклик TRectangle.Draw

Figure.Destroy; // знищення класу

Figure: = TEllipse.Create; //створення класу

Figure.Draw; // виклик TEllipse.Draw

Figure.Destroy; // знищення класу

end;

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

У класі метод може бути оголошений абстрактним за допомогою директиви adstract. Такий метод є віртуальним або динамічним, однак, на відміну від інших методів, може не мати в секції implementation свого коду. Клас, що має абстрактні методи, називається абстрактним. Такі класи і методи можуть нічого не робити, инкаспулируя таким способом доступ до методів нащадків, наприклад:

procedure DoSomething; virtual; abstract;

Звернення до абстрактного методу, що неперекривається викликає помилку часу виконання (run time error), наприклад:

Type

TClass2 = class(TClass0).

..

procedure Paint; virtual; abstract;

end;

TClass1 = class(TClass0).

..

procedure Paint; override;

end;

var

jClass1: TClass1;

jClass2: TClass2;

begin

jClass1.Paint; // правильно

jClass2.Paint; // неправильно: звернення до абстрактного методу.

..

end;

Кожний клас має два особливих методи - конструктор і деструктор. Конструктор призначений для створення класу, т. е. для виділення під нього динамічної пам'яті. Деструктор, навпаки, призначений для знищення класу, т. е. для звільнення дільниці пам'яті, зайнятого цим класом. У класі TObject є стандартні методи Create (створити) і Destroy (знищити). У цьому класі оголошений також метод Free, який спочатку перевіряє коректність адреси і тільки потім викликає метод Destroy. У зв'язку з цим переважніше використати метод Free замість методу Destroy. Всякий клас за умовчанням містить змінну Self, в яку після виділення динамічної пам'яті вміщується адреса класу. Перш ніж виконати звернення до методів класу, його треба створити. Хоч конструктор і деструктор є процедурами, вони появляються спеціальними словами. Конструктор появляється словом Constructor, деструктор - словом Destructor. Часто для забезпечення доступу до полів предка в конструкторові необхідно заздалегідь створити клас-предок. Це можна зробити за допомогою слова Inherited.

Приклад:

type

TShape = class(TGraphicControl)

Private {внутрішні оголошення}

FPen: TPen;

FBrush: TBrush;

procedure PenChanged(Sender: TObject);

procedure BrushChanged(Sender: TObject);

public {зовнішні оголошення}

constructor Create(Owner: TComponent); override;

destructor Destroy; override;

...

end;

constructor TShape.Create(Owner: TComponent);

begin

inherited Create(Owner); // створення класу-предка TGraphicControl

Width: = 65; // зміна успадкованих властивостей TGraphicControl

Height: = 65;

FPen: = TPen.Create; // створення окремого поля TPen типу class

FPen.OnChange: = PenChanged;

FBrush: = TBrush.Create; // створення окремого поля TBrush типу class

FBrush.OnChange: = BrushChanged;

end;

Деякі прості класи можуть бути створені і знищені без оголошення конструкторів і деструкторов. Наприклад, якщо клас є нащадком TObject, то в ньому явно Constructor і Destructor в деяких випадках оголошувати немає потреби:

Type TClassy = class;..

var Classy: TClassy;

...

Classy:= TClassy.Create; {створення класу}.

..

Classy:= TClassy.Free; {знищення класу}

В мові є можливість оголошувати в межах одного класу декілька методів з одним і тим же ім'ям. При цьому всякий такий метод повинен бути таким, що перезавантажується (директива overload). Компілятор такі методи ідентифікує по своїх унікальних наборах формальних параметрів. Для того щоб відмінити реакцію компілятора Delphi на появу методу з тим же ім'ям, кожний такий метод треба помітити директивою reintroduce. Далі в секції implementation необхідно привести коди всіх таких методів.

Приклад:

Type TClassy = class;

Procedure HH(i, j: byte; var s: String); reintroduce; overload;

Procedure HH(q: String); reintroduce; overload;

Procedure HH(a: array oh Integer); reintroduce; overload;

...

implementation.

..

Procedure TClassy.HH(i, j: byte; var s: String);

Begin

S:=IntToStr(i + j);

End;

Procedure TClassy.HH(q: String);

Begin

L2.Cattion:= q;

End;

Procedure TClassy.HH(a: array oh Integer);

Begin

L1.Cattion:= IntToStr(a[6] + a[4]);

End;

...

Тепер, після звернення до методу на ім'я TClassy.HH, програма викличе саме той метод, формальні параметри якого відповідають фактичним параметрам в звертанні.

18.5. Властивості класу

Властивості, як і поля, є атрибутами класу. Властивості появляються за допомогою слів property, read і write. Слова read і write конкретизують призначення властивості. Синтаксис властивості такий:

property propertyName[indexes]: type index integerConstant specifiers;

де propertyName - ім'я властивості; [indexes] - параметри-імена в формі имя1, имя2,. .., имяN: type; index - ціла константа; read, write, stored, default (або nodefault) і implements - специфікації. Всяке оголошення властивості повинно мати одну з специфікацій read або write або обидві разом.

Приклади:

property Objects[Index: Integer]: TObject read GetObject write SetObject;

property Pixels[X, Y: Integer]: TColor read GetPixel write SetPixel;

property Values[const Name: string]: string read GetValue write SetValue;

property ErrorCount: Integer read GetErrorCount;

property NativeError: Longint read FNativeError;

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

Кожна властивість може мати специфікацію read або write або обидва разом в формі

read fieldOrMethod

write fieldOrMethod

де fieldOrMethod - ім'я поля або методу, оголошеного в класі, або властивість класу-предка.

Якщо fieldOrMethod оголошене в класі, то воно повинне бути визначене в тому ж класі. Якщо воно оголошене в класі-предку, то воно повинне бути видиме з нащадка, т. е. не повинно бути приватним полем або методом класу-предка. Якщо властивість є поле, то воно повинно мати тип. Якщо fieldOrMethod є read-специфікація, то воно повинне бути функцією без параметрів, тип якої співпадає з типом властивості. Якщо fieldOrMethod є write-специфікація і метод, то воно повинне бути процедурою, що повертає просте значення або константу того ж типу, що тип властивості. Наприклад, якщо властивість оголошена:

property Color: TColor read GetColor write SetColor;

тоді метод GetColor повинен бути описаний як

function GetColor: TColor;

і метод SetColor повинен бути описаний як

procedure SetColor(Value: TColor);

або

procedure SetColor(const Value: TColor);

Якщо властивість має специфікацію read, то воно має атрибут "read only" (тільки для читання). Якщо властивість має специфікацію write, то воно має атрибут "write only" (тільки для читання).

18.6. Структура класу

Всякий клас має структуру, яка складається з секцій. Кожна секція появляється спеціальним зарезервованим словом. До їх числа відносяться: published (декларированние), private (приватні), protected (захищені), public (доступні), automated (автоматизовані). Всередині кожної секції спочатку появляються поля, потім - властивості і методи.

Приклад:

type

TMyClass = class(TControl)

private.

.. { приватні оголошення тут}

protected.

.. { захищені оголошення тут }

public.

.. { доступні оголошення тут }

published.

.. { декларированние оголошення тут }

end;

Секції визначають області видимості компонент класу:

Private - компоненти класу доступні тільки всередині цього класу;

Public - компоненти класу доступні в поточному і будь-якому іншому модулі, який містить посилання в списку uses на модуль, в якому оголошений клас;

Published - те ж, що Public, однак в ній повинні бути перераховані властивості, які доступні не тільки на етапі виконання програми, але і на етапі її візуального конструювання коштами Delphi;

Protected - секція доступна тільки методам поточного класу і методам класів-предків;

Automated - секція використовується для оголошення властивостей і методів обробки OLE-контейнерів в рамках OLE-технології.

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

18.7. Операції над класами

Над класами дозволено виконувати дві операції - is і as.

1. Операція is. Синтаксис вираження, вмісного операцію is, має вигляд

object is class

Це вираження має логічний тип (boolean) і повертає True, якщо змінна object має тип class класу, інакше - False.

Приклад:

if ActiveControl is TEdit then TEdit(ActiveControl).SelectAll;

У цьому прикладі: якщо клас ActiveControl має тип TEdit, то буде виконаний метод TEdit(ActiveControl).SelectAll.

2. Операція as. Синтаксис вираження, вмісного операцію as:

object as class

Результатом обчислення цього вираження є посилання на об'єкт того ж типу, що і тип класу class. При виконанні програми object може мати той же тип, або тип класу-нащадка, або nil.

Приклади:

with Sender as TButton do // якщо Sender має тип TButton

begin // або тип-нащадок від TButton

Caption: = '&Ok';

OnClick: = OkClick;

end;

(Sender as TButton). Caption: = '&Ok'; //властивості Caption змінної

// Sender типу TButton або його нащадка привласнюється значення '&Ok'

Додаток

Перелік

налагоджених процедур і функцій,

написаних автором

Нижче використані глобальні типи і змінні:

Type

CompareType = (Less, Equal, Greater);

Var

Lon, Lon2: LongInt;

Serv: String[255];

Procedure Delay(MilliSec: LongInt);

{затримка часу на MilliSec миллисекунд}

Var k: LongInt;

begin

k:=GetTickCount; {в модулі Windows.pas}

While GetTickCount < (MilliSec+k) do;

end;

Function Ctrl_ Shift_Down(i: byte): boolean;

{Чи Натиснена одна з цих клавіш Ctrl - 1, Shift - 2}

var

ShiftState: TShiftState;

j: LongInt;

begin

Result:=false;

Case i of

1: j:= VK_CONTROL;

2: j:= VK_SHIFT;

end;

ShiftState: = KeyDataToShiftState(j);

Case i of

1: Result:= (ssCtrl in ShiftState);

2: Result:= (ssShift in ShiftState);

end;

end;

Function CtrlDown: boolean;

{чи натиснена клавіша Ctrl}

begin

Result:=Ctrl_ Shift_Down(1);

end;

Function ShiftDown: boolean;

{чи натиснена клавіша Shift}

begin

Result:=Ctrl_Shift_Down(2);

end;

Function Profit(Expend, Price: Real): Real;

{рентабельність=(ціна - витрати)/витрати*100}

begin

if (Expend < > 0) then Result:= (Price/Expend-1.0)*100.0

else Result:= 1.e5;

end;

Procedure Warn1(S: Variant);

{Вікно з Variant-значенням, наприклад Warn1('Процес закінчений')}

begin

MessageDlg(S, mtInformation, [mbOk], 0);

Screen.ActiveForm.Refresh;

End;

Procedure Warn4(s1, s2, s3, s4: String);

{те ж, що Warn1, але в 4 рядки}

var i, j: byte;

begin

i:=Length(s1); j:=i;

i:=Length(s2);

if (i > j) then j:=i;

i:=Length(s3);

if (i > j) then j:=i;

i:=Length(s4);

if (i > j) then j:=i;

Warn1(enter(s1, j)+''#13#10+''+Center(s2, j)

+''#13#10''+Center(s3, j)+''#13#10+''+Center(s4, j));

end;

Function DaNet(S: String): boolean;

{Вікно. Призначено для питання, на яке можна відповісти, клацнувши по одній з кнопок "Так" чи "Ні"}

begin

DaNet:=MessageDlg(S, mtConfirmation, [mbYes, mbNo], 0)=mrYes;

Screen.ActiveForm.Refresh;

end;

Function DaNet4(s1, s2, s3, s4: String): boolean;

{Вікно. Те ж, що DaNet, тільки в 4 рядки}

begin

DaNet4:=MessageDlg(rim(s1)+''#13#10+''+Trim(s2)+''#13#10''+Trim(s3)

+''#13#10+''+Trim(s4), mtConfirmation,[mbYes, mbNo], 0)=mrYes;

Screen.ActiveForm.Refresh;

end;

Function InOtrReal(i, a, b: real): boolean;

{Якщо i в орезке [a, b], то повертає True}

begin

Result:=(i > =a) and (i < =b);

end;

Function ExitK: boolean;

{стандартне питання про вихід}

begin

ExitK:=DaNet('Вихід? )(');

end;

Function Pos2(SubS, S: String; StartPos: byte): boolean;

{чи входить SubS в S починаючи з StartPos}

begin

Lon:=Pos(SubS, S);

Result:= (Lon > 0) and (StartPos = Lon);

end;

Function ChStr(Ch: Char; d: Word): String;

{створює рядок з символа Ch, повторюваного d разів}

begin

if d > 0 then

begin

SetLength(Result, d);

FillChar(Result[1], d, Ch);

end;

end;

Function Prop(d: Word): String;

{створює рядок з d пропусків}

begin

Result:=ChStr(' ', d);

end;

Function Pad(s: String; d: Word): String;

{вставляє праворуч від рядка пропуски, добираючи її до довжини d}

begin

Serv:=s;

Lon:=Length(s);

If (d > Lon) then Serv:=s+Prop(d-Lon);

Result:=Serv;

end;

Function PadCopy(s: String; n, d: Word): String;

{копіює з s починаючи з позиції n рядок довжини d. У разі меншого рядка добирає її до довжини d}

begin

Serv:=Copy(s, n, d);

if Length(Serv) < d then Serv:=Pad(Serv, d);

Result:=Serv;

end;

Function LeftPad(s: String; d: Word): String;

{вставляє зліва від рядка пропуски, добираючи її до довжини d}

begin

Serv:=s;

Lon:=Length(s);

if (d > Lon) then Serv:=Prop(d-Lon)+s;

Result:=Serv;

end;

Function Center(s: String; d: Word): String;

{вставляє зліва і праворуч від рядка порівну пропуски, добираючи її до довжини d}

begin

Serv:=s;

Lon:=Length(s);

Lon2:=Round(0.5*(d-Lon));

if (d > Lon) then Serv:=Prop(Lon2)+s+Prop(d-Lon2);

Result:=Serv;

end;

Function CompStrings(s1, s2: String): CompareType;

{порівняння рядків: s1 < s2 - Less, s1=s2 - Equal, s1 > s2 - Greater}

begin

if (s1 < s2) then CompStrings:=Less

else

if (s1 > s2) then CompStrings:=Greater

else

CompStrings:=Equal;

end;

Function CompReal(r1, r2: Real): CompareType;

{порівняння дійсних чисел}

begin

if (r1 < r2) then Result:=Less

else

if (r1 > r2) then Result:=Greater

else

Result:=Equal;

end;

Procedure IncRe(Var r: Real; h: real);

begin

r:=r+h;

end;

Function LongToStr(L: LongInt; d: byte): String;

{конвертує ціле в рядок довжини d}

begin

Str(L, Serv);

Result:=LPad(Serv, d);

end;

Function Long2Str(L: LongInt): String;

{конвертує ціле в рядок}

begin

Str(L, Serv);

Result:=Serv;

end;

Function StrLong(st: String): LongInt;

{конвертує рядок в ціле }

begin

Val(Trim(st), Lon, Code);

Result:=Lon; end;

Function Str2Long(st: String; Var L: LongInt): boolean;

{конвертує рядок в ціле. Повертає True у разі успіху}

begin

Val(Trim(st), L, Code);

Result:=(Code=0);

end;

Function RealToStr(R: Real; Posle: byte): String;

{Конвертує Real в рядок, Posle - кількість символів в дробовій частині R}

begin

Str(R:20:Posle, Serv);

RealToStr:=Trim(Serv);

end;

Function Slash(Dir: String): String;

{ставить в кінець шляху символ ' \'}

begin

Serv:=Trim(Dir);

if (Serv[Length(Serv)] < > '\') then Result:)(=Serv+'\'

else Result:)(=Serv;)(

end;)(

Function ChWinDos(Ch:)( Char): Char;

{перетворює російський Windows-символ в російський DOS-символ}

Var i, j: byte;

begin

i:=Ord(Ch);

Case i of

168: {Е} j:=240;

184: {е} j:=241;

192..255: if (i > 239) then j:=i-16 else j:=i-64

else j:=i;

end;

Result:=Char(j);

end;

Function ChDosWin(Ch: Char): Char;

{перетворює російський DOS-символ в російський Windows-символ}

Var i, j: byte;

begin

i:=Ord(Ch);

Case i of

240: {Е} j:=168;

241: {е} j:=184;

128..175: j:=i+64;

224..239: j:=i+16

else j:=i;

end;

Result:=Char(j);

end;

Function StrWinDos(st: String): String;

{перетворює російський Windows-рядок в російський DOS-рядок}

Var

n, i: byte;

s: ^String;

begin

New(s);

n:=Length(st);

s^:= '';

if (n > 0) then

for i:=1 to n do

s^:= s^+ChWinDos(st[i]);

Result:=s^;

Dispose(s);

end;

Function StrDosWin(s: String): String;

{перетворює російський DOS-рядок в російський Windows-рядок}

Var

n, i: byte;

s: ^String;

begin

New(s);

n:=Length(st);

s^:= '';

if (n > 0) then

for i:=1 to n do

s^:= s^+ChDosWin(st[i]);

Result:=s^;

end;

Function InputStr(const Prompt: String; Var s: String; IsParol: byte): boolean;

{введення рядка. Prompt - пояснення, s - рядок, що вводиться,

isParol=1, якщо засекречене введення, інакше видиме}

begin

Result:=

KdnInputQuery('Введення строки', Prompt, s, clBlack, (IsParol=1));

end;

Function ParolControl(RealParol: String): boolean;

{повертає True, якщо введений рядок співпадає з RealParol}

var

b, h: boolean;

i: byte;

begin

St:='';

i:=0;

b:=false;

Repeat

Inc(i);

h:=InputStr(' Введіть пароль. ..', St, 1);

if h then b:= (St=RealParol);

if not b and h then Warn1('Помилка');

Until b or (i=3) or (not h);

Result:=b;

end;

Function ExistSubDir(SubDir:String; Dir: tPathStr):boolean;

{встановлює наявність субдиректорії SubDir всередині директорія Dir. Наприклад, в D:\DIR0001 субдиректорії BAR }

begin

Result:=DirectoryExists(Slash(SubDir)+Dir);

end;

Function GetFileSize(const FileName: string): LongInt;

{розмір файла}

var Sr: TSearchRec;

begin

if FindFirst(ExpandFileName(FileName), faAnyFile, Sr) = 0 then

Result: = Sr.Size

else Result: = - 1;

end;

Function FileDateTime(const FileName: string): System.TDateTime;

{час створення файла FileName, наприклад:

s:= DateTimeToStr(FileDateTime('c:\KdnBread\Bread.exe'))}

begin

Result: = FileDateToDateTime(FileAge(FileName));

end;

Function HasAttr(const FileName: string; Attr: Word): Boolean;

{чи має файл FileName атрибут Attr}

begin

Result: = (FileGetAttr(FileName) and Attr) = Attr;

end;

Procedure AppendText(Var f: Text; nF: String);

{відкриває текстовой файл для додавання рядків}

begin

Assign(f, nF);

if KdnFS(nF, 1) > 0 then Append(f) else Rewrite(f);

end;

Procedure AppendToText(nF, s: String);

{додає рядок в кінець текстового файла}

Var f: TextFile;

begin

AppendText(f, nF);

Writeln(f, s);

CloseFile(f);

end;

Procedure KdnExec(Command: String);

{запуск іншого додатку, наприклад ' c:\KdnBreadDir\KdnBread.exe'}

begin

Serv:=Command+#0;

If WinExec(@Serv[1], SW_SHOWNORMAL) <32

then Warn2('Помилкове завершення WinExec');

end;