Object Pascal

[ виправити ] текст може містити помилки, будь ласка перевіряйте перш ніж використовувати.

скачати

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

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

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

символи _ + -

26 великих і 26 малих латинських букв A, B, ... Y, Z, a, b, ..., y, 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.

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

a: = a + 1,

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

Disk_C_DirctoryCounter: = Disk_C_DirctoryCounter +1.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Приклади:

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

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

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

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

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

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

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

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

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

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

цілі [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, A_Par: Integer;

T1, T2, T3: LongInt;

CircleCounter: byte;

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

Максимально допустимий діапазон значень визначається їх типом.

Приклади:

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 x 10 ^ -39 ... 1.7 x 10 ^ 38

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

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

3.6 x 10 ^ -4951 ... 1.1 x 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;

T: Integer;

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

у формі з фіксованою десятковою крапкою;

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

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

12.455

-988.45

-8.0

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

E

Приклади:

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

5.245E-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-рядки не оголошена, то при дії директиви компілятора {$ H +} або без її вказівки таке оголошення рівносильно AnsiStrig. Якщо встановлена ​​директива {$ H-}, то тип 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

A, 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.1415926536E +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. Такий спосіб дозволяє:

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

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

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

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

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

У цьому зв'язку важливо підкреслити, що навіть при збігу базових типів відмінність в призначених для користувача типах може призвести до непередбачуваного поведінки програми. Наприклад, в нижченаведеної секції 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, що представляє собою упорядковану сукупність елементів одного типу.

Слід розрізняти два види масивів: масив-тип і масив-змінну.

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

= 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].

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

: Array [,, ...,]

Of;

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

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

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

Type

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

Var

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

Z: tA1; {масив}

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

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

Таблиця 5

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

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

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

Var Y, Z: tA1;

Var y, 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 і два одномірних масиву A і V як цілі змінні типу Integer. Потім у блоці begin ... end розташовані три обчислювальних оператора.

Var

i: Integer;

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

...

begin

i: = 5;

V [8]: = i +9;

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

end;

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

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

V: = A;

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

V: = A * V;

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

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

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

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

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

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

= Record

:;

:;

...

:;

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

:;

:;

...

:;

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, c: Integer;

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

z: tMass;

r: tRec;

End;

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

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

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

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

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

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

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

Fa Gri.a Fk [6] Gri.z [2, 34] FrName FrMass2 [1, 50]

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

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

J: = 123;

Fa: = J + 9;

Gri.a: = (Fa + J) * (Fc + Fb - Gri.c);

Gri.a: = (Fa + J) * (Fc + Fb - Gri.c);

Fk [1]: = Fz [2,30];

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

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

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

Приклад:

With Gri do

Begin

a: = 12 * (a + b + c + Fa);

b: = 64 * (b - c);

End;

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

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

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', 'c']; {оператор визначення безлічі}

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

Таблиця 6

Опера-ція

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

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

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

Приклад

+

-

*

=

=

in

Об'єднання

Віднімання

Перетин

Не менше

Не більше

Рівність

Нерівність

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

set

set

set

set

set

set

set

елемент set

set

set

set

boolean

boolean

boolean

boolean

boolean

Set1 + Set2

S - T

S * T

Q = S2

S2 = MySet

MySet S1

A 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;

B: boolean;

...

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

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

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

B: = S1 = S2; {False, т. к. S2 не є підмножиною S2}

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

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

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

Var

S1: set of Integer;

B: boolean;

...

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

B: = (4 in S1); {True, т. к. 4 є елементом множини S1}

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

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

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

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

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

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

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

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

Var Fi: TextFile;

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

Var F: File;

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

Type

TRec = Record

A: Real;

B: Integer;

C: 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

P * 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

A

B

not A

A and B

A or B

A xor B

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

Ставлення

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

>

<

> =

8

(5 <3) and (z = 0)

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

not ((x <y) and (z> y))

('Ab' = 'ac') and (x = z)

(4 in [2 .. 23])

True

False

True

True

False

True

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

Вираз:

Not ((x> 6 + 8 * 2) and (y <7) or (z> 7)) and (xy)

Порядок:

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 було дано коротке визначення цього оператора - одного найпростіших і найбільш часто використовуваних операторів. Нагадаємо, що його синтаксис має вигляд

x: = y;

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

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

Var

Ch: Char;

S: String [5];

Q: String [18];

L, J: Integer;

P: Byte;

R: Real;

B: Boolean;

Rec: Record

A: Word;

B: String [20];

End;

...

Таблиця 13

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

Значення

Q: = 'd: Dir1Worda.txt';

S: = Q;

Q: = S + 'r';

Ch: = Q [2];

L: = 450;

P: = L;

J: = 100;

R: =-L / J;

J: =- L / J; J: =- L - 200;

B: = J> L;

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

Rec.A: = J-20;

Rec.B: = 20;

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

'D: Dir1Worda.txt'

'D: Di'

'D: Dir'

':'

450

Помилка, т. к. max P = 255

100

-4.5

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

250

False

True

230

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

'Dd'

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, якщо PosLength (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: = 'Іванов Сергій Петрович';

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

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

Function SizeOf (Obj): Integer;

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

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

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

Таблиця 14

Формат

Опис

0

#

.

,

E +, E-

;

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

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

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

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

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

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

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

Таблиця 15

Формат

Число 1

Число 2

Число 3

Число 4

0

0.00

#. # #

#, # # 0.00

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

#, # # 0.00;; Zero

0.000E +00

#.### E-0

1234

1234

1234.00

1234

1,234.00

1,234.00

1,234.00

.234 E +03

1.234E3

-1234

-1234

-1234.00

-1234

-1,234.00

(1,234.00)

-1,234.00

-1.234E +03

-1.234E3

0.5

1

0.50

.5

0.50

0.50

0.50

5.000E-01

5E-1

0

0

0.00

0.00

0.00

Zero

0.000E +00

0E0

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

Function Char (X: byte): Char;

Повертає символ з номером X.

Ch: = 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}

Functio n 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 / X) у відповід-но до квадрантами координатної площини 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;

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

Function Ceil (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 (T: 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 р. і мілісекунд від півночі поточного дня}

Function TimeStampToDateTime (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 жовтня 1926 '}

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

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

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

ss: = IntToStr (H) + '' + 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:30 am '));

Види форматів дані в табл. 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;

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

Procedur e Move (Var Source, Dest; Count: Integer);

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

Function ParamCount: Word;

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

Procedure Break;

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

. Procedure Continue;

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

Таблиця 16

Формат

Опис

C

D

Dd

Ddd

Dddd

Ddddd

Dddddd

M

Mm

Mmm

Mmmm

Yy

Yyyy

h

hh

n

nn

s

ss

t

tt

am / pm

ampm

a / p

/

:

Показує спочатку дату у форматі дд.мм.гг, потім час у форматі чч.мм.сс. Не показує час, якщо дробова частина 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 (x <10.7) then a [4]: ​​= 5 else a [4]: ​​= 6;

if (x <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: x: = 0;

1,3: x: = 1;

10 .. 15: x: = 2

else x: = 3;

End;

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

Приклад.

x: = 0;

i: = 0;

While (x <101.667) do

Begin

Inc (i);

X: = X + 5.617;

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

End;

У цьому прикладі цикл буде виконуватись до тих пір, поки не виконається умова x <101.667. У тілі циклу змінна X з кожним кроком циклу збільшує своє значення на 5.617 так, що на певному етапі умова x <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 за допомогою математичної формули

Object Pascal

Зовнішній цикл з лічильником 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;

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

With Student 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 (p, 8000); {виділення пам'яті}

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

n: = i + 9;

Finally

FreeMem (p, 8000); {звільнення пам'яті}

End;

14. Покажчики

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

Тип Pointer утворює покажчик без типу. Покажчик на тип має синтаксис:

^ Ім'я типу

Приклади оголошення покажчиків:

Type

tDinArr = Array [1 .. 1000, 100] of String [255]; {звичайний тип}

tDinArrPtr = ^ tDinArr; {покажчик на тип tDinArr}

tRecPtr = ^ tRec; {покажчик на тип запису, який описаний нижче}

tTRec = Record {звичайний тип-запис}

A: Integer;

B: Real;

C: 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: P: Pointer; Size: Word);

Виділяє блок пам'яті розміру Size і привласнює адресу початку блоку вказівником P.

Procedure FreeMem (Var: P: Pointer; Size: Word);

Звільняє блок пам'яті розміру Size, адресований покажчиком P.

Нижче наведено докладний приклад, який демонструє економний процес копіювання текстового файлу 't1.txt' в файл 't2.txt' з використанням покажчика Buffer.

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: P: Pointer);

Створює нову динамічну змінну того типу, на який посилається вказівник. Еквівалентна оператору GetMem (P, SizeOf (P ^));

Procedure Dispose (Var: P: Pointer);

Знищує динамічну змінну, на яку вказує P. Еквівалентна оператору FreeMem (P, SizeOf (P ^));

Procedure ReallocMem (var P: Pointer; Size: Integer);

Процедура працює наступним чином:

якщо P = Nil і Size = 0, то оператор не виконає ніяких дій;

якщо P = Nil і Size> 0, то оператор спрацює аналогічно GetMem;

якщо P 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 (P: Pointer): Integer;

ReallocMem: function (P: 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;

Процедура c ім'ям 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 C);

описує С як константу без типу.

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

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

Наступний приклад використовує параметри без типу у функції 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;

P: TPoint;

...

i: = Compare (Vec1, Vec2); {0, розміри однакові}

Vec [1]: = Compare (i, Vec1); {-1, розмір i менше розміру Vec1}

PX: = Compare (Vec1, P); {1, розмір Vec1 більше розміру P}

PY: = Compare (i, P); {-1, розмір i менше розміру P}

Vec2 [8]: = Compare (i, PX); {0, розміри i і поля PX однакові}

...

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);

викликає цю функцію (запускає її алгоритм) і після обробки повертає результат обчислень змінної I.

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. Якщо два параметри мають однакове ім'я і один з них описаний усередині підпрограми, а інший - за її межами, то діє той параметр, який описаний в підпрограмі. Аналогічно визначається область доступності параметрів описаних в різних модулях. Таким чином, при описі імен діє такий принцип: більш пізній оголошення скасовує облаcтей дії раніше описаних імен. Всередині однієї підпрограми не можна оголошувати двох і більше однакових імен.

Пояснимо область дії імен на прикладі наступного модуля

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 (x: Integer): Integer;

Begin

d: = d - x;

Deccy: = Sqr (x);

End;

...

d: = 3; a: = Deccy (3) * Deccy (d); {a = 0, d = 0}

d: = 3; a: = Deccy (d) * Deccy (3); {a = 81, d = -3}

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

15.8. Рекурсивні процедури та функції

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

В якості ілюстрації наведемо приклад простий і надзвичайно ефективної процедури сортування (розстановки елементів в порядку неспадання) фрагмента цілочисельного одновимірного масиву A:

procedure QuickSortPart (var A: array of Integer; iLo, iHi: Integer);

var

Lo, Hi, Mid, T: Integer;

begin

Lo: = iLo;

Hi: = iHi;

Mid: = A [(Lo + Hi) div 2]; {середній елемент фрагмента}

repeat {поділ фрагменту на ліву і праву частини}

while A [Lo] <Mid do Inc (Lo);

while A [Hi]> Mid do Dec (Hi);

if Lo Hi;

if Hi> iLo then QuickSortPart (A, iLo, Hi); {сортування лівій частині}

if Lo <iHi then QuickSortPart (A, Lo, iHi); {сортування правій частині}

end;

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

Нижче наведена звичайна (нерекурсивний) процедура QuickSort сортування всіх елементів масиву, яка виконується зверненням до рекурсивної процедури QuickSortPart, де фрагмент - весь масив A.

procedure QuickSort (var A: array of Integer);

begin

QuickSortPart (A, Low (A), High (A));

end;

15.9. Параметри і конструктори відкритих масивів

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

array of type (переважно array [X .. Y] of type)

Наприклад, оператори

procedure NullChar (A: array of Char);

begin

for i: = Low (A) to High (A) do A [i]: = '0 ';

end;

оголошують процедуру NullChar, яка містить один параметр - відкритий символьний масив А будь-якого розміру. У тілі процедури використовується оператор циклу, який заповнює кожен елемент масиву символом "0". Для визначення нижньої межі індексу використана стандартна функція Low, для верхньої - High.

Якщо до такої процедури звернутися оператором NullChar (z), де тип змінної z = array [5 .. 55] of Char, то весь масив z буде заповнений символами "нуль".

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

Приклад:

var I, J: Integer;

procedure Add (A: array of Integer);

У цьому випадку можна звернутися до процедури Add, наприклад, так:

Add ([5, 7, I, I + J]);

16. Структура програми

У середовищі Delphi програма як єдине ціле представляється у вигляді проекту. У новій версії мови Object Pascal для представлення проекту використовується п'ять основних типів файлів:

dpr-файл головний програми;

текстові pas-файли;

відкомпілювалися dcu-файли;

res-файли ресурсів;

dfm-файли ресурсів екранних форм;

готові до використання програмні exe-файли.

Вихідна програма, написана в середовищі Delphi на мові Object Pascal завжди складається з декількох модулів, кожен з яких розміщується в окремому текстовому файлі. Один модуль є головною програмою. Він починається словом Program і розміщується у файлі з розширенням. Dpr. Всі інші модулі є підлеглими і починаються словом Unit. Такі модулі розміщуються у файлах з розширенням. Pas. Всі модулі закінчуються оператором End, після якого ставиться символ "крапка".

Кожен модуль може використовувати інші модулі, до числа яких можуть відноситися текстові файли, res-і dfm-файли ресурсів або відкомпілювалися файли Unit-модулів. Сcилка на необхідні до використання модулі міститься в секціях Uses. Текстові або скомпільовані файли зазвичай містять необхідні для використовує їх модуля величини - константи, типи, змінні, процедури і функції. Файли ресурсів необхідні для підключення констант, що описують використовувані зовнішні ресурси.

Перераховані вище модулі, розміщені в *. pas-, *. dcu-, *. res-, *. dfm-файлах, відіграють допоміжну роль: вони призначені для компіляції і подальшого складання в повноцінний програмний модуль - exe-файл, готовий до виконання на комп'ютері.

Нижче наведено приклад вихідних текстів головний програми KdnBread і одного підлеглого (використовуваного) нею модуля Main.

Program KdnBread; {початок тексту головний програми}

{Текст міститься у файлі 'c: BorlandProjectsKdnBread.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: BorlandProjectsMain.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;

functio n OneSymbString (c: 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 (c: Char; d: byte): String; {заголовок функції}

begin

Result: = CharStr (c, 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: ProjectsBreadProFirst.dat');

Reset (f, SizeOf (Rec1));

New (AppMem);

Finalization {завершення}

Dispose (AppMem);

CloseFile (f);

End. {Останній оператор модуля}

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

17. Файли

Файлом називається область даних на зовнішньому носієві - жорсткому диску, дискеті та ін Кожен файл має ім'я, яке представляє собою рядок символів. Розрізняють звичайне ім'я (або просто ім'я) і повне ім'я. Під повним ім'ям розуміється абсолютний адресу файлу, що складається з шляху і імені файлу. Наприклад, рядок 'C: Program FilesFolder1Students.dat' є повним ім'ям. Воно складається з шляху 'C: Program FilesFolder1' до файлу і власне імені файлу 'Students.dat'. Це означає, що файл 'Students.dat' розташований на диску C в папці (директорії) 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);

Виводить вміст внутрішнього буфера у файл.

Function Eof (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);

Var f: Text;

Begin

AssignFile (f, nF);

If not FileExists (nF) then Rewrite (f) {не існує, створити і відкрити}

Else {інакше}

Begin

Reset (f); {існує, відкрити}

While not Eof (f) do Readln (f); {пересунути вказівник в кінець файлу}

End;

Writeln (f, St); {записати рядок}

CloseFile (f); {закрити файл}

End;

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

Var

S1: String [58];

S2: String [189];

...

AddStrToTextFile ('c: Filesring.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.

Functio n 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: BasesSdudBase' знаходиться файл '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 - диск B і т.д.). Приклад: 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.

Function FindFirst (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 Filesdelphi4bin *.*', faAnyFile, SR);

if (SR.Attr = faArchive) then

S: = 'Файл' + SR.Name + 'має розмір' + IntToStr (SR.Size) + 'байт';

У даному прикладі процедура FindFirst шукає перший файл за маскою'*.*' (всі файли) у папці 'c: Program Filesdelphi4bin'. Атрибут 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;

Створює нову папку.

Function GetCurrentDir: 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: APPSSALESLOCAL') then; Function FileExists (FileName: string): boolean;

Перевіряє наявність файлу. Приклади:

B: = FileExists ('C: APPSSALESLOCALFort.pas'); {повне ім'я}

B: = FileExists ('Fort.pas'); {зазначено усічене ім'я файлу, перевірка його існування лише в поточній директорії}

Procedure ForceDirectories (Dir: string);

Створює нову директорію.

Procedure ForceDirectories (C: APPSSALESLOCAL).

П р и м і т а н і е. До моменту звернення до процедури директорії 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. Синтаксис класу

Синтаксис всякого класу має вигляд

type className = 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. Часто для забезпечення доступу до полів предка в конструкторі необхідно попередньо створити клас-предок. Це можна зробити c допомогою слова 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 GetTickCountj) then j: = i;

i: = Length (s3);

if (i> j) then j: = i;

i: = Length (s4);

if (i> j) then j: = i;

Warn1 (Center (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 (Trim (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 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;

Functio n CompStrings (s1, s2: String): CompareType;

{Порівняння рядків: s1s2 - Greater}

begin

if (s1s2) then CompStrings: = Greater

else

CompStrings: = Equal;

end;

Function CompReal (r1, r2: Real): CompareType;

{Порівняння дійсних чисел}

begin

if (r1r2) 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;

Functio n 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: KdnBreadBread.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: KdnBreadDirKdnBread.exe'}

begin

Serv: = Command + # 0;

If WinExec (@ Serv [1], SW_SHOWNORMAL

Додати в блог або на сайт

Цей текст може містити помилки.

Програмування, комп'ютери, інформатика і кібернетика | Реферат
285.6кб. | скачати


Схожі роботи:
Типи даних в Object Pascal
Об`єктно-орієнтоване середовище програмування Object Pascal в профільному курсі інформатики
Розробка програми на мові Borland Object Pascal Ide Borland Delphi
Основні відомості про алгоритмічну мову Turbo Pascal Графіка Pascal
Pascal 9
Програмування Pascal
Turbo Pascal
Паскаль Pascal Блез
Оператори Turbo Pascal 7
© Усі права захищені
написати до нас