Будь умным!


У вас вопросы?
У нас ответы:) SamZan.net

ОСНОВИ ПРОГРАМУВАННЯ ТА АЛГОРИТМІЧНА МОВА PASCAL

Работа добавлена на сайт samzan.net:


   МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ

НАЦІОНАЛЬНИЙ  ТЕХНІЧНИЙ  УНІВЕРСИТЕТ  УКРАЇНИ

"КИЇВСЬКИЙ  ПОЛІТЕХНІЧНИЙ  ІНСТИТУТ"

«ОСНОВИ ПРОГРАМУВАННЯ ТА

АЛГОРИТМІЧНА МОВА PASCAL|язики|»

Навчальний посібник

Київ   НТУУ “КПІ”

2010

ОСНОВИ ПРОГРАМУВАННЯ ТА АЛГОРИТМІЧНА МОВА PASCAL.   Навчальний посібник |

 /Укл.: доц. Ю.Д. Щербашин, ст.викл. Д.С. Смаковський.

|.: НТУУ “КПІ”, 2010 , -|  с|із|. 197

Навчальне видання|

Укладачі:     Щербашин Юрій Дмитрович                   

                    Смаковський  Денис Сергійович

Відповідальній редактор            д.т.н    С.О.Лук’яненнко

                 

Рецензенти:    доц.   В.М. Медведєва

                       доц.    В.Я.Сидоренко

                       доц.    Є.В.Щербаков


ЗМІСТ  

[1] ВСТУП

[2]
ЧАСТИНА 1. ОСНОВИ ПРОГРАМУВАННЯ

[2.1] Розділ 1. Архітектура сучасних ПК

[2.1.1] 1.1. Структурна схема ПК .

[2.1.2] 1.2. Загальні|загальні| принципи роботи комп'ютера

[2.1.3] 1.3. Позиційні системи числення

[2.2] Завдання для самостійної роботи

[2.3]
Розділ 2. Історія розвитку мов|язиків| програмування високого рівня

[2.4] Розділ 3. Загальні|загальні| принципи програмування

[2.4.1] 3.1. Вимоги до професії

[2.4.2] 3.2. Мови|язики| програмування і програмне|програмова| середовище|середовище|

[2.4.3] 3.3. Структура програмних комплексів

[2.4.4]
3.4. Структура програми

[2.4.5] 3.5. Технологія програмування і налагодження програм на МВР

[2.4.6] 3.6. Техніка обчислень|підрахунків|

[2.4.7] 3.7. Типи обчислювальних процесів

[2.4.8] 3.8. Цикли в обчислювальному процесі

[2.4.9] 3.9. Загальна структура прикладної програми

[2.5] Завдання для самостійної роботи

[3]
ЧАСТИНА|частина| 2.  МОВА|язик| ПРОГРАМУВАННЯ PASCAL (ПАСКАЛЬ)

[3.1] Розділ 4.  Знайомство з|із| мовою|язиком| Паскаль|язик| |

[3.1.1] 4.1. Середовище програмування Borland Turbo Pascal v.7.0 (DOS)

[3.1.2] 4.2. Перша програма. Поняття про типи даних і оператор циклу for

[3.2] Завдання для самостійної роботи

[3.3]
Розділ 5. Прості типи даних в |язиці| PASCAL і дії над ними

[3.3.1] 5.1. Типи даних

[3.3.2] 5.2. Цілі числа

[3.3.3] 5.3. Числа з плаваючою комою (дійсний тип)

[3.3.4] 5.4. Логічний тип

[3.3.5] 5.5. Символьний тип

[3.3.6] 5.6. Символьний рядок (тип STRING[N])  

[3.3.7] 5.7. Тип-діапазон

[3.3.8] 5.8. Рідко використовувані типи

[3.3.9] 5.9. Константи

[3.3.10]      5.10. Комплексний приклад на дії з простими типами

[3.4] Завдання для самостійної роботи

[3.5]
Розділ 6. Структуровані типи

[3.5.1] 6.1. Масиви

[3.5.2] 6.2. Записи  

[3.5.3] 6.3. Рідко використовувані типи

[3.5.4] 6.4. Іменування констант, константи, що типізуються

[3.6] Завдання для самостійної роботи

[3.7]
Розділ 7. Операції і оператори

[3.7.1] 7.1. Оператор привласнення|присвоєння|. Сумісність типів

[3.7.2] 7.2. Арифметичні операції

[3.7.3] 7.3. Логічні операції

[3.7.4] 7.4. Операції відношення|ставлення| (порівняння)

[3.7.5] 7.5. Пріоритет операцій

[3.7.6] 7.6. Оператори циклу

[3.7.7] 7.7. Оператори альтернативного вибору

[3.7.8] 7.8. Оператори передачі управління

[3.8] Завдання для самостійної роботи

[3.9]
Розділ 8. Процедури і функції

[3.9.1] 8.1. Створення|створіння| і виклик підпрограм (процедур і функцій)

[3.9.2] 8.2. Формальні і фактичні параметри

[3.9.3] 8.3. Способи передачі в підпрограму фактичних параметрів

[3.9.4] 8.5. Параметри-функції і параметри-процедури

[3.10] Завдання для самостійної роботи

[3.11] Розділ 9.  Як створюються програмні|програмові| комплекси

[3.11.1] 9.1. Етапи створення великих програмних|програмових| комплексів

[3.11.2] 9.2. Технічні вимоги на розробку програмного комплексу

[3.11.3] 9.4. Модульна архітектура складних програмних|програмових| комплексів

[3.12] Завдання для самостійної роботи

[3.13]
Розділ 10. Динамічне виділення пам'яті, покажчики

[3.13.1] 10.1. Організація простору оперативної пам'яті в ПК

[3.13.2] 10.2. Динамічне виділення пам'яті. Типи покажчиків

[3.13.3] 10.3. Використання покажчиків при роботі з|із| процедурами і функціями

[3.14] Завдання для самостійної роботи

[3.15]
Розділ 11.  Робота з файлами|виведення|

[3.15.1] 11.1. Типи файлів

[3.15.2] 11.2. Доступ до файлів

[3.15.3] 11.3. Логічні пристрої|устрої|

[3.15.4] 11.4. Відкриття |відчиняти| файлу

[3.15.5] 11.5. Процедури вводу/виводу|виведення|

[3.15.6] 11.6. Навігація вводу/виводу|виведення|

[3.15.7] 11.7. Закриття файлу

[3.15.8] 11.8. Процедури і функції для роботи з|із| файлами

[3.15.9] 11.9. Комплексний приклад|зразок| роботи з|із| файлами

[3.16] Завдання для самостійної роботи

[3.17]
Розділ 12. Елементарні функції графіки

[3.17.1] 12.1. Формування зображень на екрані дисплея

[3.17.2] 12.2. Ініціалізація графічного режиму

[3.17.3] 12.3. Координати, сторінки, вікна

[3.17.4] 12.4. Малювання простих фігур

[3.17.5] 12.5. Управління кольором|цвітом|

[3.17.6]     12.7. Анімація

[3.18] Завдання для самостійної роботи

[4]
РЕКОМЕНДОВАНА  ЛІТЕРАТУРА

[5]
Додаток А

[6]
ПРЕДМЕТНИЙ ВКАЗІВНИК |середовища|


“Те, що ми вивчаємо
|проходимо| сьогодні,

повинно ставати фундаментом для того,

що ти  дізнаєшся|взнаєш| завтра. Не можна починати|починати|

будівництво будинку|дому| з горища”

В.Пєлєвін, АМПІРВ

ВСТУП

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

До сучасних основоположних універсальних  мов|язики| високого рівня (МВР), можна віднести|розглядають| ПАСКАЛЬ (PASCAL) і  Сі (C,С++). Ці мови використовуються в  програмних|програмової| середовищах |середовища| Delphi|, Visual| C++|, Borland| C++| Builder|, Microsoft| C#|.

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

На жаль, сучасне програмне|програмова| середовище|середовище| вимагає, окрім знання відповідного МВР, досить великих|величезних| знань технології роботи в цьому програмному|програмовій| середовищу|середовищі|. Достатньо поглянути на тисячосторінкові  довідники  з  програмування, щоб|аби|  зрозуміти  всю  складність  їх  освоєння  ‘з нуля’. Виникає порочний|хибний| круг|коло| - незнання мови|язика| не дозволяє орієнтуватися в технології, незнання технології не дозволяє розуміти додаткові поняття, що вводяться|запроваджують| до МВР для забезпечення функціонування програмного|програмової| середовища|середовища|. Виходом з|із| цього положення|становища| може бути вивчення, насамперед|передусім|,  базових понять мови|язика|  з|із| поступовою, поетапною прив'язкою до сучасних технологій програмування.

Навчальний посібник складається з двох частин.|частин| В першій частині розглядаються загальні принципи роботи персонального комп'ютера  і програмування на ньому. В другій частині  вивчається програмування на найбільш простій універсальній алгоритмічній мові - ПАСКАЛЬ (PASCAL).

Загальний обєм посібника включає 12 розділів, список рекомендованої літератури, Додаток А та Предметний вказівник. Розділи 1-5,9,11 написані Ю.Д.Щербашиним, розділи 7,8,10,12 –Д.С.Смаковським. В кінці кожного розділу наведений перелік контрольних питань та завдання для самостійної роботи. Викладачі можуть використовувати контрольні питання, як питання екзаменаційних білетів, а завдання для самостійної роботи – як завдання по  лабораторному практикуму з дисципліни.

Перші – ознайомчі, розділи мають спільне для всіх студентів завдання. Для кожного подальшого розділу в Додатку А наведена достатня кількість завдань для забезпечення самостійної роботи кожного студента групи по суто індивідуальному завданню. Індивідуальні завдання вказані у Додатку А у вигляді зсилок на розділи підручника МГУ [16]:  В.Н.Пильщиков. Сборник упражнений по языку Паскаль. –М: «Наука», 1989. 

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

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

МВР- мова високого рівня

БСПП - бібліотека стандартних підпрограм

ООП- об'єктно-орієнтоване програмування

ОС- операційна система

ПК- персональний компютер 

ПОП- пристрій оперативної пам’яті

ППП- пристрій постійної пам'яті

ПОПі - програма обробки переривань

НЖМД (НГМД) – накопичувач на жорсткомунучкому) магнітному диску 

COM1, COM2 – біт-послідовні порти телекомунікаційного вводуиводу

LPT – байт-послідовний порт  подключення  принтера (плотера)

MMI| (man-machine| interface, англ.|) - людино-машинний інтерфейс

USB- біт- послідовний порт подключення накопичувача на flash- пам‘яті 

ETHERNET локальна обчислювальна мережа.

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

Автори вдячні зав. кафедри автоматизації проектування енергетичних процесів  та систем КПІ професору Лук’яненко С.О. та доценту тієї ж кафедри Медведєвій В.М. за цінні методичні  зауваження щодо  змісту навчального посібника.


ЧАСТИНА 1. ОСНОВИ ПРОГРАМУВАННЯ

Розділ 1. Архітектура сучасних ПК

1.1. Структурна схема ПК .

 Обчислювальна техніка і інформаційні технології переживають період бурхливого розвитку. Потужність сучасного переносного персонального комп'ютера (ПК)   на декілька порядків перевищує потужності суперкомп'ютерів 60-80-х. Проте принципи побудови, так звана архітектура комп'ютера, змінилися незначно.

Комп'ютер – це  цифровий автомат, що керується програмою. Він здатен виконувати:

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

На рис.1.1. наведена спрощена |зображати| структурна схема сучасного комп'ютера.

1.2. Загальні|загальні| принципи роботи комп'ютера

Роботою комп'ютера управляє програма – послідовність команд, що примушують процесор виконувати згадані вище дії. Стартова програма, яка починає виконуватися відразу ж при включенні комп'ютера, записана в  енергонезалежному пристрої постійної пам'яті, - ППП (ROM – read only memory, англ.). Ця програма зчитує з нульової доріжки жорсткого диска програму-завантажувач, поміщає її в  пристрій оперативної пам’яті - ПОП, (RAM – random access memory, англ.) і передає управління цій програмі.   Завантажувач зчитує з диска і запускає програмне забезпечення операційної системи - ОС, (OS - operation system, англ.), що здійснює управління обчислювальним процесом. Під управлінням ОС зчитуються в ПОП і запускаються прикладні програми (application programs, англ.).

В першому, грубому розгляданні можна рахувати, що для роботи будь-якої, прикладної або системної, програми завантажувач виділяє в ПОП дві області:

сегмент кодів – область, де розміщується код завантажуваної на виконання програми,

сегмент даних – область, де розміщуються оброблювані цією програмою  дані.

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

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

Мінімальною одиницею інформації, що адресується, в сучасних комп'ютерах, прийнятий байт (byte – 8 двійкових розрядів-біт). Адресний простір ПОП починається з нульової адреси. Частину адресів спільного адресного простору займає ППП і буфер відеопам'яті дисплея.

Код кожної команди, розташованої в ПОП (ППП) за певною адресою, містить|утримує|:

  •  код операції
  •  0,1 або 2  адреси даних-операндів (залежно від коду операції).

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

1.3. Позиційні системи числення

Як зазначено вище, комп'ютер працює з даними в двійковому форматі. Коротко ознайомимося з особливостями двійкової системи числення, де окремі розряди можуть набувати тільки два значення: 0 і 1. Двійкова система, як і  десяткова, відноситься до класу позиційних систем. У позиційній десятковій системі  одиниця у позиції (розряді) зліва більше одиниці в позиції справа вдесятеро.

Наприклад, десяткове число 1325 утворено так:

132510=5+(2*10)+((3*10)*10)+(((1*10)*10)*10)=5*100+2*101+3*102+1*103.

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

11012=1*20+0*21+1*22+1*23=1+0+4+8=1310.

Програмісти часто користуються також шіснадцятковою системою числення, розряди (цифри) якої можуть набувати значень: 0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F|. У Таблиці 1.1 показана відповідність числових даних в різних позиційних системах числення, вживаних при програмуванні. Початкуючим програмістам рекомендуємо вивчити цю таблицю напам'ять.


Таблиця 1.1.

Система числення

10-тичн.

8-ричн.

16-ричн.

2-їчн |.

(тетрада)

10-тичн.

8-ричн.

16-ричн.

2-їчн. (тетрада)

0

0

0

0000

8

10

8

1000

1

1

1

0001

9

11

9

1001

2

2

2

0010

10

12

A

1010

3

3

3

0011

11

13

B

1011

4

4

4

0100

12

14

C

1100

5

5

5

0101

13

15

D

1101

6

6

6

0110

14

16

E

1110

7

7

7

0111

15

17

F

1111

Між двійковою і шіснадцятковою| системою є проста відповідність – кожен символ шіснадцяткової | системи переводиться|переказує| в тетраду (4 біта) двійкової системи відповідно до Таблиці 1.1

З’ясуємо зворотню операцію перетворення десяткового числа у шіснадцяткове. Для цього потрібно число у десятковому представленні послідовно ділити на 16, регіструючи при кожному діленні залишок. Наприклад, нам потрібно знайти 16-кове представлення десяткового числа 2010. Послідовність операцій представимо в Таблиці  1.2:


Таблиця 1.2

Чисельник

Знаменник

Частка

Залишок10

Залишок16

2010

16

125

10

A

125

16

7

13

D

7

16

0

7

7

Таким чином, 201010= 7DA16. Далі, керуючись Таблицею 1.1, можемо вказати двійкове представлення цього ж десяткового числа: 201010=7DA16=0111 1101 10102

Контрольні питання:

  1.  Складові частини компютера.
  2.  Послідовність дій запуску ПК.

Завдання для самостійної роботи

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


Розділ 2. Історія розвитку мов|язиків| програмування високого рівня

Мови програмування високого рівня (МВР) з'явилися вже на перших етапах становлення обчислювальної техніки. Першою такою поширеною МВР, була розроблена американськими фахівцями  в середині 50-х мова ФОРТРАН (FORTRAN- formula translator, англ.). Як випливає з  назви, ця мова орієнтована на проведення математичних розрахунків, що було важливе в епоху бурхливого розвитку ядерної фізики і авіаційно-космічній техніки.  Його відрізняють простота і синтаксична строгість.

На цій мові розроблені бібліотеки програм науково-технічних розрахунків, які не втратили актуальності і в даний час. Досить відзначити, що до складу інструментальних засобів сучасних ПК входить програмна середа ФОРТРАН. Мова жива впродовж 60-ти років! Основні конструкції цієї мови увійшли до сучасних МВР без істотних змін.

Конкуренцію Фортрану повинна була скласти мова|язик| АЛГОЛ (ALGOL| – algorithmic| language|) розробки європейських, у тому числі радянських фахівців|спеціалістів|, що з'явилася|появлявся| в 1960 році. Алгоритмічно і синтаксично ці дві мови|язики| дуже близькі і в перші роки розвивалися паралельно - на американських ЕОМ – ФОРТРАН, на  французьких, німецьких і радянських ЕОМ – АЛГОЛ-60.

Ситуація змінилася, і не на користь Алголу, в середині 60-х, коли почалася|починала| експансія американської обчислювальної техніки. В цей час СРСР і країни СЕВ прийняли ідеологію американських великих ЕОМ з|із| архітектурою IBM-360| і малих ЕОМ з|із| архітектурою PDP-7|, на яких використовувалися транслятори з Фортрану і мови|язика| інженерних розрахунків БЕЙСІК.

Оскільки великі ЕОМ були орієнтовані на нескладні, але|та| інформаційно ємкі|ємні| комерційні розрахунки, з'явилася|появлявся| спеціалізована МВР КОБОЛ - (COBOL-| common| business| oriented| language, англ.|). У цій мові|язиці| вперше|уперше| особлива увага приділена обробці символьної інформації (обробка структурованих даних, копіювання, порівняння  символьних рядків, робота з|із| текстовими дисплеями,  зовнішніми накопичувачами великого об'єму|обсягу| і так далі). Логічним продовженням цього напряму|направлення| на сучасному рівні є мова|язик| FOXPRO|, а також бібліотечні функції обробки символьної інформації в сучасних мовах.

Наступний|такий| крок розвитку  мов|язиків| високого рівня – це  поява МВР – Паскаля і  Сі (PASCAL, C,C++), які покликані задовольнити вимоги сучасних інформаційних технологій.      

Мова|язик| програмування високого рівня ПАСКАЛЬ (Pascal| – на честь швейцарського фізика Блеза Паскаля, 1623-1662 рр.) була запропонована|вигадувати| швейцарським програмістом Никлаусом Віртом  в 60-х роках як засіб навчання|вчення| початкуючих програмістів. Строгість|суворість| і синтаксична прозорість мови|язика| відразу завоювала симпатії розробників трансляторів, що сприяло  повсюдному поширенню|розповсюдженню| мови|язика| як інструментального засобу для великих і малих ЕОМ.

З|із| появою в 80-х  роках персональних комп'ютерів і середовища|середовища| програмування Turbo| Pascal| фірми|фірма-виготовлювача| Borland|, автор – Андерс Хейлсберг (Anders| Heilsberg|), ПАСКАЛЬ став домінуючим інструментальним засобом для розробки прикладного програмного|програмового| забезпечення, яким  залишається і до цього дня.

Паралельно із|із| становленням  МВР ПАСКАЛЬ в 70-х роках з'явилася|появлявся| мова|язик| С (читається –сі). Її створив програміст фірми|фірма-виготовлювача| Bell| Laboratories|  Денніс Рітчи (Dennis| Ritchie|), як інструментальний засіб розробки програмного|програмового| забезпечення операційної системи  UNIX|  для мінімашини  PDP-7|. На відміну від строго|суворий| регламентованого Паскаля  первинний варіант мови|язика| С (1978р|.) допускав досить|достатньо| вільне|вільне| поводження з різними типами даних, що при обчисленні|підрахунку| виразів  і зверненні до підпрограм часто приводило|наводило| до так званих ‘побічних ефектів -| неконтрольованим змінам значень змінних.

Стандарт мови|язика| С (ANSI| C) був введений|запроваджувати| тільки|лише| в 1983 р. Він частково нівелював ці недоліки|нестачі|. На роботу комісії із стандарту ANSI| C значно вплинули ідеї, закладені в Турбо Паскалі фірми|фірма-виготовлювача| Borland|. З того часу між цими двома МВР йде негласне змагання і взаємовплив – нові ідеї однієї мови|язика| тут же з'являються|появляються| в іншій. Так під впливом Паскаля в Сі з'явилася|появлялася| чіткіша регламентація типів даних, а під впливом Сі в Паскалі з'явилися|появлялися| оператори дострокового переривання циклу BREAK| і CONTINUE|.

У 1983 р. співробітник Bell| Laboratories| Бьярн Страуструп (Bjarn| Straustrup|) розробив  C++| - вдосконалений, об'єктно-орієнтований варіант мови|язика| Сі. У новому варіанті мови|язика| посилений контроль над типами даних, що дозволило усунути головний|чільний| недолік|нестачу| ранніх варіантів Сі - побічні ефекти.

Разом з Turbo Pascal 7.0  мова C++ підтримує як традиційну технологію програмування, засновану на використанні підпрограм, так і нову технологію об'єктно-орієнтованого програмування (ООП), що використовує апарат спадкоємства властивостей і інкапсуляції, – локалізації зони дії змінної, що значно підвищує надійність програмного продукту.

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

  •  Незалежність мови|язика| від апаратних засобів і архітектури комп'ютерної системи,
  •  Підтримка технології об'єктно-орієнтованого програмування,
  •  Наявність засобів візуального програмування, що в значній мірі|значною мірою| автоматизують процес програмування людино-машинного інтерфейсу – так званого  MMI| (man-machine| interface, англ.|),
  •  Робота з|із| сучасними системами управління базами даних (СУБД),
  •  Робота з|із|   системами телекомунікації,
  •  Підтримка 2D-| і 3D-| комп'ютерної графіки.

Цим вимогам в більшій або меншій мірі відповідають сучасні версії мов|язиків| PASCAL  і С(С++).  

Контрольні питання:

  1.  Історія виникнення сучасних МВР.
  2.  Вимоги для сучасних МВР.


Розділ 3. Загальні|загальні| принципи програмування

3.1. Вимоги до професії

Один із законів Паркінсона наголошує: “У кожній відладженій програмі є, як мінімум, одна помилка. Правило зберігає силу після виправлення цієї помилки”.

Це не жарт - це гірка правда. Але, є різні типи помилок|та|є різні  . Відомий анекдот програміста:

- Майкрософт для нової класної версії Windows| випустив документ виявлених помилок. Там їх ціла тисяча!

- А в моїй програмі тільки єдина помилка!

- Ну, і як?

- Та|так|, програма не працює!

Важка|тяжка| ти, доля|доля| програміста! Персональний комп'ютер – його основний ‘робочий інструмент’. Цей інструмент  складний і вимагає від майстра певних здібностей і досить|достатньо| обширних|величезних| спільних|загальних| і спеціальних знань. Отже, про професійні здібності і спільні|загальні| знання.

По-перше, програміст повинен мати добру пам'ять. Ця якість необхідна для запам'ятовування імен змінних і ‘одномоментного бачення|видіння|‘ як можна більшого фрагмента |налагоджувати| програми, що відладжується.|зразок| 

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

По-третє, програміст має бути спостережливим|спостережливим|. Ця якість дуже допомагає тоді, коли не вдається логічно ‘обчислити|вичисляти|’ причину помилки. В цьому випадку програміст варіює вхідними даними або намагається|пробує| використовувати інший варіант програмного|програмового| блоку. Якщо він спостережливий|спостережливий|, то може відмітити|помітити| реакцію, яку він не чекав як відгук на такі варіації. “…Я змінив|зраджував| знак другого операнда, а результат  змінився замість очікуваної|сподіваної| одиниці на мінус одиницю! Що б це означало|значило|?.”  Далі до аналізу ситуації підключається апарат логічного мислення. 

У важких|тяжких| випадках  деякі програмісти, не знайшовши причину помилки, просто переписують програму заново|наново|. Як не дивно, це інколи|іноді| допомагає. Але|та| ми не  прихильники|прибічники| таких методів ‘стрілянини|стрільби| по площах|площах|’. Справжній|даний|, добросовісний програміст докопуватиметься до причини помилки. В крайньому випадку|у крайньому разі|, він виконає покрокову відладку, ретельно оцінюючи результати  кожного кроку до тих пір, поки помилка не буде ‘спіймана’. При цьому дуже часто помилка виявляється абсолютно|цілком| в іншому програмному|програмовому| блоці, а не в тому, на якому було зосереджено увагу програміста (тому і не допомагало логічне мислення!).

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

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

Незалежно від спеціальності по диплому, на всьому протязі професійної кар'єри програміст має бути готовий освоювати все нові і нові галузі знань. Одним словом, “Вік живи - вік навчайся ”!

3.2. Мови|язики| програмування і програмне|програмова| середовище|середовище|

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

Можливості системи команд якнайповніше використовує  мова Асемблера (Assembler, від assemble – збирати, вмонтовувати, англ.) – так звана мова низького рівня. У загальному випадку  один символьний рядок Асемблера, як правило, породжує одну машинну команду.

До поширених сучасних професійних універсальних мов|язиків| високого рівня відносять ПАСКАЛЬ (Pascal|) [1,2] і Сі (C|із|, С++, C#|) [3,4,5]. Вони відрізняються компактнішим описом програми, ніж Асемблер. Один символьний рядок  МВР породжує в середньому 5-6 команд машинного коду.

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

  •  редактор символьного тексту програми, складеної на МВР;
  •  редактор екранних форм, за допомогою яких відображуються|відображають| результати обчислень|підрахунків| і органи управління обчислювальним процесом;
  •  транслятор,  що здійснює переклад програми,   написаної на МВР (початковий текст), в так званий об'єктний код – двійковий машинний код, доповнений зсилками на імена зовнішніх щодо трансльованої програми змінних і функцій;
  •  розвинені бібліотеки стандартних програм загально-математичного  і спеціалізованих напрямів;
  •  компонувальник, що об'єднує код трансльованої програми з об'єктними кодами інших, у тому числі бібліотечних, програм в єдиний завантажувальний *.exe – модуль і запам'ятовує його на зовнішньому носієві (диску);
  •  засоби відлагодження програм.

В даний час транслятори, як правило, об'єднуються з компонувальниками і називаються компіляторами (compile  – збирати, англ.)

До сучасного програмного|програмової| середовища|середовища| відносяться: DELPHI| (мова|язик| Паскаль) [6], Borland| С++ Builder| 6 (мова|язик| C++|) [7], С# технології .NET Framework| (мова|язик| C#| - читається: Сі шарп| або Сі дієз) [8,9], Visual| C++|[10], Visual| Basic| [11].

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

3.3. Структура програмних комплексів

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

Текст книги може посилатися на інші книги, зокрема, на довідники. У нашій термінології – це бібліотеки стандартних підпрограм (БСПП). Кожна мова високого рівня має свій набір БСПП, що значно полегшує роботу програміста, оскільки не доводиться кожного разу заново ‘винаходити велосипед’. Зазвичай бібліотеки стандартних підпрограм сучасних МВР містять наступні підпрограми:

  •  обчислення|підрахунки| математичних функцій (sin|, tg|, ln|, exp|.. і так далі)
  •  роботи із|із| зовнішніми пристроями|устроями| (клавіатура, миша, дисплей, принтер, диски)
  •  роботи з|із| графікою
  •  людино-машинного інтерфейсу (MMI -  man-machine interface,англ.)
  •  створення/знищення|створіння| об'єктів для об'єктно-орієнтованого програмування
  •  звернення до функцій операційної системи, так званий  API (application program interface,англ).

Процес розробки складного програмного|програмового| комплексу починається з розбиття початкового|вихідного| завдання|задачі| на окремі, більш-менш самостійні підзадачі, які розбиваються на ще дрібніші|мілкі| підзадачі і так далі поки об'єм|обсяг| підзадачі нижнього рівня ієрархії буде осяжно малим, – не більше 1-2 сторінок тексту на МВР.

Зазвичай використовується технологія низхідного програмування [12]: у програмі, старшій за ієрархією, робляться виклики підпрограм, але замість реальної підпрограми ставиться підпрограма - ‘заглушка’, що лише імітує роботу справжньої підпрограми.

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

Символьні тексти програмного комплексу можуть зберігатися в декількох окремих символьних файлах з розширеннями:

*.pas-| для Pascal - програм

*.c|із| – для програм на Сі

*.cpp-| для програм на C++|

*.cs| – для програм на C#|

*.bas| – для програм на Бейсику

*.asm| – для програм на Асемблері.

Для складних програмних|програмових| комплексів кількість таких символьних файлів з|із| початковим|вихідним| текстом може досягати декількох сотень і навіть тисяч з|із| розміщенням в кожному з них текстів декількох десятків підпрограм. Сучасне програмне|програмова| середовище|середовище| дозволяє компонувати програмні|програмові| комплекси, окремі символьні файли яких написані на різних мовах|язиках|.


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

У тексті програми на МВР розрізняють 3  розділи:

  •  Заголовок програми (підпрограми)
  •  Розділ опису даних (констант і змінних)
  •  Розділ виконуваного коду (тіло програм).

У мові|язиці| Паскаль заголовок програми завжди розміщується першим. У нім же розділ опису даних завжди передує розділу опису виконуваного коду. У Сі та Бейсику це обмеження зняте, і нові змінні можна оголошувати упереміж з|із| виконуваним кодом.

Заголовок програми (підпрограми) містить|утримує|:

  •  ім'я програми (підпрограми)
  •  список і типи вхідних параметрів-даних
  •  тип значення, що повертається визиваючій програмі (для підпрограм-функцій).

Розділ опису даних містить|утримує| імена і типи|типи| даних (змінних і констант).

Розділ виконуваного коду містить|утримує| кодову частину|частину| – тіло програми. Тіло головної|чільної| програми містить|утримує| здебільше|здебільшого| коди викликів підпрограм з|із| невеликими вкрапленнями машинних команд, що аналізують код завершення викликаної|спричиняти| підпрограми або пересилають результати в інші області пам'яті  або інші підпрограми. Тіло підпрограм  нижнього рівня містить|утримує| тільки|лише| коди машинних команд.

3.5. Технологія програмування і налагодження програм на МВР

Програмування і налагодження програм на МВР може бути представлене послідовністю кроків:

  1.  Завантажувачем операційної системи завантажується і запускається на виконання стартова секція програмного середовища (Turbo Pascal, Borland C,  Delphi, Visual C, C++ Builder, C#) з її інтерфейсом користувача - MMI (man-machine interface).
  2.  За допомогою MMI| програміст завантажує із зовнішнього носія файл з|із| початковим|вихідним| текстом на відповідній мові|язиці|  або безпосередньо формує текст у вікні символьного редактора цього програмнго|програмової| середовища|середовища|.
  3.  Відредагований програмний|програмовий| текст запускається на компіляцію. В разі|у разі| відсутності синтаксичних помилок програма, що відтрансльована і скомпонована|, запускається на виконання.
  4.  Якщо транслятор виявив синтаксичну помилку, то програміст відповідно виправляє початковий|вихідний| текст  і знову повторює компіляцію до тих пір, поки транслятор не перестане виявляти помилки.
  5.  При виконанні програми, вільної від синтаксичних помилок, можливі діагностичні повідомлення про помилки часу виконання (run-time errors). Якщо таких помилок немає, то аналізуються вихідні дані програми на відповідність їх тестовому завданню.
  6.  Якщо вихідні дані роботи програми не відповідають потрібним, то:

а) аналізуються вхідні дані програми на предмет неточностей

б) аналізується алгоритм роботи

в) виконується налагоджувальний роздрук|роздруківка| результатів, у важких|тяжких| випадках – покрокове виконання програми.

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

3.6. Техніка обчислень|підрахунків|

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

У сучасних середовищах візуального програмування (Delphi, Visual C, Borland C++Builder, Microsoft.net C#) функція монітора максимально автоматизована і прихована від розробника прикладної програми, що  спростило програмування застосувань. Проте, такий компонент застосування, створений автоматично або ‘вручну’, завжди існує і необхідно розуміти механізм роботи програмного комплексу застосування в середовищі сучасної операційної системи.

На рис 3.1. представлений|уявляти| граф роботи прикладних програм в середовищі|середовищі|  операційної системи.


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

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

3.7. Типи обчислювальних процесів

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

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

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

Постановка завдання під цей алгоритм може виглядати так: “ Після запуску програми діждатися запрошення (блок 2) і ввести з клавіатури два числа (блок3). Якщо перше число більше другого (блок 4), то викликати підпрограму A (блок 5), інакше – викликати підпрограму B (блок 6). Залежно від результатів u і w роботи цих підпрограм (блок 7  аналізу), виконується один з блоків лінійних обчислень (блоки 8, 9), або програма повертається до введення запрошення (блок 2). Результати роботи блоку 8 (9) роздруковуються на принтері (блок 10). Блоки 1,11 – пуск і зупинка програми ”.

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


 


Як видно
|показний| з|із| блок-схеми рис.3.2., програма складається з операторів вводу/виводу|виведення| (блоки 2,3,10), операторів аналізу і вибору однієї з двох  або з|із| декількох гілок обчислювального процесу (блоки 4,7), операторів виклику підпрограм (блоки 5,6), блоків операторів лінійних обчислень|підрахунків| – 8, 9.

3.8. Цикли в обчислювальному процесі 

При роботі програми часто виникає необхідність  повторного виконання якоїсь ділянки (блоку) програми. На рис.3.2. – це гілка   повторень, що йде від блоку  аналізу 7 до блоку введення початкових даних 2. Цикл виконання блоків 2-7 повторюватиметься поки змінні u  і w будуть рівні. При нерівності цих змінних програма завершиться виводом на друк якихось результатів обчислень в одному з блоків 8,9. На блок-схемах  гілка, що створює цикл, змальовується лінією із стрілкою.

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

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

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

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

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

Цикл може бути утворений чотирма способами:

  1.  Цикл з|із| умовним переходом на мітку
  2.  Рахунковий цикл
  3.  Цикл з|із| передумовою
  4.  Цикл з|із| постумовою.

Цикл з умовним переходом на мітку утворюється в результаті виконання  умовного оператора, що перевіряє деяку умову (u=w, в прикладі рис 3.2.) і, при виконанні умови, передає управління  на відміченого оператора. На рис 3.2. міткою L1: відмічений перший оператор блоку 2. Спосіб організації циклу з передачею управління ‘далеко назад’ на  відміченого оператора – природний апарат машинних команд, застосовується в сучасному Асемблері. Він широко застосовувався у Фортрані і Бейсику, що вело до структурної непрозорості, заплутаності створюваної програми. Мірою боротьби із структурною плутаниною було виникнення технології структурного програмування [13], де основний принцип - мінімізація використання в програмуванні відмічених операторів. Цей тип циклу вважається застарілим, і в сучасному програмуванні розцінюється як ‘ознака поганого смаку’. Проте, сучасні МВР зберегли апарат передачі управління на мітку, і в деяких випадках, коли цикл охоплює багато обчислювальних блоків, буває зручнішим скористатися цією фортранівсько-асемблерною архаїкою.

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

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

Приклад|зразок|  3.1а. Мова|язик| Паскаль:

.....

1)       var| i,s,n:integer|;

.....

2)        s:=0|;

3)       n:=10|;

4)       for| i:=1| to| n do|

5)        begin|

6)         s:=s+i|;

7)         write|(s:3|);

8)        end|;

.....

Приклад|зразок|  3.1б. Мова|язик| Сі:

.....

1)        int| i,s,n|;

.....

2)        s=0|;

3)        n=10|;

4)        for| (i=1|; i<=n|; i++|)

5)         {

6)           s=s+i|;

7)           printf|(“%3d”,s);

8)            }

.....

Рядки з крапками показують, що Приклад 3.1 – лише фрагмент програми на відповідному МВР, нумеровані рядки – оператори цього фрагмента (в справжній програмі нумерація не застосовується, тут нумерація наведена для пояснення дії окремих операторів). Програма накопичує суму членів простої арифметичної прогресії у комірці з ім'ям s. Змінна циклу зберігається у комірці i . Число членів арифметичної прогресії задається у комірці n.

Рядок 1 описує тип використовуваних змінних, в даному випадку  i,s,n – змінні цілого типу. Рядки 2,3 задають початкові значення – очищують комірку підсумовування s і задають число n. Рядки 4-8  - рахунковий цикл. Рядок 4 – оператор рахункового циклу, рядки 5,8 – операторні дужки, що обмежують складеного оператора, що складається з двох простих операторів - накопичення суми (рядок 6) і роздруку її значення (рядок 7).

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

У тих випадках, коли заздалегідь невідоме число циклів повторення, використовуються два інших сучасних ‘безміткових|’ типів циклу.

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

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

Цикл з|із| постумовою  завжди виконується як мінімум один раз, а цикл з|із| передумовою може не виконатися жодного разу. Поширеніший цикл з|із| передумовою, де він використовується при читанні  рядків-записів з|із| файлу на зовнішньому носієві. Якщо при черговій спробі читання запису з|із| файлу виникає умова-ситуація ‘кінець файлу’, то програма припиняє виконання циклу читання. Файл може мати нульову довжину (є ім'я, але|та| немає даних). В цьому випадку команди циклу не виконуються жодного разу.

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

3.9. Загальна структура прикладної програми

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

У стартовій секції виконується підготовка на початок роботи програмного|програмового| комплексу:

  •  ініціалізація (часто – очищення)  змінних і приведення в початковий|вихідний| стан|достаток| прапорців аналізу умов
  •  резервування (відкриття|відчиняти|) необхідних пристроїв|устроїв| вводу/виводу|виведення|.

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

|показний| ||чільно 

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

Відмітимо, що в завантажувальний *.exe - модуль застосування користувача з БСПП поміщаються тільки необхідні підпрограми. Одна і та ж підпрограма з БСПП, ОП, СП може викликатися з декількох точок програм різних рівнів, що значно скорочує об'єм завантажуваного модуля. Так до службової підпрограми Сп1 звертаються монітор і дві оброблювальні  програми ОП1, ОПm, а до СПk звертаються ОП1 і СПn+1. У свою чергу, СПk звертається до двох бібліотечних функцій.

3.10. Типи підпрограм

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

Результат виконання підпрограми може бути переданий в викликаючу програму через  регістр  процесора. Така підпрограма називається функцією. У мовах високого рівня ім'я функції є ім'ям цього результату і може використовуватися в арифметичних і логічних виразах спільно із звичайними змінними. Приклад – бібліотечна функція обчислення сінусу аргументу x, – sin(x). Підпрограми, що в явному вигляді не передають результат в викликаючу програму, називаються процедурами. Приклад - процедура очищення екрану дисплея CLRSCR.  

Контрольні питання:

  1.  Які Ви знаєте мови програмування високого рівня та програмні середовища.
  2.  Складові сучасного програмного середовища
  3.  Принципи побудови великих програмних комплексів (програмних застосувань)
  4.  Основні складові розділи програми на МВР
  5.  Граф роботи програмних застосувань в середовищі сучасної ОС
  6.  Типи обчислювальних процесів. Навести приклад блок-схеми алгоритму.
  7.  Типи ціклів в обчислювальному процесі.
  8.  Загальна структура програми-застосування. Типи підпрограм.

Завдання для самостійної роботи

  1.  Розробити схему програми перетворення десяткового числа в двійкове.
  2.  Розробити схему програми перетворення шістнадцяткового числа в десяткове
  3.  Орієнтуючись на Приклад 3.1а скласти програму обчислення  факторіалу – n!


ЧАСТИНА|частина| 2.  МОВА|язик| ПРОГРАМУВАННЯ PASCAL (ПАСКАЛЬ)

Розділ 4.  Знайомство з|із| мовою|язиком| Паскаль|язик| |

4.1. Середовище програмування Borland Turbo Pascal v.7.0 (DOS)

Освоєння технології програмування найлегше почати з dos-версії мови фірми Борланд - Turbo Pascal 7.0. Хай вас не бентежить той факт, що ви на сучасному ПК з сучасною  операційною  системою  використовуєте  програмне  забезпечення    30-річної давності, розроблене для операційної системи DOS Microsoft. Про правильність роботи старого програмного забезпечення поклопоталися розробники Біла Гейтса. Основоположною концепцією фірми Microsoft є сумісність нових операційних систем із старим матзабезпеченням.  Саме концепція еволюційного розвитку програмного забезпечення дозволила фірмі Microsoft завоювати і впродовж декількох десятиліть утримувати провідну позицію в розробці операційних систем для персональних комп'ютерів.

Для початку роботи створимо мінімально можливу версію інструментального середовища|середовища| Turbo| Pascal|, яка в архівному стані|достатку| легко уміщається навіть на дискеті 3,5. Це корисно виконати|проробити| з двох міркувань|тямі|:

  1.  Створюємо гранично компактне  мобільне інструментальне середовище|середовище|, придатне для установки на будь-якому ПК архітектури Intel|, – від самих древніх|стародавніх| IBM XT до новітніх|найновіших|.
  2.  Визначаємо, які компоненти програмного|програмової| середовища|середовища| істотно|суттєвий| важливі|поважні| для її функціонування. Не секрет, що в інсталяційний пакет програмного середовища|середовища| розробник поміщає ‘все, що напрацював’ з даного питання, включаючи ‘технологічне сміття’, яке ніколи не знадобиться користувачеві. Практика роботи на Турбо Паскалі дозволила зі|із| всієї великої кількості компонент виділити необхідний мінімум.

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

З інсталяційного диска перепишемо в корінь (тобто без використання піддиректорій!) цієї директорії компоненти відповідно до Таблиці 4.1.

Таблиця 4.1.

№п/п

Найменування  файлу-компоненту

Директо-рія інсталя-ційного|

диска

Об'єм|обсяг|

кіло-байт

Призначення компоненту

1.

TURBO.exe

BIN

952,0

Основний модуль програмного середовища

2.

TURBO.TPL

BIN

48,5

Системна бібліотека підпрограм

3.

TURBO.TP

BIN

4,0

Файл конфігурації прогр.середи

4.

GRAPH.TPU

UNITS

33,0

Б-ка графічних підпрограм

5.

EGAVGA.BGI

BGI

5,5

Графічний драйвер

6.

            *.CHR

BGI

122,0

Шрифти тексту в графіч.режимі

7.

TURBO.TPH

BIN

734,0

Довідковий файл

Для створення програм, що працюють в текстовому режимі, досить перших трьох файлів. Для програм, що працюють з графікою, додатково необхідна бібліотека графічних підпрограм (GRAPH.TPU) і графічний драйвер (EGAVGA.BGI) Програмне середовище має довідкову систему (файл TURBO.TPH), що викликається з середовища Турбо Паскаля  одночасним натисненням клавіш  Ctrl+F1.

 На Рис.4.1. показаний екран директорії d:\Tpmin| зі|із| всіма необхідними для роботи компонентами.

Рис 4.1.

Запускаємо *.exe-файл програмного|програмової| середовища|середовища|TURBO|.EXE. На екрані з'являється|появляється| головне|чільне| меню|програмової| |середовища|  (Рис.4.2.)

Рис.4.2.

Натискуючи клавішу F10, дістаємо доступ до  головного меню (зверху). Клавішами курсору “”, ”” вибираємо пункт меню File. Клавішами курсору “”, “вибираємо пункт Open випадного меню. Натискуємо клавішу Enter, отримуємо екран, змальований на рис.4.3.

Рис.4.3.

Далі, натискуючи клавішу Tab, переміщаємося по вікнах підміню. Вийшовши у вікно Files, стрілками курсору вибираємо потрібний *.pas-файл. За допомогою Tab  активізуємо вікно Open і натискуємо клавішу Enter. Отримуємо екран рис 4.4. – вікно редагування вибраного *.pas-файла.

Якщо ви складаєте нову програму, то на мал. 4.2. вибираєте File\New. З'являється порожній синій екран редагування файлу noname.pas.

Рис.4.4.

Редагування тексту Паскаль-программи виконується за допомогою клавіш курсора і наступних|слідуючих| клавіш:

Enter – створення нового порожнього рядка, курсор встановлюється в її початок

Backspace- знищення символу зліва

Delete – знищення символу справа

Insert – перемикання між режимами заміна/вставка символу

Ctrl+K  B – початковий маркер блоку, що позначається

Ctrl+K  K – кінцевий маркер блоку, що позначається (блок закрашується білястим   кольором)

Ctrl+K  C – копіювання поміченого блоку в позицію курсору активного вікна

Ctrl+K  V – переміщення поміченого блоку в поточну позицію курсору

Ctrl+K  Y – знищення поміченого блоку

Ctrl+K  H – зняття позначки з блоку

Ctrl+Y  - знищення рядка

Аlt+цифра – активація  одного з 9-ти вікон, в яких редагуються Паскаль-файли; Alt+0 – редагування списку цих вікон

Ctrl+Insert – запис поміченого блоку в системний буфер

Shift+Insert – читання блоку з системного буфера в позицію курсору поточного активного вікна

Аlt+f3 – знищення активного вікна

Esc – скидання попередньої команди редагування

F2 – запис відредагованого файлу поточного активного вікна на диск

F9 – трансляція-компоновка Паскаль-програми

Ctrl+F9 – трансляція-компоновка-виконання Паскаль-програми

Аlt+x – вихід з Паскаль-середи

Після редагування тексту вибраної програми перевіряється її синтаксис (клавіша F9). Після усунення синтаксичних помилок програма запускається на виконання (клавіші Ctrl+F9). По клавіші F2 відладжена програма запам'ятовується на зовнішній носій.

Налаштування програмного середовища Turbo Pascal  виконується через вікно Options верхнього меню і досить детально описано в [1].

4.2. Перша програма. Поняття про типи даних і оператор циклу for 

Тепер, коли ми розуміємо структуру програми на МВР (див. розділ 3) і навчилися управляти програмним середовищем Турбо Паскаля (див. розділ 4.1), приступимо до освоєння азів мови. Вивчення  почнемо з конкретного прикладу.

Припустимо, що|нехай| нам необхідно вивести на екран дисплея рядок тексту:

*** Моя перша програма ***,

а в наступному рядку - всі десяткові цифри: 0,1..,9.

На рис.4.5. показаний прокоментований початковий текст  програми, що виконує це завдання. Відразу відзначимо, що коментарі – не сприймана транслятором частина тексту Паскаль-програми,  поміщені у фігурні дужки: {….}. Звичайно, Ваші майбутні реальні Паскаль-програми не будуть настільки старанно прокоментовані, але мінімізувати цей важливий компонент програмного забезпечення, як це роблять багато початкуючих програмістів, категорично не рекомендуємо.

Річ у тому, що початковий текст – це основний документ, по якому надалі вестиметься модернізація Вашого програмного продукту. Без модернізації не обходиться жодна серйозна розробка (зверніть увагу, що ми користуємося сьомою (!) редакцією програмної середи Turbo Pascal 7.0 ). З одного боку, початковий текст має бути зрозумілий транслятору, а з іншого боку – розробникові, що модернізує  Ваше творіння. Таким розробником можете виявитися Ви або ваш колега. Тому ретельно, але не надмірно  коментуйте Вашу Паскаль-програму, щоб Ви змогли в ній розібратися через рік або через 10 років. Не сподівайтеся на свою прекрасну пам'ять. Як показує досвід,  алгоритм програми має властивість забуватися з дивною прудкістю!

Рис. 4.5.

Ще одна корисна властивість фігурних дужок: при відладці програми Ви можете оперативно відключати якісь  фрагменти програми, перетворюючи цей фрагмент на коментар (приклад - див. мал. 4.6). Це настільки дієвий прийом, що досвідчені програмісти практично ніколи не користуються стандартним відладчиком. Коментарі можна брати також в таких дужок: (*....*). Другий вид дужок використовується у поєднанні з першим саме для ефективного управління тимчасовим відключенням програмних блоків.

Отже, розглянемо|розглядатимемо| нашу першу Паскаль-програму.

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

Якщо програма велика, і її компоненти розташовані в декількох *.pas- файлах (див. розділ 1), то модулі з неголовною програмою повинні починатися з обов'язкового ключового слова unit (англ., модуль – відособлена частка чогось), за яким через пропуск слідує ім'я цього модуля. Ім'я модуля  в заголовку і ім'я *.pas-файла, у якому поміщені початкові тексти підпрограм цього модуля,  повинні збігатися(!).

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

Далі починається розділ опису даних. Константам (секція const) і змінним (секція var) програміст дає довільні символьні імена, яким транслятор ставить у відповідність адресу цієї змінної (константи) в ПОП. Залежно від типу змінної транслятор резервує під неї певну кількість байтів. Наступному імені транслятор привласнює наступний вільний адрес і так далі. Для  імен змінних (констант) використовуються літери латинського алфавіту, цифри, а також знак підкреслення: (‘_’).  Першим символом імені має бути буква або знак підкреслення, тобто ім'я не може починатися з цифри.

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

Третій рядок – це опис константи - символьного рядка. Ключовим тут є слово const. Далі через один або декілька пропусків – ім'я константи (msg), знак рівності і значення символьного рядка в апострофах. У ПОП цей рядок займає 30 байтів - вміст поля між апострофами, включаючи пропуски, плюс один байт, де зберігається довжина символьного рядка (в даному випадку – число 29).

Четвертий рядок містить ключове слово var, що позначає початок секції опису змінних. П'ятий рядок оголошує імена двох цілочисельних змінних типа integer, кожна з яких займає в ПОП по 2 байти, разом – 4 байти. Шостий рядок оголошує ім'я символьної змінної типа char, яка займає в ПОП один байт.

Сьомий рядок – початок розділу кодової частини (тіла) програми. Ключове слово тут – ‘begin’ (так звана відкриваюча дужка блоку - в даному випадку тіла програми). Відмітимо, що після begin крапка з комою не ставиться. Завершує тіло програми ключове слово ‘end.’ (закриваюча дужка тіла програми + крапка). Крапка після закриваючої дужки - вказівка транслятору про завершення трансляції.

Восьмий і дев'ятий рядки – виклик зовнішніх підпрограм. Восьмий рядок (clrscr;) – виклик процедури очищення екрану, яка знаходиться в модулі CRT (див. рядок 2). Дев'ятий рядок (writeln (msg);) – виклик процедури виводу на екран змінної або константи, в даному випадку- msg – символьного рядка - константи.

Десятий-чотирнадцатий рядки – так званий рахунковий цикл for. Ці команди виконуються циклічно десять разів. За допомогою цього циклу виводяться на екран символи цифр ‘0’,’1’,’2’,...,’9’. Загальна структура рахункового оператора циклу  for:

for  <лічильник_циклу> := <поч.зн.ліч.циклу> to <кінц.зн.ліч.циклу> do <оператор>;

Лічильник циклу (у нашому прикладі – змінна i), інколи званий параметром циклу, - змінна цілого типа, в перший момент набуває значення <поч.зн.ліч.циклу>. Найчастіше в Паскалі початкове значення параметра циклу дорівнює 1, але в нашому прикладі <поч.зн ліч.циклу>=0. В принципі це може бути будь-яке ціле позитивне або навіть негативне число.

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

Після ключового слова do йде одиночний простий або багаторядковий складений оператор, що обмежується операторними дужками begin…end . У нашому прикладі використаний складений оператор. Цей складений оператор виконується в циклі 10 разів, при цьому параметр циклу i пробігає значення 0,1,2,3,4,5,6,7,8,9.

Як відомо, кожен символ, що виводиться на екран або принтер, в машинному вигляді|виставі| кодується  одним байтом, тобто двійковими числами  від 00000000 до 11111111, що відповідає десятковим числам від 000 до 255.

Символ-цифра ‘0’ кодується двійковим числом 00110000 (десятковим числом 4810=0*20+0*21+0*22+0*23+1*24+1*25+0*26+0*27), символ ‘1’ кодується десятковим числом 49 і так далі, символ ‘9’- числом 57.

У дванадцятому рядку символьна змінна ch формується складанням константи 48 із змінною циклу i. В результаті для першого циклу, коли i=0, ch має код=48+0=48, що відповідає символу ‘0’; для десятого циклу ch має код=48+9=57, що відповідає символу  ‘9’. Тринадцатий рядок виводить на екран сформований символ. Ці два рядки обрамовани  операторними дужками (begin…end) і утворюють т.з. складений оператор.  

Нарешті останній виконуваний оператор програми (readln;) – ввод даних з клавіатури, тут використовується для призупинення програми, щоб можна було розгледіти результат. Якщо не поставити readln;, то результат роботи вашої програми ‘втече’, тобто на екрані  редагований текст накриє його. В цьому випадку, щоб глянути результат роботи програми, слід одночасно натискувати Alt+F5. Повторне натиснення цих двох клавіш повертає екран редагування.

На рис.4.6 показаний  екран дисплея з|із| результатом виконання нашої першої програми.

Рис.4.6.

Контрольні питання:

1 Основні складові програмного середовища TURBO PASCAL.

2. Органи управління TP7_DOS

3. Прокоментувати програму на Рис.4.5. Складові програми.

Завдання для самостійної роботи

1. Hа основі завдання самостійної роботи розділу 3 (вправа 3.3) скласти та налагодити  програму обчислення  факторіалу (n!). Дослідити, яке найбільше n  не призводить до аварійного завершення програми. Зясувати причину аварійного завершення програми вже при не дуже великих значеннях . 


Розділ 5. Прості типи даних в |язиці| PASCAL і дії над ними

5.1. Типи даних

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

  •  символами – тип char, довжина - 1 байт
  •  символьними рядками – тип string, довжина – від 0 до 255 байт
  •  невеликими цілими числами (–128..+127) – тип shortint, довжина – 1 байт
  •  невеликими позитивними (беззнаковими) цілими числами (0..255) – тип byte, довжина – 1 байт
  •  цілими  числами середньої розмірності (–32768..+32767) – тип  integer, довжина –  2 байти
  •  беззнаковими цілими числами середньої розмірності (0..65535) – тип word, довжина – 2 байти
  •  цілими числами великої розмірності (–2147483648..+2147483647) -тип longint, довжина – 4 байти
  •  логічними величинами– тип boolean, довжина – 1 байт
  •  дійсними числами (числами з плаваючою комою) низької точності, тип – single, довжина – 4 байти
  •  дійсними числами середньої точності, тип – real, довжина – 6 байт
  •  дійсними числами подвійної точності, тип – double, довжина – 8 байт
  •  дійсними числами підвищеної точності, тип – extended, довжина – 10 байт.

У ширшому трактуванні під даними розуміють всі іменовані об'єкти, використовувані в мові|язиці| Турбо Паскаль [1] (рис.5.1.)


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

Як можна відмітити з прикладу попереднього розділу, тіло програми складається з операторів. Кожен оператор закінчується символом ‘крапка з комою’ (‘;’). У одному рядку тексту на МВР може бути декілька операторів. Оператор (за винятком оператора виклику процедури ) розділений на ліву і праву частину знаком операції  привласнення – (‘:=’). У лівій частині від знаку привласнення указується змінна, якої привласнюється  вираз, що стоїть праворуч від знаку привласнення. Вираз може містити імена одній або декілька змінних (операндів), об'єднаних знаками арифметичних або логічних операцій. Порядок обчислення виразу регулюється круглими дужками і пріоритетом операцій, як це прийнято у виразах алгебри.

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

Таблиця 5.1.

Операція

Дія

Пріоритет

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

Тип результату, приклад

not k

Заперечення

(інверсія всіх бітів числа)

1-(найвищий пріоритет) -

унарні операції

Цілі, булеві (Boolean)

Тип результату - тип операнда k.

 Приклад|зразок|:

var| i,k:byte|; у,n:Boolean|;

......

k:=254|; i:=not| k; {k=11111110,i=00000001|}

y:=true|; n:=not| y|в|; {n=false|}

......

@k

Взяття адреси змінної

1

Будь-який

Тип результату - покажчик. Приклад – див. далі опис роботи з покажчиками

i * k

j * t

t * s

Множення

2 –

мульти-плікативні опера-ції

Цілі, дійсні

Тип результату – т.з. ‘старший тип’ (див. нижче)

Приклад|зразок|:

var| i,k:byte|; j:word|; t,s:real|;

begin|

  i:=255|; k:=2|; j:=i*k|; {j=510|}

               { Якби|аби| змінна j була байтом, тобто

                   допускала тільки|лише| числа менше

                   256, то виникла б помилка}

  t:=2|; s:=3.14;{дійсні константи без

                         дробової частки|частини|  можна

                   указувати|вказувати| без десяткової крапки|точки|}

  t:=t*s|; {t=6.28}

     { Паскаль  і Сі допускають використання

         в одному операторові однієї і тієї ж

змінної -як операнд і як результуюча змінна}

 writeln|(t); {Вивід |виведення| на дисплей значення t в

                     експоненціальному форматі}

{j:=j*t|; {Помилка! Так не можна,

     треба: j:=round|(j*t|);  =3203 –  див. нижче}

 t:=j*t|; {Так можна!  t=6.28*510=3202.8}

 writeln|(t:10:3|);{Вивід  на дисплей значення       

                            t у форматі   дійсного числа

                           з  фіксованою крапкою|точки|}

 readln|; {Припинення програми, очікування|чекання| 

               натиснення клавіші  ENTER|}

  end.    {Кінець програми}

i / k

j / t

t / s

Дійсне ділення

2

Цілі, дійсні

Тип результату – т.з. ‘старший тип’ (див. нижче)

i div k

Цілочисе-льне ділення

2

Цілі

Тип результату – цілий. Приклад|зразок|:

....

j:=| 7 div| 5; {j=1|}

....

i mod k

Залишок від цілочисе-льного ділення

2

Цілі

Тип результату – цілий. Приклад|зразок|:

....

j:=| 9 mod| 5; {j=4|}

j:=14| mod| 3; {j=2|}

.....

i and k

Логічне ‘І’ (кон'юнкція, логічне множення)

2

Цілі, Boolean

Тип результату – тип операндів.

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

Приклад|зразок|: 1023 and| –128= 896, що в двійковому вигляді|виді|  виглядає так:

   0000 0011  1111 1111=1023

and| 

   1111 1111  1000 0000=-128

=

    0000 0011  1000 0000     =512+256+128=896.

Приклад|зразок| для логічного типа|типу| :

(5>2) and| (1>2) {цей вираз=| false|, тобто помилковий}

(5>2) and (1<2) {цей вираз= true, тобто істиний}

k shl n

Зсув вліво бітів цілого числа

2

Цілі

Тип результату – ‘старший тип цілих’

Операнд k розширюється до розміру integer|, заповнюючи старші біти знаком числа. Біти операнда k зрушуються|зсовують| вліво на n розрядів. Розряди, що звільнилися|визволяли| справа, заповнюються нулями.

Приклад|зразок|: 8 shl| 4=128, що в двійковому вигляді|виді| виглядає так:

0000 1000 shl 4=1000 0000=128

k shr n

Зсув управо бітів цілого числа

2

Цілі

Тип результату – ‘старший тип цілих’.

Операнд k розширюється до розміру integer|, заповнюючи старші біти знаком числа. Біти операнда k зрушуються|зсовують| управо|вправо| на n розрядів. Розряди, що звільнилися|визволяли| зліва|ліворуч|, заповнюються нулями.

Приклад|зразок|: -128 shr| 1=32704, що в двійковому вигляді|виді| виглядає так:

1111 1111 1000 0000 shl| 1=|

0111 1111  1100 0000 =32704

i + k

Арифметичне складання

3 (адитивні операції)

Цілі, речові

Тип результату – ‘старший тип’

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

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

i – k

Арифметичне віднімання

3

Цілі, речові

Тип результату – ‘старший тип’.

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

i or k

Порозрядне логічне ‘АБО’ (диз'юнкція, логічне складання)

3

Цілі, Boolean

Приклад|зразок|: 1023 or| –128= -1 що в двійковому представленні виглядає так:

   0000 0011  1111 1111 (1023)

or| 

   1111 1111  1000 0000  (-128)

=

   1111 1111  1111 1111   (-1)

i xor k

Порозряд-не логічне виключаю-че ‘АБО’ (нееквіва-лентність, складання по модулю 2)

3

Цілі, Boolean

Приклад|зразок|: 1023 xor| –128= - 897 що в двійковому вигляді|виді|  виглядає так:

   0000 0011  1111 1111 (1023)

xor| 

   1111 1111  1000 0000  (-128)

=

   1111 1100  0111 1111  (- 897)

i = k

Перевірка на рівність

4 (найнижчий пріори-тет)-

операції відно-шення (порів-няння)

Цілі, дійсні, символи, рядки

Тип результату – Boolean: якщо операнди рівні, то результат true, якщо не рівні, то false.

i<>k

Перевірка на нерівність

4

Цілі, дійсні, символи, рядки

Тип результату -  boolean: якщо операнди не рівні, то true, якщо операнди рівні, то  false

i<k

Перевірка на менше

4

Цілі, дійсні, символи, рядки

Тип результату -  boolean: якщо операнд i менше операнда  k, то результат true, інакше -false.

i<=k

Перевірка на менше і рівно

4

Цілі, дійсні, символи, рядки

Тип результату -  boolean: якщо операнд i менше або дорівнює операнду  k, то результат true, інакше -false.

i>k

Перевірка на більше

4

Цілі, дійсні, символи, рядки

Тип результату -  boolean: якщо операнд i більше операнда  k, то результат true, інакше -false.

i>=k

Перевірка на більше і рівно

4

Цілі, дійсні, символи, рядки

Тип результату – Boolean: якщо операнд i більше або дорівнює операнду  k, то результат true, інакше -false.

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

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

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

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

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

При описі змінних в секції var можна посилатися як на основних типів, так і на типів з секції type. Слід звернути увагу, що  в секції type транслятор  пам'ять не виділяє. Це не більше ніж ‘шаблон’, по якому в секції var виділяється пам'ять під декларовані змінні.  Найчастіше секція type використовується при описі структурованих даних, зокрема, записів.  Нижче, при ознайомленні із структурованими даними ми детально розглянемо використання секції  type.

У цьому розділі приведений|наводить| докладний опис основних типів загального|загального| вживання|застосування| - так званих простих типів.  Решта типів розглядається|розглядає| в подальших|наступних| розділах.

5.2. Цілі числа

Як видно    з приведеної на рис.5.1 класифікації, цілочисельні змінні і константи (shortint, byte, integer, word, longint) відносяться до простого порядкового типа. Це означає, що цілі типи мають кінцеве число значень, які можна упорядкувати за збільшенням і перенумерувати. До  них застосовна функція ORD(X), яка повертає порядковий номер значення виразу X. Для цілих типів ORD(X) повертає само значення X, тобто ORD(X)=X.

До порядкових типів можна також застосовувати функції:

PRED(X) – повертає попереднє значення порядкового типа:

                            ORD (PRED(X)) = ORD(X)-1;

SUCC(X) – повертає наступне значення порядкового типа:

                            ORD| (SUCC|(X)) = ORD|(X)+1.

Приклад|зразок| 5.1.:

var|

    i:shortint; {i- ціле коротке (-128..0..127)}

begin|

 i:=127;  {127-максимальне значення для типа shortint}

 writeln(PRED(i)); { вивід на екран числа ‘126’}

 inc(i); { процедура збільшення значення змінної  i на 1, виникає

                переповнення: i= -128! }

 writeln(SUCC(i)); { вивід на екран числа ‘-127’}

end|.

Як видно з прикладу, збільшення на одиницю граничного для даного типа значення дає число початку діапазону (в даному випадку  ‘-128’), т.е. услід за найбільшим для даного порядкового типа числом йде саме менше число.

Старший розряд цілих чисел типа shortint, integer, longint трактується як знаковий. Нуль в старшому розряді – число позитивне, одиниця – число негативне, причому негативні числа представлені в так званому додатковому коді. Щоб отримати негативне число, необхідно узяти таке ж по модулю позитивне число, інвертувати всі двійкові розряди і додати до отриманого одиницю. Наприклад, число мінус 1 отримуємо так: 00000001->11111110 +1=11111111=FF16, число мінус 2 отримуємо так:

0000001011111101+1=11111110=FE16 

мінімальне число мінус 128 отримуємо|одержуємо| так:

1000000001111111+1=10000000=8016.

Зворотне перетворення з додаткового коду в прямий код виконується по тому ж алгоритму: в негативного цілого числа інвертуються всі двійкові розряди і додається (не віднімається!) одиниця. Наприклад, маємо негативне число shortint: 1111 1110. Інвертуємо розряди і додаємо 1:  

0000 0001+1=0000 0010=2, тобто ми мали справу з числом ‘–2’ (див. вище).

Для беззнакових цілих чисел byte|, word| старший розряд трактується як звичайний|звичний| біт, тому у них верхня межа|межа| діапазону удвічі|вдвічі| більше, чим у|в|  shortint| та integer| відповідно, а нижня межа|межа| дорівнює нулю.

Початкуючі програмісти розгублюються|розгублюють| за ситуації, коли треба застосовувати знакові, а коли беззнакові типи. Правило просте: якщо змінна не може бути негативною|заперечною| – використовуй |тип| byte| або word|, інакше – shortint| або integer|. Для великих цілих чисел використовуй longint|.  Наприклад, номер місяця в році – byte|, табельний номер працівника – word|, температура повітря в повідомленні Гідрометцентру – shortint|, рівень води в річці|ріці| в порівнянні з ординаром| (середнім значенням) в сантиметрах  - integer|, річний фінансовий баланс підприємства в копійках – longint|.

До цілих типів допустимі  операції, приведені в Таблиці 5.1.

До цілих типів можна застосовувати процедури і функції, перераховані в Таблиці 5.2.

Таблиця 5.2.

Стандартні процедури і функції, застосовні до цілих типів

Звернення

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

(для функцій)

Дія

abs(x)

x

Повертає модуль x

char(b)

char

Повертає символ за його кодом b

dec (vi[,k])

-

Процедура. Збільшує цілочисельну змінну vi  на k одиниць, а за відсутності k – на одиницю (у квадратних дужках вказаний необов'язковий параметр)

inc (vi[,k])

-

Процедура. Зменшує цілочисельну змінну vi  на k одиниць, а за відсутності k – на одиницю (у квадратних дужках вказаний необов'язковий параметр)

hi(i)

byte

Повертає старший байт аргументу i

lo(i)

byte

Повертає молодший байт аргументу i

swap(i)

word

Міняє місцями байти в двубайтных цілих (word, integer)

odd(i)

boolean

Повертає TRUE, якщо аргумент i – непарне число

random(w)

word

Повертає псевдовипадкове ціле число, рівномірно розподілене в діапазоні [0…(w-1)]

sqr(x)

x

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

5.3. Числа з плаваючою комою (дійсний тип)

Числа з плаваючою комою (дійсний тип), як і цілі, відносяться до простого типа.

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

Характеристики різних форматів чисел з|із| плаваючою комою приведені в Табл.5.3.

Таблиця 5.3.

Довжина, байт

Назва формату

Кількість значущих цифр в десятковому уявленні

Діапазон десяткового ладу

4

single

7..8

-45..+38

6

real

11..12

-39..+38

8

double

15..16

-324..+308

10

extended

19..20

-4951..+4932

8

comp|

(надвеликі цілі числа для комерційних розрахунків)

19..20

(-263+1).. (263-1)

-9.2*1018..+9.2*1018 

Дійсне число в Турбо Паскалі занімає|позичає| від 4 (single|) до 10 (extended|) байт і має наступну|слідуючу| структуру в пам'яті ПК:

s

e

m

Тут s -  знаковий розряд числа

          e – двійковий порядок|порядок|   

          m-|  мантиса числа.

Мантиса m має довжину від 23 (single) до 63-х (extended) двійкових розрядів.

Операції над числами з|із| плаваючою комою виконуються схемно-| з використанням арифметичного співпроцесора, або, за відсутності такого, - з використанням підпрограм. В процесі запуску Турбо Паскаль перевіряє склад апаратних засобів і виявляє наявність або відсутність співпроцесора. При налаштуванні програмної|програмової| середи|середовища| рекомендуємо в налаштуваннях компілятора  у вікні “Numeric| processing|” указувати|вказувати| обидві ситуації – процесор сам вибере правильний варіант.

Відмітимо, що арифметичний співпроцесор завжди обробляє числа у форматі EXTENDED (10-байтное число). Найбільш універсальним форматом дійсних чисел, сумісним з Сі і іншими сучасними  МВР, є  формат DOUBLE (8-байтне дійсне). 

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

Таблиця 5.4.

Стандартні математичні функції Турбо Паскаля

Звернення

Тип параметра

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

Примітка

abs(x)

Цілий, дійсний

Тип аргументу

Модуль аргументу

arctan(x)

Дійсний

Дійсний

Арктангенс (значення в радіанах)

sin(x)

Дійсний

Дійсний

Синус, кут в радіанах

cos(x)

Дійсний

Дійсний

Косинус, кут в радіанах

exp(x)

Дійсний

Дійсний

Експонента ( ex)

ln(x)

Дійсний

Дійсний

Логарифм натуральний

frac(x)

Дійсний

Дійсний

Дробова частка числа x

int(x)

Дійсний

Дійсний

Ціла частка числа x

round (x)

Дійсний

LongInt

Ціле число, отримане з речового x округленням по правилах арифметики

trunk (x)

Дійсний

LongInt

Ціле число, отримане з речового x відкиданням дробової частки

pi

-

Дійсний

=3.1415926535897932.

random

-

Дійсний

Псевдовипадкове дійсне число, рівномірно розподілене в діапазоні [0..0.9999.]

random(x)

Цілий

Цілий

Псевдовипадкове ціле число, рівномірно розподілене в діапазоні [0.. (x-1)]

randomize

-

-

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

sqr(x)

Дійсний

Дійсний

Квадрат аргументу

sqrt(x)

Дійсний

Дійсний

Корінь квадратний від x

Нажаль, Паскаль не має вбудованої функції z=xy (x і y – дійсні змінні), яка досить часто використовується в науково-технічних розрахунках.. Значення z можна обчислити, використовуючи техніку логарифмування/потенціювання. Дійсно, логарифмуючи вираз z=xy, отримаємо: ln(z)=y*ln(x). Потенціюючи останній вираз, отримаємо:

z=ey*ln(x)=exp(y*ln(x)).

Формула справедлива при x>0| і довільному y|в|, тому перед обчисленням|підрахунком| по ній необхідно перевірити позитивність аргументу x.

5.4. Логічний тип

Логічний тип (булевий - англ., boolean, по імені англійського математика Д.Буля) відноситься до типу порядкових і може набувати тільки 2 значення:  TRUE (істина) або FALSE (неправда). При цьому :

 Ord|(False|)= 0

Ord|(True|)= 1

Succ|(False|)= True|

Pred|(True|)= False|

False| < True|

Тип boolean  виникає при виконанні операцій порівняння величин двох змінних для подальшого розгалуження програми по декількох напрямах.

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

Значеннями символьного типу є множина всіх символів ПК. Кожному символу приписується ціле число в діапазоні 0..255. Це число служить кодом внутрішнього представлення символу. На відміну від ‘демократичного’ Сі в строгішій мові Паскаль  код символу і символ мають різні типи, і тому між цілими числами і символами недопустимі прямі операції привласнення, порівняння і арифметичних дій.  Для обходу цієї заборони використовуються спеціальні функції – вже відома вам ORD (перетворення символу в код) і CHR (перетворення коду в символ).

Приклад|зразок| 5.2.:

var|

 c|із|: char| ;

i,j|: integer| ;

begin          {після ключового слова begin  крапка з комою (;)  не ставиться}

 c:=’0’;             { у символьну змінну c  помістили символ ‘0’}   

j:=ORD(c);      { отримання коду символу, що знаходиться в c (48)

                               і занесення його в цілочисельну змінну j}

 i:= j+2;                { операція  складання двох цілих чисел, i=48+2=50}

 writeln(CHR(i)); { вивід на екран символу з кодом 50,тобто  ‘ 2’

end|.

Для кодування символів використовується Таблиця коду ASCII (Amirican Standard Code for Information Interchange– з кодами символів 0..127), що був доповнений символами русифікации і т.з. псевдографіки (друга половина таблиці з кодами символів 128..255). Коди 0..32 – це т.з. символи, що управляють. Вони використовуються для управління процесом передачі символів, що відображуються (коди 33..255). Оскільки спочатку таблиця ASCII розроблялася для апаратури передачі даних, не всі її символи, що управляють, використовуються в програмуванні. У Таблиці 5.5. приведені найбільш важливі кодування символів, що управляють, з якими при програмуванні доводиться часто стикатися.

Таблиця 5.5.

Код

Ім'я

символу

Значення

10-ичн.

16-ричн.

7

07

BEL

Дзвінок. Вивід на екран цього символу супроводиться звуковим сигналом без переміщення курсору.

9

09

HT

Горизонтальна табуляція. При виводі зміщує курсор на екрані на 8 позицій праворуч.

10

0A

LF

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

11

0B

VT

Вертикальна табуляція. При виводі на екран замінюється спеціальним знаком.

12

0C

FF

Прогін до кінця сторінки на принтері. При виводі на екран замінюється спеціальним знаком.

13

0D

CR

Повернення каретки. Вводиться натисненням на клавішу Enter. При цьому генеруються 2 символи: CR і LF (1310,1010). При виведенні CR на екран подальші символи виводяться з першої позиції того ж рядка. При виводі на дисплей або принтер пари кодів CR,LF подальші символи виводяться з першої позиції нового рядка

26

1A

SUB|

(EOF)

Кінець файлу (EOF – end of file). Вводиться з клавіатури натисненням Ctrl+Z. При виводі на екран замінюється спеціальним знаком. При виведенні файлу на диск додається у файл після виконання процедури закриття файлу - CLOSE.

27

1B

ESC

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

На рис.5.2. роздрукована кодова  DOS-таблиця для всіх символів, що відображуються, а також для символів, що управляють, змінюють відображення на екрані дисплея. Роздрук складається з полів структури: <десятковий код>=<відображення символу>;<пробіл>.

Рис.5.2.

Звернемо увагу, що вивід|виведення| на екран коду 10 (LF|) викликав|спричиняв| просування|переказ| рядка без зміни позиції в рядку, і код 11 роздрукувався|друкував| на рядок нижче. Аналогічно, код 13 (CR|) викликав|спричиняв| перехід на початок поточного рядка, де і були роздруковані|друкувати| символи з|із| кодами 26 (EOF|) і 27 (ESC|).

5.6. Символьний рядок (тип STRING[N])  

Символьний рядок – основний тип, спеціально пристосований для обробки символьних даних, це послідовність (одновимірний масив) символів з можливістю зміни довжини рядка від 0 до N безпосередньо в процесі роботи програми.  Значення N  не повинне перевищувати 255, що цілком достатньо для більшості застосувань. Якщо в оголошенні рядка параметр [N] не вказаний, то транслятор за умовчанням приймає максимальну довжину N=255.

На відміну від символу рядок не є|з'являється| порядковим типом, тобто до нього, як до цілісної|суцільної| конструкції, не застосовні функції ORD|, SUCC|, PRED|, проте|однак| вони застосовні до його окремого елементу – символу.  До будь-якого символу в рядку можна звернутися|обертатися| точно так, як і  до елемента одновимірного|одномірного| масиву при цьому індекс (номер) елементу указується|вказує| в квадратних дужках. Наприклад:

var|

 Name:string[25];

 L: byte|;

begin| 

Name :=’Шевченко А.’;

Writeln (Name[1], Name[9],Name[10]); { Роздрукується: Ш А -  перший  

                        символ (‘ Ш’), 9-й    символ (пропуск|прогалина|), 10-й символ (‘А’|)}

L:=| ord| (Name|[0]); {L=11|}

end|.

В даному прикладі рядковій змінній Name транслятор виділяє 26 байт: Name[0],Name[1]...,Name[25]. У байт з нульовим індексом Name[0] заноситься фактична довжина символьного рядка, в нашому прикладі - число 1110 (довжина символьної константи ‘Шевченка А.’):

Name

Індекс

ел-та в рядку

[0]

[1]

[2]

[3]

[4]

[5]

[6]

[7]

[8]

[9]

[10]

[11]

[12]

...

[25]

Значення

11

‘Ш’

‘е’

‘в’

‘ч’

‘е’

‘н’

‘к’

‘о’

‘  ’

‘А’

‘.’

0

...

0

Щоб|аби| дізнатися|взнавати| поточну довжину рядка Name|, необхідно звернутися|обертатися| до елементу Name|[0] не як до символу, а як до числа типа|типу| byte|, використовуючи вже відому нам функцію  ord| ( ):

L:=ord| (Name|[0]);

Поширеніший варіант отримання|здобуття| поточної довжини рядка – за допомогою функції LENGTH| ( ):

L:=| length| (name|);

Символьний рядок має розвинену систему операцій, процедур і функцій.

До рядків можна застосовувати операцію конкатенації (зчеплення)  “+”|:

Name:=Name+’-футболист|’; {Name=’Шевченко| А.-футболист’}

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

При роботі з рядками дуже ефективна також операція присвоєння (‘:=’), яка одним оператором забезпечує пересилку великих масивів символів.

До рядків застосовні процедури і функції, наведені в Таблиці 5.6.:

Таблиця 5.6.

Звернення

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

Дії

CONCAT (S1,S2[,S3.])

STRING

Функція-еквівалент операції зчеплення: S1+S2+......

COPY(ST, INDEX, COUT)

STRING

Функція копіює  з рядка ST COUT символів, починаючи з символу з номером INDEX. Використовується в програмах редагуванні символьних текстів

DELETE(ST,INDEX,COUT)

STRING

Процедура. Видаляє COUT символів з рядка ST, починаючи з символу з номером INDEX . Використовується в програмах редагуванні символьних текстів

INSERT(SUBST,ST,INDEX)

STRING

Процедура. Вставляє підрядок SUBST в рядок ST, починаючи з символу з номером INDEX. Використовується в програмах редагуванні символьних текстів

LENGTH (ST)

INTEGER

Функція повертає довжину| рядка ST|. Використовується в програмах редагування символьних текстів

POS (SUBST, ST)

INTEGER

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

STR(X[:WIDTH[:DECIMALS]],ST)

STRING

Процедура. Перетворить число X речового або цілого типа|типу| в рядок символів ST|; WIDTH| і  DECIMALS|, якщо вони присутні, то задають відповідно загальну|загальну| ширину поля числа, що виводиться, і (для дійсних чисел) кількість розрядів дробової частини|частини|. Якщо поля WIDTH| і DECIMALS| відсутні, то дійсне число представляється  в експоненціальному форматі( ч.ччччЕчч).

Широко використовується в графічному режимі для виведення числових  даних в графічні вікна

VAL (ST,  X,  CODE)

INTEGER, REAL

Процедура. Перетворить рядок символів ST| у внутрішнє представлення цілої або дійсної змінної X, яке визначається типом цієї змінної; параметр CODE| містить|утримує| нуль, якщо перетворення виконане|проходило| успішно, інакше вміст X не міняється, а CODE| містить|утримує| номер позиції в рядку ST|, де виявлений помилковий (неприпустимий|недопустимий| для числового уявлення|вистави|) символ. У рядку ST| можуть бути провідні пропуски|прогалини|, але|та| задні|відомі| пропуски|прогалини| недопустимі. Для дійсних чисел допустимо як експоненціальне  уявлення|вистава|, так і представлення|вистава| з|із| фіксованою крапкою|точкою|.

Використовується рідко, оскільки консольне введення зручніше реалізувати за допомогою READLN ( )

UPCASE(ch)

CHAR

Функція перетворить рядковий символ ch  латинського алфавіту в заголовний. Решта всіх символів, у тому числі – символи кирилиці, повертається без зміни. У російськомовних застосуваннях практично не використовується.

Операції відношення “=,<>,>,<,>=,<=” виконуються над двома рядками посимвольно зліва направо з врахуванням старшинства коду символів. Якщо один рядок коротший, то рядки автоматично вирівнюються по довжині за рахунок доповнення справа короткого рядка байтами з нульовим кодом. Операції відношення у поєднанні з процедурами COPY, DELETE і оператором привласнення (‘:=’) дуже зручні при сортуванні символьних рядків, оскільки при їх використанні програма працює з рядками як з цілісними об'єктами.

5.7. Тип-діапазон

Тип-діапазон є підмножина свого базового порядкового типу. Він  задається межами своїх значень усередині базового типу:

<мин.знач>..<макс.знач>

Наприклад:

type| 

    digit| =’0’..’9’;

    codedig| = 48..52;

var|

    date| :1..31;

    cifra|: digit|;

 kodcif|: codedig|;

 latsym|: ‘A’|..’z’; {latsym| – символьна змінна з|із| обмеженим діапазоном кодів             

                                            символів}

begin|

..

end|.

Як видно з прикладу, тип-діапазон необов'язково описувати в секції шаблонів TYPE, його можна указувати безпосередньо в секції VAR - резервування пам'яті під змінні. Основне призначення типа-діапазону – суворіший контроль змінних відповідного типа. Наприклад, якщо ми в тілі програми-прикладу використовуємо таких операторів:

date:=31|;

inc|(date|);

то при  включеному контролі options\compiler\runtime errors (див. Розділ 4)  виникне помилка періоду виконання: ‘Error 201: Range check error.’, що вказує на оператор інкремента, який виводить змінну date за межі допустимого діапазону.

5.8. Рідко використовувані типи 

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

type

       Colors=|(red|, green|, blue|, white|, black|);

var  c1,c2,c3: Colors;

begin|

 c1:=red|;

 c2:=green|;

 c3:=blue|;

end|.

Відповідність між значеннями перераховуваного типа|типу| і порядковими номерами цих значень, встановлюється порядком|порядком| перерахування|переліку|:  перше значення в списку отримує|одержує| порядковий номер 0, друге – 1 і так далі Максимальна кількість можливих значень перераховуваного типа|типу| складає 65536 значень.

У наведеному вище прикладі|зразку| ord| (red|)=0,.,ord| (black|)=4.

На практиці перераховуваний тип використовується украй рідко. По суті, перераховуваний тип – це список іменованих констант натурального ряду чисел 0,1,2,...

Будь-який МВР, у тому числі Паскаль, не може програмно виводити на пристрій відображення (дисплей, принтер) імена змінних, оскільки ім'я змінної або константи використовується тільки транслятором і лише для ‘внутрішнього вживання’- заміни в машинній команді імені його адресою. Оскільки перераховуваний тип – це список іменованих констант, роздрукувати яке-небудь ім'я із списку перерахування (red, black і тому подібне) з нашого прикладу командою writeln не удасться.  Єдиною можливістю виведення таких імен є обчислення порядкового номера цього імені за допомогою функції ORD( ) і роздрук з масиву рядків рядка-найменування з відповідним індексом (див. нижче Приклад 5.3.).

5.9. Константи

Константи можуть входити у вирази в правій частині операторів привласнення, використовуватися в операціях порівняння, а також використовуватися як фактичні параметри при виклику процедур і функцій.   Як константи в Тубо Паскалі можуть використовуватися цілі десяткові і шістнадцяткові числа, дійсні  числа, символи, рядки символів, конструктори множин (див. розділ 6). У Паскалі є також дві логічні константи (true і false) і одна адресна константа NIL. Останню привласнюють покажчику (див. розділ 10), ще не ‘зарядженому’ конкретною адресою.

Цілі десяткові числа-константи можуть мати значення -2147483648 до 2147483647 (4 байти). Цілі числа, що виходять за цей діапазон, доводиться записувати у вигляді дійсного числа з десятковою крапкою, наприклад, 3000000000. або так 3000000000.0.

Шістнадцяткові числа-константи складаються з шістнадцяткових цифр, яким передує знак долара, наприклад $3F або $f0000008. Діапазон допустимих шістнадцяткових чисел – від $00000000 до $FFFFFFFF. Як і в десятковому уявленні, передуючі (крайні ліві) нулі при записі константи можна опускати.

Дійсні числа-константи записуються із знаком або без нього з використанням десяткової крапки і/або експоненти. Експоненціальне представлення крім цифр включає латинський символ e або E, за яким слідує знак порядку і десятковий порядок, наприклад, 3141.5e-3 відповідає числу 3.1415;  -17E2  відповідає числу мінус 1700.

Символьна константа – це будь-який символ ASCII в апострофах, наприклад, ‘z’, ‘Ф’. Для запису символу апострофа він подвоюється: ‘’’’.

Допускається запис символу-константи вказівкою його внутрішнього коду, якому передує символ # (символ ‘дієз’). Приклади:

#10 – LF (просування рядка)

#13 – CR (повернення каретки)

#36 – ‘$’| (знак долара)

#65 – ‘A’| (символ латинської прописної букви|літери| ‘A’|)

#128- ‘А’|(символ кирилиці прописної букви|літери| ‘A’|)

#239- ‘я’| (символ кирилиці рядкової букви|літери| ‘я’|)

#179 і далі –символи| для малювання рамки документа.

Форма запису символьної константи через дієз вимушено використовується в командах write|(), writeln|()  при програмному формуванні рамки документа, оскільки немає іншого способу.

     5.10. Комплексний приклад на дії з простими типами 

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

Приклад|зразок| 5.3:

Program TestOrd;{Тестування операцій із змінними простого типа}

uses crt;

type colors = (red, blue, green, white, black); {Шаблон для перераховуваного типа}

var|

 rgb : colors;  {rgb – змінна перераховуваного типа colors}

 i : shortint;   {i- однобайтна змінна цілого типа з діапазоном –128..+127}

 j : integer;    {j- двубайтная змінна цілого типа з діапазоном –32768..+32767}

 у,n : boolean;{однобайтні змінні логічного типа}

 s1,s2 : char;  {однобайтні змінні - символи}

 date:1..31;     {однобайтна змінна цілого тип-діапазон}

 alflat:'A'..'z';   {символ з діапазону латинських букв}

 alfrus:'А'..'я';  {символ з діапазону російських букв}

 st1,st2 : string[15];   {символьні рядки завдовжки до 15 символов-байт}

const e:extended=pi;{e-дійсна константа, що типізується ( ініційована почат-

ковим значенням змінна) завдовжки 8 байт,pi-|вбудована константа= 3.1415…}

namclr: array[0..4] of string[15] = ('red','blue','green','white','black');{масив

                                                                                               рядків-констант}

begin        clrscr; {очищення екрану }

writeln|('Приклад|зразок| впорядкування цілих чисел shortint| на числовій осі: ');       

                                               {виведення повідомлення  на екран}

i:=127|; {01111111}

write| ('i=',i|, 'pred|(i)=',pred(i) '); {126}

{writeln|('succ|(127)=',succ(i));}   {-128} {Run-time| error|: range| check| error|! Ф-ія

                  succ|  виводить i за межі|межі| діапазону!}

inc|(i);  {i= -128=10000000|, інкремент дозволяє здолати|подолати| кордон|межу| діапазону!}

j:=1023|;

write|('   i=',i|'  ');  {-128}

writeln|('succ|(-128)=',succ(i));{-127. Наступне|слідуюче| за -128 значення  на числовій 

                                                            осі}

writeln('Приклади логічних операцій and, or, xor'); {виведення повідомлення

                                                                                          на екран}

writeln|('над числами 1023 і -128: 0000 0011  1111 1111=1023'); {виведення

                                                                                  повідомлення на екран}

writeln|('                                          1111 1111  1000 0000=-128 '); {виведення

                                                                                   повідомлення  на екран}

writeln('and=',j and i',                     0000 0011  1000 0000=512+256+128=896');

                                                                              {виведення даних на екран}

writeln('or=',j or i',                          1111 1111  1111 1111=-1'); {виведення даних

                                                                                                       на екран}

writeln('xor=',j xor i',           1111 1100  0111 1111=-(0000 0011 1000 0000+1)');        

                                                                                    {виведення даних на екран}

WRITELN|('                             = -(512+256+128+1)=-897 '); {виведення

                                                                            повідомлення на  екран}

write|('Приклади|зразки| операцій зсувів|зсуву|: '); {виведення повідомлення на екран}

write( '-128 shl 1=',i SHL 1'    '); {-256. Виведення даних на екран}

j:=$ff80 shr 1;

writeln('-128 shr 1=',i shr 1); {+32704. Виведення даних на екран}

write|('Приклад|зразок| дійсного ділення|поділки| цілих: '); {виведення повідомлення на екран}

writeln('32704/-256’,j/ i); {виведення даних на екран}

write|('Приклад|зразок| порівняння символів:');

s1:='1|';

s2:='2|';

writeln('''1''<''2''=',s1<s2); {виведення даних на екран}

write|('Приклад|зразок| порівняння чисел:');

writeln('((1<2) AND (3.14>2))=',(1<2) AND (3.14>2)); {виведення даних на

                                                                                             екран}

write |('Приклад|зразок| аналізу на непарне число:');

writeln(' odd(1)=',odd(1)not odd(1)=', not odd(1)); {виведення даних на екран}

write |('Приклад|зразок| операцій з|із| булевими змінними:');

y:=true;

n:= not y;

writeln| ('true=',ord|'(y), false=',ord|(n)); {виведення даних на екран}

write|('Тип|тип|-діапазон цілого:');

date:=31|;

{ inc(date);}{ Помилка!: інкремент виводить змінну date

             за дозволений для неї діапазон. Тому оператор закоментовано}

writeln|('date=',date|); {Виведення даних на екран:  date=31|}

 for i:=0 to 57 do

 begin|

  alflat:=chr|(ord|('A'|)+i);{формування в alflat| чергового символу латинського алфавіту}

  write|(alflat|); {виведення символу на екран}

 end|;

writeln|(' - латинський алфавіт');

for i:=0 to 47 do

 begin|

  alfrus:=chr|(ord|('А'|)+i);{формування в alfrus| чергового символу киририці}

  write|(alfrus|);

 end|;

 for i:=0 to 15 do

 begin|

  alfrus:=chr|(ord|('р'|)+i);{формування в alfrus| чергового символу кирилиці}

  write|(alfrus|); {виведення символу на екран}

 end|;

writeln|(' - рус.алфавит');

writeln|('Приклад|зразок|  дійсного числа extended|:');

writeln|(e,e:26:24|); {Виведення  дійсного числа ( у експоненціальному

                                форматі і в форматі фіксованої коми з|із| великим числом

                                знаків (24) після|потім| десяткової  крапки|точки|}

writeln|('Приклад|зразок| виведення імені члена ''white'|' перерахування|переліку| colors|: ';  

 namclr|[ord|(white|)]);

 readln|;

end|.

Результати роботи програми TestOrd| приведені на рис.5.3.

Рис.5.3.

Контрольні запитання:

  1.  Назвіть всі прості типи даних,  що підтримуються Паскалем.
  2.  Операції в Паскалі, пріоритет операцій.
  3.  Приведення типів при  виконанні арифметичних операцій.Що таке старший тип’?
  4.  Числова вісь цілих чисел. Що йде за самим великим цілим числом, якщо додати до нього +1?
  5.  Представлення відємних цілих в додатковому коді. Алгоритм здобуття відємного двійкового числа.
  6.  В яких випадках користуватися тим, чи іншим типом цілого.
  7.  Стандартні процедури і функції, застосовані до цілих типів.
  8.  Формати дійсних чисел в Паскалі. Їх двійкове представлення.
  9.  Стандартні математичні функції. Як на Паскалі обчислити для дійсних  x,y значення z=xy?
  10.  Логічний тип, коли він виникає і де використовується?
  11.  Що таке таблиця ASCII? Структура таблиці. Що таке управляючі символи?
  12.  Символьний рядок, його структура. Процедури і функції для обробки символьних рядків.
  13.  Навіщо в Паскалі введений тип-діапазон? 
  14.  Що таке перераховуваний тип?
  15.  Константи в Паскалі.
  16.  Прокоментувати програму Прикладу 5.3.

Завдання для самостійної роботи 

1. На основі завдання самостійної роботи розділу 4 (вправа 4.1)  модернізувати програму обчислення факторіалу для якомога більшого значення n.


Розділ 6. Структуровані типи

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

6.1. Масиви

Масиви складаються з  елементів одного типу (простого або структурованого). Для опису масивів використовується ключове слово array. Доступ до компонента масиву задається його порядковим номером. Розглянемо приклад.

Приклад|зразок| 6.1:

const Month : array[1..12] of string=('Jan','Feb','Mart','Apr','May', 'June',

                   'July','Aug','Sept','Oct','Nov','Dec|');{масив символьних рядків-

                                                                                                          констант}

         N=24|; {константа для управління довжиною символьного масиву}

type|

     TMonth=array[1..12] of string; { тип-масив   з 12-ти елементів-рядків

                                                                    завдовжки  до 255 байт кожний}

var  i:byte;

       mon| : TMonth|; {mon-| змінна-масив типа|типу| TMonth|}

       mch : array[0..N] of char; {(n+1)-мірний масив символів}

begin|

clrscr|;  {очищення екрану}

for i:=1 to 12 do  { заповнення масиву  mon і   вивід на дисплей назв місяців}

begin| 

  mon|[i]:=Month[i];

  write| (mon|'[i] ');

 end;

for i:=0 to N do mch[i]:=‘ ‘;{очищення пропусками символьного масиву mch}

end|.

У наведеному вище прикладі показаний спосіб завдання масиву констант - Month і масиву змінних - mon. Процедура write() у циклі послідовно в одному рядку роздруковує через пропуск назви місяців. Останній цикл for чистить пропусками (n+1)- мірний символьний масив.

Масиви бувають одновимірні|одномірні| (вектори), двовимірні (матриці), тривимірні|трьохмірні| (тензори) і так далі. Для задання масиву використовується ключове слово array, розмірність масиву вказується у квадратних дужках, тип елементів масиву вказується в кінці опису після ключового слова of . Якщо масив багатовимірний, то діапазони індексів по кожному виміру відокремлюються один від одного комою. В квадратних дужках першим іде діапазон старшого індекса, що змінюється найбільш повільно, останнім – діапазон молодшого індекса, що змінюється найбільш швидко. Діапазони зміни  індексів вказуються як обмежений перераховуваний тип-діапазон.

Приклад|зразок| 6.2:

uses crt;

var|

vector: array[0..10] of integer;     {одновимірний масив – вектор}

matr:   array[1..3,1..4] of real;       {двовимірний масив – матриця}

matr3: array[1..3,1..4,1..5] of byte;тривимірний массив- тривимірна матриця}

i,j,k : byte; { робочі адресні індекси для масивів}

begin|

clrscr|;

 for i:=0 to 10 do {цикл, що повторюється 11 разів: 0,1..,10}

begin|

vector|[i]:=i; {заповнення в циклі масиву vector|  числами натурального

                                                                                                                      ряду|низки|}

    write|(vector|[i]:5); { роздрук|роздруківка| в циклі  по одному компоненту vector| з|із| кроком

                                                                                                                       5 симв|.}

end|;

writeln|; {перехід на новий рядок}

writeln|; {ще одна нов.строка - утворився 1 пробільний рядок}

for i:=1 to 3 do { зовнішній цикл - по рядках матриці}

begin|

for j:=1 to 4 do { внутрішній цикл-по елементам одного рядка (стовпцям) матр.}

 begin|

matr|[i,j|]:=j+4*(i-1|);{порядкові числа у форматі плав.запятой}

write|(matr|[i,j|]:8:4);{друк|печатка| рядка чисел через 8 позицій з|із| 4 знаками після|потім| коми}

end; {j}

writeln|;    {перехід на новий рядок }              

end; {i}

writeln|; {пробільний рядок, що відокремлює|відділяє| двовимірну матрицю від тривимірної|трьохмірної|}

for i:=1 to 3 do { самий зовнішній цикл - по шарах матриці}

begin|

 for j:=1 to 4 do { цикл по рядках шаруючи матриці.}

begin|

        for k:=1 to 5 do { самий внутрішній цикл- по елементах одного рядка шарую чи        матриці}

        begin|

   matr3|[i,j,k|]:=k+5*((j-1|)+4*(i-1|));{цілі числа з|із| порядковими номерами

              елементів      matr3|}

   write|(matr3|[i,j,k|]:4); {роздрук|роздруківка| елементу матриці з|із| кроком 4}

 end; {k}

  writeln|;   {перехід на новий рядок матриці-| шару}              

 end; {j}

writeln|; {пробільний рядок, що відокремлює|відділяє|  двовимірні  шари-матриці один від одного}

end|; {i}

readln|;

end|.

На рис.6.1 приведений результат роботи програми. У першому рядку – роздрук|роздруківка| одновимірного|одномірного| масиву, далі роздрукована|друкувати| матриця 3х4, далі роздруковано|друкувати| 3 матриці-шари тривимірної|трьохмірної| матриці 3х4х5, кожен шар - матриця розмірності 4х5.

Рис.6.1.

Як видно|показний| з|із| прикладу|зразка|, доступ до i-го| елемента масиву vector| виглядає так: vector|[i], доступ до j-го| елементу i-ого| рядка матриці matr| виглядає так: matr|[i,j|], тобто індексація елементів матриці виконується за правилом:

<имя_матриці|>[ <індекс рядка>,<індекс| стовпця>]  

Елементи  к-мірної| матриці розташовуються в ПОП так, що спочатку змінюється молодший індекс (найправіший), потім більш старший, і останнім змінюється самий старший (найлівіший) індекс. Для тривимірної|трьохмірної| матриці matr3| з|із| попереднього прикладу|зразка| це виглядатиме так:

matr3|[1,1,1],matr3|[1,1,2]…, matr3|[1,1,5],matr3|[1,2,1]…, matr3|[1,4,5],  

matr3|[2,1,1],matr3|[2,1,2]…,matr3[2,4,5],matr3|[3,1,1]…, matr3|[3,4,5].

У всіх трьох роздруках|роздруківках| в елементи масиву поміщені для наочності|наглядний| числа, відповідні порядковому номеру елементу масиву в ПОП.

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

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

Приклад 6.3.

Program vector;

Uses crt; {підключення бібліотеки, де є процедури clrscr та readln}

const n=7;                                         {кількість елементів вектору}

var vec:array[1..n] of integer;           {вектор-рядок цілих чисел}

   i,s,vmin,vmax:integer;  {змінна циклу, сума елементів вектору, граничні               

                                           значення}

 begin

   clrscr;{очищення екрану}

   writeln('S - summa of elements of  ',n,'-dimension vector');

   writeln('Vmin, Vmax - min and max elements of  ',n,'-dimension vector');

   s:=0;vmin:=32767;vmax:=-32768;{ініціалізація змінних. Зверніть увагу,

             що vmin ініціюється     найбільшим числом, а vmax -найменшим}

   for i:=1 to n do

     begin

       writeln('Input ',i,' number:'); {запрошення до вводу з клавіатури  

                                                        чергового  елементу}

       readln(vec[i]);             {читання його в масив vec}

       s:=s+vec[i];                 {накопичення суми елементів вектору}

       if vec[i]<vmin then vmin:=vec[i]; {аналіз та встановлення значення

                                                                мінімального елементу}

       if vec[i]>vmax then vmax:=vec[i];{аналіз та встановлення значення

                                                             максимального елементу}

     end;

     writeln('s=',s,' vmin=',vmin,' vmax=',vmax);{вівід результатів}

     readln;{призупинка виконання програми}

 end.

Обробка даних  матриці. Треба обчислити матрицю C[m,n] - добуток матриць A[m,q] i B[q,n]:

C=A*B.

В матриці С  знайти найбільший елемент cmax.

Елемент i-го рядка, j-го стовпчика  результуючої матриці С обраховується за формулою:

Приклад 6.4.

Program matr;

uses CRT;

const m=3;{число рядків в А}

     q=2;{число стовпчиків в А та рядків в В}

     n=4;{число стовпчиків в В}

var A:array[1..m,1..q] of real;{}

   B:array[1..q,1..n] of real;{}

   C:array[1..m,1..n] of real;{}

   i,j,k:integer; {індекси в масивах матриць, що перемножуються}

   cmax:real; {максимальне значення в матриці С}

Begin

  clrscr;{очищення екрану}

  randomize;{випадковий початок випадкової послідовності генератора

                     випадкових чисел}

   cmax:= -1e+06;  {ініціалізація; зверніть увагу – для пошуку найбільшого

                                числа cmax проініційоване великим від’ємним числом}

{заповнення матриці А випадковими числами з діапазону ± 5.00}

 for i:=1 to m do

  for k:=1 to q do a[i,k]:=random(100)*0.1-5.0; {}

{заповнення матриці В}

 for k:=1 to q do

  for j:=1 to n do b[k,j]:=j;

 {Обчислення С=А*В}

 for i:=1 to m do   {зовнішній цикл по рядках С}

  begin

   for j:=1 to n do  {цикл по стовпчиках С}

     begin 

        c[i,j]:=0; {підготовка до сумування в c[i,j]}

        for k:=1 to q do c[i,j]:=c[i,j]+a[i,k]*b[k,j]; {внутрішній цикл

      обчислення елемента c[i,j] – підсумовування додатків a[i,k]*b[k,j]}

       end ; {кінець циклу по j}

   end;{кінець циклу по i }

 {Роздруківка С та пошук cmax}

  for i:=1 to m do

   begin for j:=1 to n do

    begin

     write(c[i,j]:7:2);  {друк одного рядка С}

     if cmax<c[i,j] then cmax:=c[i,j]; {аналіз чергового елементу С на

                                                          максимальне значення}

    end;{j}

    writeln; {друк рядка С закінчено, далі-друк з нового рядка}

   end; {i}

   writeln('cmax=',cmax:7:2); {перехід на новий рядок  друку С}

   readln;

End.

На рис.6.2. відображені можливі результати виконання цієї програми
                       Рис.6.2.

6.2. Записи  

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

Структура оголошення типа запису :

TYPE

<им’я_типу>=RECORD

                     <список полів>  

                       END;  |

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

type|

  TWorker=record {шаблон для записів типа TWorker}

                 FIO|  :string[24];{ФІО – до 24 символів, включаючи пропуски|прогалини|}

                Deprt| :byte;        {номер відділу – позитивне число<=255|}

                   TN| :word;        {табельний номер – позитивне число<=65535|}

               Salary| :real;         {оклад – число з|із| плаваючою комою}

                   end|;

var|    

  worker|: Tworker|;  {виділення пам'яті під змінну-запис типа|типу| TWorker|}

        dep|: array|[1..200] of| Tworker|; {Виділення пам'яті під масив записів типу|типу|      

                                                             TWorker|}

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

Ця структура (шаблон) використовується при виділенні пам'яті під змінну типа|типу| record| - (worker|) і під масив таких структур (dep|). Останній може заповнюватися даними із зовнішнього носія (дискета, жорсткий диск) і використовуватися для формування платіжної відомості підрозділу.

До кожного компоненту запису можна дістати доступ, використовуючи складене имя-        <им’я_змінної>.<им’я_поля>.   

Приклад:

worker|.deprt:=21;  {формуємо поля робочого запису worker|}

worker|.tn:=2753;

worker|.fio:=’Иванов Іван Іванович’;  

worker|.salary:=2504.75;

dep|[15].fio:=’Петренко Петро Петрович’; {формуємо поле fio| в 15-му записі масиву dep|}

dep|[1]:=worker; {скопіювали сформовану в worker| запис в 1-й запис масиву dep|}

Якщо доводиться багато разів звертатися до різних полів одного запису, то зручно використовувати оператора приєднання  WITH, який не вимагає указувати ім'я запису в кожному операторові:

WITH <змінна> DO <оператор>;

Наведений вище приклад|зразок| можна записати так:

With worker do

begin| 

 deprt:=21|;

 tn| :=2753;

....

 salary:=2504.75;

end|;

Як зазначено вище, поля запису можуть, у свою чергу|в свою чергу|, бути масивами або  записами. У останньому випадку складене|складове| ім'я матиме два  і більш  полів, розділені крапками|точками|.

Наприклад:

type|

BirthDay=record

  Day,month| : byte|;

            Year| : word|;

                        end;{record}

var|

rab: record {Зверніть увагу: у секції var  також можна  описувати тип (без   

             використання секції type), якщо  змінна цього типу одна, тобто не  

             потребується багатократного вживання шаблону}      

          name : string;    

                   bd : BirthDay;{поле rab.bd  само є записом вказаного вище типу

                                                                                                                 BirthDay}

       end; {record rab}  

Begin|

.....

if rab.bd.year=1988 then .. { звернення до поля bd запису rab; поле bd само є

                                              записом і в цьому записі звертаємося до поля year }

end|.

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

Розглянемо ще один дуже корисний різновид запису – т.з. запис з варіантами.

Інколи|іноді| необхідно  одну і ту ж область ПОП розглядати|розглядати| як один або інший тип даних. Наприклад, чотирибайтну змінну типу|типу| longint|  розглядати|розглядати|  як дві двубайтні|  змінні типа|типу| word| або як чотири окремі байти.

Приклад|зразок| 6.5 :

var|

 mem4: record

        Case byte of

0: (bt|:   array|[0..3] of| byte|);

1: (wd|: array|[0..1] of| word|);

2: (li|:     longInteger|);

            end; {record}

x  : word|;

by|: byte|;

lo| : longInteger|;

Поєднання ключових слів record Case … of і рядки, що йдуть далі з мітками (у прикладі це 0:, 1:, 2:) – ознака запису з варіантами. У конструкції  Case byte of  на місці типа управляючої змінної ‘byte’ можна указувати будь-якого іншого перераховуваного типа (char, integer, word). Відповідно, мітки мають бути цього типа. Значення міток і тип змінної, що управляє, тут не мають ніякого значення (пробачте за тавтологію).

В даному прикладі запис mem4| має 3 варіанти, що займають|позичають| в ПОП одну і ту ж ділянку пам'яті завдовжки 4 байти. Залежно від того, до якого поля запису ми звертаємося|обертаємося| в програмі, ця ділянка може розглядатися|розглядати| як масив з|із| 4-х байт, або масив з|із| двох слів, або як одне ціле число типа|типу| LongInt|. Продовжимо написання тіла програми (продовження Прикладу 6.5):

begin|

write| (‘x=|’);    {‘Запрошення’ до введення x}

readln| (x);       {Введення x}

with mem4 do{ оператор приєднання}

begin|

  li:=x*x|;                 {сформували  число і записали його в mem4|.li типа|типу|  longInteger|}

  if wd[1]=0 then   { число уміщалося в байт або слово}

         if bt[1]=0 then by:=bt[0]   { число <256 і вміщається в один байт }

                         else  x:=wd[0]   { інакше – поміщаємо його в word}

                   else lo:=li;               { число не вміщалося в word, поміщаємо його в longinteger }

 end; {кінець with}

end|.

Як видно з тексту програми, залежно від величини, введеної в змінну x, може сформуватися велике число, число середнього розміру або мале число. Залежно від цього результат уміщається в 4-байтной (lo), 2-байтной (x) або однобайтною (bt) змінною. Звернемо увагу, що в архітектурі Intel байт з меншою адресою (індекс[0]) містить молодші двійкові розряди числа, а байт з великою адресою (індекс[3]) містить знак числа і старші розряди, тобто порядок розташування байтів в ПОП – ‘перевернений’, але усередині байта порядок убування старшинства бітів – прямій (тобто зліва-направо).

6.3. Рідко використовувані типи

Множини – це набори однотипних, логічно зв'язаних в одну групу об'єктів. Кількість елементів, що входять в множину, може мінятися в межах 0..255. Множина, що не містить елементів, називається порожньою. Саме непостійністю кількості своїх елементів множина і відрізняються від масивів і записів.

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

Опис типа|типу| множини|множини| має вигляд|вид|:

<им’я_типа> = SET OF <базовий тип>;

Як базовий тип елементів множинаі можуть бути перераховувані типи byte або char.

Приклад|зразок| 6.6 визначення і завдання|задавання| множин|множини| [1] :

type|

 digitChar = set of  ‘ 0’..’9’;

 digit         = set of  0..9;

var| 

s1,s2,s3| : digitChar|;

s4,s5,s6| : digit|;

begin|

s1:=| [‘1’,’2’,’3’];

s2:=| [‘3’,’2’,’1’];

s3:=| [’2’,’3’];

s4:=|[0..3,6];

s5:=|[4,5];

s6:=|[3..9];

end|.

Як видно з прикладу 6.6, завдання  конкретного екземпляра множинаі в тілі програми виконується перерахуванням через кому елементів множинаі, що обрамували квадратними дужками – так званим конструктором множини. В даному прикладі множина  s1 і s2 еквівалентна, а множина s3 включена в s2, але не еквівалентна їй.

Над множинами|множиною| визначені наступні|слідуючі| операції:

  •  * перетин множин|множини|; результат містить|утримує| елементи, спільні|загальні| для обох множинаі|множини|, наприклад, s4*s6| містить|утримує| [3,6].
  •  +   об'єднання множин|множини|; містить|утримує| елементи першої множини|множини|, доповнені бракуючими елементами з|із| другої множини|множини|, наприклад, s4+s5=|[0..6].
  •  - різниця множин|множини|; містить|утримує| елементи першої множини|множини|, які не входять в другу, наприклад, s1-s3=|[‘1’|].
  •  = перевірка еквівалентності; повертає TRUE|, якщо дві множини еквівалентні.
  •  <> перевірка нееквівалентності; повертає TRUE|, якщо дві множини|множина| не еквівалентні.
  •  <= перевірка входження; повертає TRUE|, якщо перша множина|множина| включена в другу.
  •  >= перевірка входження; повертає TRUE|, якщо друга множина|множина| включена в першу .
  •  IN перевірка приналежності елементу множинаі, наприклад (3 in s6) = TRUE.

При роботі з|із| множинами|множиною| окрім|крім| операцій можна використовувати  2 процедури:

  •  INCLUDE| (S, I) – включає елемент  I в множину S
  •  EXCLUDE| (S, I) – виключає елемент  I з|із| множини S

При цьому, природно, елемент I та множина S|множина| повинні належати одному базовому типу|типу|.

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

6.4. Іменування констант, константи, що типізуються

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

Секція опису констант розташовується в будь-якому місці розділу опису змінних/констант, починається з ключового слова const і має структуру:

const

<им’я_конст.1>= <значення1>; 

............

<имя_конст.i>= <значенняi>;

.............

<имя_конст.N>= <значенняN>; ,

де  <им’я_конст|.i> - символічне ім'я, привласнене константі i,

        <значення i|>  - значення i-ої константи.

Типовий приклад|зразок| використання  іменованої константи:

const  m=2; n=3;

var matr:array[1..m,1..n] of real;

i,j: integer;

begin|

.....

for i:=1 to m do

 begin|

  for j:=1 to n  do write(matr[i,j]:10:3);

  writeln|;

 end|;

.....

end|.

В даному прикладі показаний фрагмент програми, в якому виконується рядковий роздрук матриці. Розмір матриці задається за допомогою іменованих констант m (число рядків) і  n (число стовпців). Оператор  ‘ write(matr[i,j]:10:3); ’ виконується  n разів у внутрішньому циклі, послідовно роздруковуючи елементи одного рядка матриці дійсних чисел matr  з інтервалом 10 символів з 3-мя знаками після коми. Оператор  ‘ writeln; ’ виконується в зовнішньому циклі (цикл по i) після закінчення роздруку чергового рядка матриці і забезпечує підготовку друку наступного рядка. Якщо треба обробляти матрицю іншого розміру, досить змінити числа в першому рядку програми, не коректуючи операторів тіла програми.

Спосіб іменування констант, описаний вище, дає ‘незмінні’ константи. При спробі запису у комірки m і n в тілі програми транслятор видасть помилку. Якщо в процесі роботи програми необхідно змінювати значення іменованих констант, то в мові Паскаль використовуються так звані константи, що типізуються. У мові Сі такі змінні-константи носять назву змінних, що ініціалізували, що більш відповідає сенсу - такі константи можуть бути не лише в правій частині оператора привласнення, але і в лівій. Формат константи, що типізується:

const <им’я_константи>:<тип>=<ініціююче_значення>;

Тут <тип> - будь-який тип, описаний в Розділах 5,6.

Константи, що типізуються, зручні для завдання постійної інформації одновимірних і багатовимірних числових, символьних і рядкових масивів. Як початкове значення константи-масиву, що типізується, використовується список констант, відокремлених один від одного комами. Список обрамовується круглими дужками. Для масивів-матриць в круглі дужки обрамовуються константи одного рядка. Рядки відділяються один від одного комою. Вся  інформація матриці обрамовується в додаткові круглі дужки. У загальному випадку, при оголошенні багатовимірних констант-масивів множина констант, відповідна кожному виміру, обрамовується в додаткові круглі дужки і відділяється від сусідньої множини комою (див. Приклад 6.6).

Приклад|зразок| 6.6:

   Program  TipConst; { роздрук векторів, матриць і багатовимірних масивів,

                                          заданих  константами, що типізуються   }

   uses crt;

   var i,j,k,l:byte;

   const  

         matr: array[1..3,1..4] of byte=(( 0, 1, 2, 3),    {рядок 1 матриці 3х4}

                               ( 4, 5, 6, 7),   {рядок 2}

                               ( 8, 9,10,11));{рядок 3}

      cube: array[1..2,1..2,1..3] of integer=         {матриця третього порядку}

                                (((0,1,2),(3,4,5)),      {шар 1 - матриця 2х3 }

                                ((6,7,8),(9,10,11)));  {шар 2 - матриця 2х3}

       { надшар  рядок }

   mas4:array[1..2,1..2,1..2,1..3] of word=           { матриця 4-го порядку}

                      {шар стовпч.  }

                            ((((0,1,2),(3,4,5)),                {надшар1,шар1,матриця1,| 2х3}

                               ((6,7,8),(9,10,11))),          {надшар1,шар2,матриця2, 2х3| }

                              (((12,13,14),(15,16,17)),   {надшар2,шар1,матриця3, 2х3}

                               ((18,19,20),(21,22,23))));{надшар2, шар2,матриця4, 2х3}

   Begin|

   clrscr|;

    for i:=1 to 3 do

     begin|

      for j:=1 to 4 do  write(matr[i,j]:3);

      writeln|;

     end|;

     writeln|('3x4');

   for k:=1 to 2 do

    begin|

    for i:=1 to 2 do

     begin|

      for j:=1 to 3 do  write(cube[к,i,j]:(k+2));

      writeln|;

     end|;

    end|;

     writeln|('2x2x3');

  for l:=1 to 2 do

  begin|

   for k:=1 to 2 do

    begin|

     for i:=1 to 2 do

      begin|

        for j:=1 to 3 do  write(mas4[l,k,i,j]:((l-1)*12+k+2));

      writeln|;

      end|;

    end|;

  end|;

   writeln|('2x2x2x3');

   readln|;

End|.

Приклад|зразок| 6.6 ілюструє  використання констант-масивів, що типізуються. Результат виконання цієї програми показаний на рис.6.3.

Рис.6.3

Контрольні питання:

  1.  Масиви, обява масивів, доступ до елементів масиву
  2.  Скільки байтів виділяє транслятор під масив Month з Прикладу 6.1? Не спішить з відповіддю, питання не таке просте, як здається на перший погляд.
  3.  Розробіть програму обробки даних одновимірного масиву, що віддзеркалює дані вхідного масиву.
  4.  Алгоритм і програма перемноження матриць.
  5.  Записи.Навести приклади.
  6.  Множини та дії над ними.
  7.  В яких випадках ефективне використання іменованих констант?
  8.  Завдання багатовимірної матриці за допомогою констант.

Завдання для самостійної роботи 

  1.  Розробити і відлагодити програму складання двох векторів довільного розміру (задається з клавіатури).
  2.  Розробити і відлагодити програму обчислення скалярного добутку двох векторів.
  3.  Розробити і відлагодити програму складання двох матриць довільного розміру.
  4.  Розробити алгоритм, розробити і відлагодити програму перемноження матриць


Розділ 7. Операції і оператори

Оператор – це закінчена програмна конструкція, що виконує певні дії над змінними. У операторові змінні об'єднані операціями. Кожен оператор закінчується крапкою з комою.

Як відомо, тіло програми складається з:

  •  Операторних дужок (begin…end) тіла програми та складених операторів
  •  Операторів привласнення|присвоєння| 
  •  Операторів циклу (for, while, repeat)
  •  Операторів альтернативного вибору (if, case)  
  •  Міток
  •  Операторів переходу (goto, continue, break)
  •  Операторів виклику підпрограм (процедур і функцій).

7.1. Оператор привласнення|присвоєння|. Сумісність типів

Оператор привласнення має структуру:

<им’я_змінної> := <вираз>; ,

де:    := - операція привласнення,|присвоєння|

        <им’я_змінної> - змінна будь-якого типу|типу| (див. рис.5.1.), якої привласнюється вираз,|вираз|

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

 ; - ознака кінця оператора.

Не дивлячись на  очевидну простоту, оператор привласнення має глибокий багатоваріантний функціональний сенс (те, що в мові Сі називається перевантажуваною функцією, а в ООП- поліморфізмом). Дійсно, одна справа, коли ми привласнюємо значення однієї простої змінної інший простій змінній. А як бути із структурованими даними, чи маємо ми можливість одним оператором перенести дані запису в інший запис, дані масиву в інший масив? Відповідь позитивна, якщо два записи або два масиви  однотипні (одного шаблону). Якщо ж в секції type використовуються два імені абсолютно ідентичних шаблонів, які в секції var застосовуються до двох записів (масивів), то транслятор видасть помилку! У наведеному нижче прикладі два записи мають один і той же шаблон, також як два масиви. В цьому випадку програма виконується без помилок.

Приклад|зразок| 7.1. :

Program Test;{Використання шаблонів type,присвоение записів і масивів }

uses crt;

type

tr1=record

       name|: string|[30];

       zp:real|;

       end|;

 tr2=record

       name|: string|[30];

       zp:real|;

       end|;

   tmas1=array[1..5] of tr1;

   tmas2=array[1..5] of tr1;

var|

r1:tr1|;

r2:tr1|;

mas1:tmas1|;

mas2:tmas1|;

begin|

clrscr|; { }

 r1.name:=…;

 mas1[3].zp:=…;

r2:=r1|;

mas2[2]:=mas1[3]|;

readln|;

writeln| ('The| End|');

end|.

7.2. Арифметичні операції

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

  •  +   - складання
  •  -    -віднімання
  •  *    -множення
  •  /     -ділення|поділка| дійсне
  •  div|    -ділення| цілочисельне (наприклад, 5 div| 3 =1)
  •  mod|  -залишок| від цілочисельного ділення|поділки| (5 mod| 3=2).

На відміну від інших МВР Паскаль гранично строгий до спільного використання в операціях різних типів даних. Транслятор аналізує типи даних у виразі праворуч від знаку операції привласнення (:=)  і приводить всі операнди до ‘старшого’ типа. Якщо операнди типа  byte, shortint - то до типа integer. Якщо серед операндів є дійсний тип або використовується операція дійсного ділення - то до типа real. Після обчислення виразу його тип приводиться до типу змінної зліва від знаку привласнення.

В результаті|внаслідок| роботи такого алгоритму дійсній змінній, що стоїть зліва від знаку привласнення|присвоєння|, може бути привласнене значення цілочисельного виразу|виразу|, отримане|одержувати| праворуч від знаку привласнення|присвоєння|. Зворотна ситуація недопустима: привласнення|присвоєння| дійсного значення цілочисельній змінній транслятор сприймає як помилку. Для цього випадку в Паскалі використовується функція округлення (round|)   або відкидання дробової частки|частини| (trunc|).

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

Приклад|зразок| 7.2 :

i: integer|;

a:real|;

b: byte|;

c:char|;

begin|

 a:=5.2;

 i :=2;

 a:=a/i;           {a=5.2/2=2.6}

        {i := а;            Помилка! Неприпустиме привласнення}

        i := round|(a); {i=3|}

        i :=trunk (a);  {i=2|}

        c:=’1|’;

       { b:=c;              Помилка! Неприпустиме привласнення}

        b:=| ord|(c);      {b=49|}

        c:=chr|(b+1|);   {c=’2|’}

      end|.

7.3. Логічні операції

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

Таблиця 7.1.

Операція

(синоніми назви)

Значення біта першого операнда

Значення біта другого операнда

Результуючий біт

Not |(заперечення)

-

0

1

1

0

And |(кон'юнкція,

логічне множення)

0

0

1

1

0

1

0

1

0

0

0

1

Or |(диз'юнкція,

логічне складання)

0

0

1

1

0

1

0

1

0

1

1

1

Xor |(нееквівалентність, складання по модулю 2)

0

0

1

1

0

1

0

1

0

1

1

0

У Таблиці 7.2. приведені правила отримання|здобуття| результату логічної операції для  змінних або виразів булевого типу|типу|.

Таблиця 7.2.

Операнд 1

Операнд 2

not

and

or

xor

True

-

False

-

-

-

False

-

True

-

-

-

False

False

-

False|

False

False

False

True

-

False|

True

True

True

False

-

False|

True

True

True

True

-

True|

True

False

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

i shl n - зсув вмісту i на n розрядів ліворуч; молодші розряди, що звільнилися, заповнюються нулями, наприклад, 5 shl 1=$0A=1010

i shr| n - зсув|зсув| вмісту i на n розрядів праворуч|вправо|; старші розряди, що звільнилися|визволяли|, заповнюються нулями, наприклад, 5 shr| 2=1.

7.4. Операції відношення|ставлення| (порівняння)

Операції відношення (порівняння) :  ‘ =, <, <= >, >=, <> ’  використовуються для вироблення булевої умови (true, false)  в так званих операторах з перевіркою умови (if, while, repeat…until). Тип результату виконання операції відношення – логічний (true, false).

Операції відношення застосовні до всіх простих типів (див. Розділ 5). Порівнювати між собою можна змінні однакового типа.  Допустимо також порівняння дійсних чисел з цілими.

Операції відношення|ставлення|:

a=b| – перевірка: перша змінна рівна другій?,

a<b| – перевірка: перша змінна менше другої?,

a<=b| - перевірка: перша змінна менше або рівна другої?,

a>b| - перевірка: перша змінна більше другої?,

a>=b| - перевірка: перша змінна більше або рівна другої?,

a<>b| - перевірка: порівнювані змінні не рівні?.

7.5. Пріоритет операцій

Дія дужок в арифметичних і логічних виразах  на мові Паскаль відповідає загальноприйнятим правилам. За відсутності дужок операції виконуються відповідно до їх пріоритету (див.Табл.7.3 )

Таблиця 7.3.

Пріоритет операцій

Пріоритет

Операції

 1(найвищий)

not (логічна операція НЕ), @ (операція узяття адреси змінною)

 2

*,/,div,mod, and(логічне ‘ І’), shl(зсув бітів ліворуч), shr(зсув бітів праворуч)

 3

+,-,or(логічне ‘АБО’), xor(виключаюче ‘АБО’ - нееквівалентність)

 4(найнижчий)

Операції відношення(порівняння): (=,<>,>,>=,<,<=), перевірка входження елементу в множину (in)

Вищий пріоритет має логічна операція заперечення (not), а також операція узяття адреси (@). Остання використовується при роботі з покажчиками (див. Розділ 10). Другий пріоритет мають мультиплікативні арифметичні операції (*,  /,  div,  mod),  кон'юнкція (and)  і  операції зсувів (shl, shr).

Третій пріоритет мають аддитивні  арифметичні  і логічні операції  (+, -, or, xor). І, нарешті, нижчий (четвертий) пріоритет мають операції відношення (=,<>,>,>=,<,<=), а також операція перевірки входження елементу у вказану множину (in).

Тут доречно відзначити, що мова Сі має набагато ширший набір операцій, який розділяється на 14 пріоритетів [3]. Це значно підвищує гнучкість мови і, як наслідок, вимагає вищого професіоналізму і відповідальності  автора програми. Тому рекомендуємо не поспішати програмувати на 'розумному' Сі. Принаймні, Ваші перші 5-10 тисяч рядків програмного коду краще створювати  на Паскалі (наприклад, в середовищі Delphi), поки не набудете необхідних професійних навичок, щоб відчувати небезпечні місця програми. А їх в Сі – таких 'вовчих ям', більш ніж достатньо.

Підкреслимо, що при програмуванні великих несистемних (прикладних) програмних|програмових| комплексів функціональні можливості|спроможності| Паскаля і Сі  абсолютно рівноцінні! Так чи слід “стріляти з|із| гармати по горобцях”?

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

7.6. Оператори циклу

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

FOR - оператор рахункового циклу 

WHILE...DO оператор циклу з попередньою перевіркою умови виконання циклу

REPEAT…UNTIL – оператор циклу з перевіркою в кінці циклу умови виходу з циклу.

FOR - оператор рахункового циклу, має структуру:

FOR <параметр_циклу> := <поч.знач>  TO <конеч.знач> DO <оператор>; ,

де:

     FOR, TO, DO – зарезервовані слова (для, до, виконати),

<параметр_циклу> - змінна-лічильник будь-якого порядкового типу (див.

                                    Розділ 5), частіше всього- word, integer;

<поч.знач> - початкове значення лічильника

<конеч.знач>- кінцеве значення лічильника

<оператор> - простий або складений  оператор Паскаля – декілька простих

                  операторів, обмежених операторними дужками (begin…end;)_.

WHILE…DO оператор циклу з попередньою перевіркою умови, має структуру:

WHILE <умова> DO <оператор_циклу>; ,

де:

     WHILE, DO – зарезервовані слова (поки, виконати),

     <умова> - булева змінна або булеве вираз (операція порівняння); по  

                       TRUE виконуємо оператор (оператори) циклу, по FALSE  

                        цикл закінчується,

     <оператор_циклу> - простий або складений  оператор Паскаля –

           декілька простих операторів, обмежених операторними дужками  

           (begin…end) .

REPEAT…UNTILоператор циклу з перевіркою умови в кінці циклу, має структуру:

REPEAT <оператори> UNTIL <умова_виходу_з_цикла >; ,

де:

      REPEAT, UNTIL – зарезервовані слова (виконати, поки),

      <оператори> - декілька простих операторів Паскаля, обмежених

                                зарезервованими словами (REPEAT… UNTIL),

      <умова_виходу_з_цикла> - булева змінна або булевий вираз (операція

                                                   порівняння); по FALSE цикл виконується,

                                                   по TRUE цикл закінчується. 

Увага! В Паскалі на відміну від Сі і більшості інших  МВР, цей цикл виконується, поки постумова=FALSE,  а вихід з циклу походить, коли постумова стане TRUE.

7.7. Оператори альтернативного вибору

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

IF…THEN...ELSE – оператор галуження по двох напрямах

CASE… OF...ELSE...END оператор галуження по множині напрямів.

Оператор галуження по двох напрямах має структуру:

IF  <умова> THEN <оператор1> [ELSE  <оператор2> ]; ,

де:

      IF, THEN, ELSE – зарезервовані слова (якщо, то, інакше),

             квадратними дужками позначена необов'язкова частина оператора,

      <умова> - умова порівняння – набір змінних, об'єднаних операціями

                        порівняння; умова – логічний тип, що приймає значення

                        TRUE або FALSE,

        <оператор1> - простий або складений оператор (блок операторів),

                                 виконуваних, якщо умова=TRUE,

           <оператор2> - простий або складений оператор (блок операторів),

                                     виконуваних, якщо умова=FALSE.

Оператор галуження по множині напрямів має структуру:

CASE <ключ_вибору> OF <список_вибору_операторів>  

                                                            [ELSE<оператор>] END; ,

де:

      CASE, OF, ELSE, END – зарезервовані слова (випадок, з, інакше,

                                                   кінець), квадратними дужками позначена   

                                                   необов'язкова частка оператора,

     <ключ_вибору> - будь-яка змінна перераховуваного типу,

     <список_вибору_операторов> - одна або більш  конструкцій вигляду:

               <константа_выбору>: <оператор>;

                <константа_выбору>- константа, перелік констант (через кому)

або діапазон констант (через покажчик діапазону-  ..)

                   того ж типа, що і ключ_вибору,

                   <оператор> - простий або складений оператор.

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

7.8. Оператори передачі управління

Оператори передачі управління дозволяють порушити послідовність виконання команд. Наприклад, в блоці команд оператора циклу – перейти на кінець циклу або достроково перервати цикл. До операторів цього типу в Паскалі відносяться:

  •  GOTO - оператор безумовної передачі управління на поміченого оператора
  •  BREAK – оператор дострокового переривання циклу
  •  CONTINUE – оператор пропуску кінцевих операторів циклу і переходу на перевірку умови виконання циклу.

Оператор безумовної передачі управління на поміченого оператора має структуру:

GOTO <мітка> ,

де:

GOTO- резервоване  слово (перейти на),

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

У Паскалі використання оператора GOTO і міток швидше виключення, чим поширене явище, тому контроль посилений. На відміну від Фортрану і Бейсика, де мітки операторів проставляються довільно, в Паскалі потрібне оголошення міток в розділі опису даних. Тут використовується ключове слово LABEL (мітка), наприклад:

Program .;

Uses ...;

Label L1,0,999;

Type| ...;

Var  n:byte;

             ...;

    Begin|

   ...

L1:  n:=0;

   ....

   ....

   If … then goto L1 else goto 999;

999:

  end|.

Як видно з наведеного прикладу, мітка – це ім'я, яке, на відміну від імені змінної, може починатися з будь-якого символу, у тому числі – з цифри, після якого ставиться двокрапка. Відмітимо, що в секції LABEL  описуються тільки мітки операторів.  Мітки-константи вибору в операторові CASE і мітки варіантів в описі запису з варіантами носять локальний характер і тому в секції  LABEL не описуються.

Оператор дострокового переривання циклу BREAK не має параметрів і дозволяє достроково вийти з оператора циклу.

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

У Прикладі|зразку| 7.3   приведено використання розглянутих вище операторів|розглядали| .

Приклад 7.3:

Program SimplClc; { Програма виконує арифметичну операцію над двома цифрами, що вводяться з клавіатури }

Uses CRT; { використовуємо зовнішній модуль-бібліотеку CRT, де є процедура CLRSCR – очищення екрану}

Label  S;     { мітка для переходу по goto}

var|

              st: string; { символьний рядок з арифметичним виразом, наприклад:  ‘7+9=’}

       operat: char; { символ операції}

          x,y,z: real; { операнди у форматі дійсних чисел}

  stop, op2 : boolean; { прапорці}

               i : integer; { лічильник циклів для for}

begin|

   clrscr|;           {очищення екрану}

S: stop:=false;  { Прапор-ознака закінчення програми; S: - мітка}

    op2:=false;  {op2 - ознака другого операнда, тобто зараз чекаємо перший операнд}

Repeat                   { головний цикл програми, див. until в кінці програми }

Writeln('Введіть вираз, наприклад, 5/3= ' ); { запрошення до введення даних}

Readln|(st|); {Прочитали рядок з|із|  виразом|виразом|, далі будемо посимвольно розбирати цей рядок}

for i:=1 to length(st) do { посимвольний аналіз рядка st; length(st) – індекс останнього символу –  число символів рядка st }

 begin {початок складеного оператора}

  if st[i]=' ' then continue;{ аналіз на пропуск-перехід на нову ітерацію i  }

  case st[i] of   {case1 -анализ на цифру/нецифру}

   '0'..'9':begin { символ-цифра, тобто це або перший або другий операнд}

               if op2=false then

                begin { перший операнд арифметичного виразу}

                  x:=ord|(st|[i]) - ord|('0'|); {формування з|із| символу числового значення першого операнда}

                  op2:=true; { установка прапора, що при наступному (не цьому!) зверненні до case1 символ цифри – це буде другий операнд арифметичного виразу}

                 end  { кінець складеного оператора в if op2=..}

                                   else            { op2=true}

                begin       { початок складеного оператора по else }

                  y:=ord|(st|[i]) - ord|('0'|); {формування з|із| символу числового значення другого оператора}

                  case operat of             {case2- обчислення виразу, сюди потрапляємо тільки після введення  символу операції - operat, див.нижче: if st[i]='=' then …else operat:=st[i]; }

                     '+': z:=x+y|;

                      '-': z:=x-y|;

                     '*': z:=x*y|;

                      '/': z:=x/y;

                   end;{case2}

            end;{else if op2=true}

          end;{0..9}

 else     {case1}

  begin { черговий символ st – не цифра}

   if st[i]='=' then begin { ознака кінця вираз – роздрукувати результат і перейти на початок програми}

                      write|(z:4:1|);

                      writeln|;

                      goto s; { перехід на мітку – початок програми }

                             end|

                    else operat:=st[i]; {else if: st[i]  не знак рівності, не цифра і не пропуск, тобто це знак операції}

  end;{else case1}

 end;{case1}

 end;{ закриваюча дужка складеного оператора циклу for }

if st=' ' then stop:=true; {st=пробілу}

until stop; {см.зверху repeat}

end|.

Приклад|зразок| 7.3 добре прокоментований. Як бачимо, навіть така функціонально проста програма має досить|достатньо| складну логічну структуру. Необхідне постійне тренування в складанні програм і читанні чужих. До речі, читання чужих програм набагато складніше в освоєнні, чим складання власних. Настійно рекомендуємо уважно вивчити текст Прикладу|зразка| 7.3, запрограмувати його і поекспериментувати з|із| модифікацією програми. Якщо зможете, спробуйте удосконалити програму, щоб|аби| можна було працювати з|із| багатозначними|многозначними| дійсними числами, а не з|із| цифрами, наприклад, ‘1024.5*2.543/5 = ’. До удосконалення цієї програми ми ще повернемося в розділі 9.

Контрольні питання:

  1.  Що таке оператор? Оператор привласнення, сумісність типів.
  2.  Арифметичні операції
  3.  Логічні операції
  4.  Операції відношення
  5.  Пріоритет операцій
  6.  Оператори циклу
  7.  Оператори галуження програми
  8.  Оператори передачі управління

Завдання для самостійної роботи 

1. Скласти блок-схему алгоритму для програми Прикл.7.3.


Розділ 8. Процедури і функції

8.1. Створення|створіння| і виклик підпрограм (процедур і функцій)

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

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

У Паскалі підпрограми підрозділяються на процедури і функції. У мові Сі поняття процедури відсутнє, тобто всі підпрограми є функціями.

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

Procedure <им’я_процедури>(<список_форм._парам.>); {заголовок

                                                                                                    процедури}

     <розділ опису локальних змінних>

     <тіло процедури, обмежене операторними дужками  begin…end;>

Виклик процедури в тілі програми – це згадка імені процедури із списком фактичних параметрів в круглих дужках. Приклад виклику процедури:  

writeln(x,y); .

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

На відміну від процедури функція повертає значення, тип якого вказується в додатковому полі заголовка ' :<тип_повертаєм_значения> '. Функція використовується в операторах привласнення як звичайна змінна. Приклад використання функції: y:=sin(x)+5.3;

Формат опису функції:

Function<имя_функции>(<список_форм._парам.>):<тип_повертаєм.значен.>;

<розділ опису локальних змінних>

<тіло процедури, обмежене операторними дужками begin.. end;>

Поле ' (<список_форм._парам.>) ' заголовка  процедури або функции– це обмежений круглими дужками список формальних параметрів, розділених один від одного комою або точкою з комою (приклад – див нижче).

8.2. Формальні і фактичні параметри

Формальними параметрами можуть бути імена (або адреси) змінних і/або констант - простих і структурованих з вказівкою їх типа, а також  імена процедур і функцій зі своїми параметрами. Формат списку формальних параметрів:

(<Ім’я_змін1>:<ТИП1>;<Ім’я_змін2>:<ТИП2>;..)

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

Розділ опису локальних змінних може бути відсутнім, а функція                  ( процедура) –  використовувати змінні із заголовка або глобальні змінні з головної   програми. Якщо в процедурі (функції) використовуються  тільки глобальні змінні, то заголовок такої підпрограми може не містити списку формальних параметрів. Приклад:  стандартна процедура CLRSCR; - очищення  екрану.

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

 Типи формальних параметрів вказуються безпосередньо в списку формальних параметрів опису процедури (функції) через символ двокрапки, як це робиться в секціях var розділу опису даних. Наприклад:

......

procedure  proc1(i,j:word;  x,y:real; var z:real; st1:string[25]); {заголовок

                                                                                                      процедури}

var { опис локальних змінних процедури}

    s: string;

   q: byte; 

 а,b:real; {тут  a,b – локальні змінні, що належать тільки  proc1}

begin { початок тіла процедури}

  ....

  if  s=st1 then ... ;

  q := i+j; {локальна змінна q обчислюється через формальні параметри i,j}

  ....

end; {кінець опису proc1}

function fun1(а,b:byte):string; {заголовок функції, що повертає рядок}

 begin {початок тіла функції; тут a,bформальні параметри, що будуть передані із  головної програми; a,b  не мають ніякого  відношення до

                                                             локальних a,b із процедури proc1 }

   ....

   fun1:=chr(a)+chr(b); { Зверніть увагу: fun1 розглядається як звичайна       

змінна типа string  і їй привласнюється деякий

обчислюваний  вираз     конкатенація двох

символів; в результаті в рядок з ім'ям fun1   

поміщено два символи }

end; {fun1}

Звернення|звертання| до proc1| і fun1| із|із| визиваючої програми при цьому може бути таким:

.....

      var| 

            m,n:word;

              i,j:byte;

              c,d,f: real;

               ss:string[25];

      begin|

       ...

Proc1(m,n,d,c,f,ss); {правильне звернення до процедури – всі змінні списку

                                 фактичних параметрів вказані в порядку, визначеному   

                                  формальними параметрами опису процедури}

(* Proc1|( m,ss,n,d,f,c|); {неправильне звернення до процедури – порушений

                              лад|порядок| дотримання|проходження| типів в списку фактичних параметрів} *)

 i:=49;

j:=50|;

writeln| (fun1|(i,j|)); {Тут фактичним параметром стандартної процедури             

                writeln|()  є|з'являється| змінна-функція fun1| з|із| фактичними параметрами i та j}

      end|.

Спробуйте здогадатися, що виведе на екран процедура writeln|() з|із| цього прикладу|зразка|?

Якщо ви уважно вивчали матеріал і приклади  попередніх розділів (таблиця кодування символів  ASCII, функція перетворення числа в символ), то легко відповісте на це питання: на екрані з'являться символи ' 12 '. Тому, кому важко з відповіддю на це питання, радимо повторно пропрацювати відповідні розділи.

8.3. Способи передачі в підпрограму фактичних параметрів

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

Передача в підпрограму копії фактичного параметра.

Передача в підпрограму адреси фактичного параметра.

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

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

У [1]  приведений простий приклад|зразок|, що пояснює|тлумачить| специфіку передачі в підпрограму значення або адреси фактичного параметра.

Приклад|зразок| 8.1.:

const|

       а: integer=5;

       b: integer=7;

Procedure Inc2(var c:integer; b:integer);

begin|

c:=c+c|;

b:=b+b|;

writeln|(‘подвоєні:’, c:5|, b:5|:);

end; {Inc2}

Begin {main}

writeln|(‘початкові  :’,a:5, b:5|);

inc2|(а,b|);

writeln|(‘результат  :’,a:5,b:5);

End|.

Результат виконання цієї програми:

початкові  :    5    7

подвоєні   :  10   14

результат  :  10     7

Як видно з прикладу, подвоєння другого формального параметра в процедурі Inc2 не викликало зміни фактичної змінної b, оскільки цей параметр описаний в заголовку процедури як параметр-значення, тобто в процедуру передана копія фактичного b, і ця копія  в процедурі піддалася зміні без зміни значення  b в головній програмі.

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

Формат const зручний при передачі в підпрограму параметра-масиву як вхідні незмінні дані. Дійсно, в цьому випадку передача за значенням викликає копіювання масиву, що приводить до великих витрат часу і пам'яті.

Для закріплення розуміння цього важливого|поважного| для програміста розділу наведемо практичний приклад [1]  використання підпрограм для вирішення завдання|задачі| перекладу|переказу| символів рядка до верхнього регістра|реєстру| (прописні букви|літери|) за допомогою процедури  ProcUpSt|()  і, для різноманітності, з|із| аналогічними можливостями|спроможностями| функції  FunDnSt|():string  - перекладу|переказу| символів рядка до нижнього регістра|реєстру| (рядкові букви|літери|).

Приклад|зразок| 8.2:

Program CharsCnv; {програма-тест перевірки роботи процедури  ProcUpSt|() і  функції FunDnSt|():string  }

Uses crt;

var|

      sinp,sout:string;{  початкова і перетворена строки - глобальні змінні }

{*************Розділ опису  процедур і функций*******************}

Procedure ProcUpSt(s1: string; var s2: string); {заголовок процедури

                                  перетворення  символів рядка до верхнього регістра|реєстру|}

var {секція опису локальних змінних}

      i: integer; { лічильник циклу перетворення}

      с: char;    { робоча змінна перетворення}

begin {початок тіла процедури}

s2:= ' '; { чистимо рядок виходу}

for| i:=1| to| length|(s1|) do| {цикл посимвольного аналізу початкового|вихідного| рядка}

 begin|

   c:=s1|[i];                     {черговий символ для аналізу}

   if (c>='a') and (c<='z') then {Початок оператора if, аналіз на рядкових  

                                                                                                                латині}

     c:= chr(ord('A')+ord(c)-ord('a')){перетворення їх в прописних.

                                                          Розібратися  як!!!}

  else if  (c>='а') and (c<='п') then  {аналіз на першу половину рядкових

                                                                                                          кирилиця}

     c:= chr(ord('А')+ord(c)-ord('а')) {перетворення їх в прописних}

   else if (c>='р') and (c<='я') then   {аналіз на другу половину рядкових

                                                                                                      кирилиця }

     c:= chr(ord('Р')+ord(c)-ord('р'));{перетворення в прописних. Кінець          

                                                                                                оператора if}

      { прописні символи при такому аналізі залишилися в c не

                                                                                                 перетвореними!}

 s2:=s2+c|;  {Додавання|добавляти| до вихідного рядка чергового перетвореного

                                                                                                              символу}

 end|;

 end;   { ProcUpSt }

Function FunDnSt(s1: string):string;  {заголовок функції перетворення                 

                                                           символів рядка до нижнього регістру|реєстру|}

var {секція опису локальних змінних}

      i: integer; { лічильник циклу перетворення}

      с: char;    { робоча змінна перетворення}

     s2|: string|;   {результат  перетворення}

 begin {початок тіла функції; коментарі див. вище  в тілі ProcUpSt }

  s2:= ' ';

for| i:=1| to| length|(s1|) do|  {}

 begin|

   c:=s1|[i];

   if (c>='A') and (c<='Z') then

     c:= chr(ord('a')+ord(c)-ord('A'))

   else if  (c>='А') and (c<='П') then

     c:= chr(ord('а')+ord(c)-ord('А'))

   else if (c>='Р') and (c<='Я') then

     c:= chr(ord('р')+ord(c)-ord('Р'));

   s2:=s2+c|; {}

 end|;

 FunDnSt:=s2;  {Увага! Завжди потрібно зарядити змінну-ім'я функції,

                            інакше  –   помилка}

 end;   { FunDnSt }

(**************** Головна|чільна| програма **********************)

Begin|

 Write(' Введіть рядок:  ');{Запрошення до введення. Програма зупиниться   

                                                                                                         на   readln()}

  Readln|(sinp|); {Вводимо|запроваджуємо| з клавіатури рядок і натискуємо|натискаємо| Enter|}

  ProcUpSt|(sinp,sout|);  {Обробляємо введений|запроваджувати| рядок і перетворимо його

                                               в рядок  sout|   з|із| символам верхнього регістра|реєстру|}

  Writeln('   результат процедури: ',sout);  {роздрук результату}

  Sout:=FunDnSt(sinp);{ Обробляємо введений рядок і перетворимо його                                                      

                                               в рядок  sout|   з|із| символам нижнього регістра|реєстру| }

  Writeln('   результат функції: ',sout);      { роздрук результату }

End|.

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

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

8.4. Параметри-масиви і параметри-рядки 

Вище ми відзначали, що параметрами можуть бути імена простих змінних і констант, структурованих змінних і констант, а також імена процедур (функцій).

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

Procedure| S(а: array|[1..10] of| real|);

Правильним визначенням  такої процедури буде:

type|

     tmas1=array[1..10] of real;

Procedure s(a:tmas1);

........

Аналогічно оголошується функція:

 type|

      tsin=string|[15];

    tsout=string|[30];

Function St(s:tsin):tsout;

.......

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

8.5. Параметри-функції і параметри-процедури

Параметри-функції і параметри-процедури відносяться до так званого процедурного типу (див. рис.5.1). Це нововведення фірми Борланд, відсутнє в стандарті мови Паскаль. Основне призначення цих типів – засіб передачі процедур і функцій як фактичні параметри звернення до інших процедур і функцій.

Для оголошення процедурного типа|типу| використовується заголовок процедури (функції), в якому опускається її ім'я, наприклад:

type| 

 tProc=Procedure|(n:word|; var| a:byte|); { визначення процедурного типу|типу| з|із|               

                                                                                              двома  змінними}

var| 

  procvar|: tProc|; {змінна процедурного типу|типу|}

         x,y: byte;

{******************Опис процедур і функцій *******************}

Procedure  Bound(x: word; var y: byte); {процедура обмеження змінної}

begin|

  if| x>255| then| y:=| x mod| 255

  else|  y:=x|

end|;

{****************** Головна|чільна| програма| *************************}

Begin|

 Procvar:=Bound|; {завантажили процедурну змінну ProcVar| ім'ям (точніше  

                                            адресою точки   входу в тіло процедури)  Bound|}

 For| x:=150| to| 180 do|

   begin|

     Procvar|(x+100,y|);{викликаємо|спричиняємо| Bound| в циклі 30 разів}

     Write| (y:8|)

   end|;

End|.

Контрольні питання:

  1.  Створення і  виклик підпрограм.
  2.  Визначення процедури і функції.
  3.  Формальні і фактичні параметри.
  4.  Способи передачі в підпрограму фактичних параметрів.
  5.  Параметри-масиви і параметри-рядки.
  6.  Параметри-функції і параметри-процедури.

Завдання для самостійної роботи 

1. Нарисувати  схему алгоритму прикладу 8.2.

Розділ 9.  Як створюються програмні|програмові| комплекси 

9.1. Етапи створення великих програмних|програмових| комплексів

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

Замовник зазвичай|звично| формулює свою проблему у вигляді Технічних вимог (ТВ). Після|потім| опрацювання|проробляти| ТВ Розробник складає Технічне завдання|задавання| (ТЗ) на розробку по правилах, обумовлених у відповідних нормативних документах (ГОСТ, ДСТУ), і затверджує його у Замовника. Вся розробка програмного|програмового| комплексу ведеться відповідно до ТЗ.

9.2. Технічні вимоги на розробку програмного комплексу

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

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

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

Діалог з|із| оператором має бути гранично простим і виглядати так:

Введіть арифметичний вираз:                  { ПК-запрошення до введення}

5.2*3=             {Оператор - вводить|запроваджує| з клавіатури арифметичний вираз|вираз| і Enter|}

15.6                 { Відповідь ПК – результат обчислення арифметичного виразу}

Введіть арифметичне вираз:    { Нове запрошення ПК, и.т.д..}

........   “

Ось|от| такі побажання (Технічні вимоги) Замовника.

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

Алгоритм програми калькулятора  складається з 12 функціональних блоків, з яких два блоки оформлено у вигляді підпрограм: процедури PLex (блок 4) і функції Conv (блок 7 ). Призначення процедури PLex – розбирання початкового рядка на три рядки-лексеми (перший, другий операнди і тип операції). Функція  Conv викликається в рахунковому циклі двічі. Її призначення – переклад лексеми (символьного рядка) оператора в число (двійковий код). Призначення решти блоків зрозуміле з блок-схеми. Програма закінчує працювати, якщо при черговому запрошенні    (блок 2, мітка L1:)  на клавіатурі натискувати ‘Enter’ без введення інших символів. Крім того, символьний рядок з арифметичним виразом має бути оформлений синтаксично правильно – мати два операнди, символ арифметичної операції між ними і закінчуватися символом '=' (рівно).

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

 

 9.3. Ескізне опрацювання|проробляти| програмного|програмового| продукту

Отже, Головний конструктор проекту (а це він розробив блок-схему рис.9.1, оскільки часто Замовник сам не знає, чого він хоче, - Правило 1) приступає до створення свого творіння. Перш за все, підберемо бригаду розробників:

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

Бібліотеку підпрограм  розробляє кращий програміст і мій друг – Віктор Сидоренко.

Ну, а якщо у  Замовника в процесі розробки з'явиться примха (а примха, всупереч ТЗ, з'являється завжди - Правило 2, тому що, див. Правило 1), то як ‘резерв головного командування’ до проекту підключаю нашу чарівну програмістку, блондинку Людочку Савченко.

      Пам'ятайте: Замовник завжди прав! Правило 3.

Почали|починали|! Головний|чільний|  конструктор по блок-схемі рис.9.1 накидав і (відладив|налагоджував|!) ескіз програмного|програмового| продукту, відображений|зображати| на рис.9.2.

Рис.9.2. Ескіз програми


Як бачимо, у нас вже є:

  •  Шаблон рядка-лексеми і шаблон масиву таких рядків в секції type
  •  Опис змінних, використовуваних головною програмою, в секції var
  •  Опис (точніше, заготівка) процедури лексичного аналізу PLex
  •  Опис (заготівка) функції Conv
  •  Тіло головної|чільної| програми (майже готове до промислової експлуатації, да-да не дивуйтеся!)

Наступний крок - виділення в особливу групу глобальних змінних і підпрограм і створення окремих  *.pas-модулей для глобальних змінних і підпрограм. На рис.9.3. показана та ж головна програма, але з видаленими з неї глобальними змінними і описувачами підпрограм. Програма стала компактніше, а в її розділі Uses окрім CRT з'явилися імена двох додаткових модулів – MyVar і MyLib. На рис.9.4 і рис.9.5 показані тексти цих програмних модулів.

Рис.9.3. Calculat| – програма-калькулятор

Що змінилося на рис.9.3 в порівнянні з ескізом рис.9.2 і Прикладом 7.3, в якому арифметичні операції проводилися тільки над однорозрядними числами (цифрами)?

Текст головної|чільної| програми  ' схудлий '  за рахунок видалення|віддалення| фрагмента тіла програми (див. Приклад|зразок| 7.3), який в нашому проекті оформляється у вигляді підпрограм. В порівнянні з ескізом рис.9.2 з|із| тексту рис.9.3  видалені|віддалені| описувачі глобальних змінних і підпрограм.  Опис глобальних змінних  винесений в окремий модуль MyVar| (див. рис.9.4). Опис підпрограм винесений  в окремий модуль MyLib| (див. рис.9.5). Природно, модуль MyLib| – поки що ескіз справжньої|даної| бібліотеки стандартних призначених для користувача програм, але|та| всі інтерфейсні угоди вже відпрацьовані|відробляти|.

Ріс.9.4. MyVar|програмний|програмовий| модуль опису глобальних змінних

Ріс.9.5. MyLib| – ескіз модуля опису стандартних підпрограм користувача

На цьому робота Головного конструктора проекту як програміста закінчена. Кажучи по-науковому, залишилася неприємна робота по менеджменту перетворення ескіза модуля MyLib в працюючий програмний продукт. А по-простому - промоушн трохи неорганізованого, але талановитого програміста, мого друга Віктора Сидоренко (промоутер – погонич худоби, ам.).  Адже це він зробить левову частку роботи проекту, а мені залишається тільки інтелігентна робота пожинателя лавр розробника такого прекрасного(?)  і багатьом необхідного(?!) програмного продукту.

Спробуйте тепер і Ви свої сили в розробці модуля MyLib|.

9.4. Модульна архітектура складних програмних|програмових| комплексів

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

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

Тепер залишилося роз'яснити|роз'ясняти|, що таке програмний|програмовий| модуль і як він влаштований|улаштувати|. Програмний|програмовий| модуль – це окремо трансльований *.pas-файл, що має наступні|слідуючі| розділи:

  •  Заголовок
  •  Інтерфейсний розділ
  •  Виконувана частина|частина| 
  •  Частина|частина|, що ініціює процес виконання підпрограм модуля

З рис.9.4, 9.5 видно, що заголовок модуля має структуру:

Unit  <ім'я модуля> ;

На відміну від головної програми, де заголовок (Program) може бути взагалі відсутнім, в модулі  наявність заголовка обов'язкова,  причому ім'я модуля повинне збігатися з ім'ям його  *.pas-файла.

Ім'я модуля служить для  його зв'язку з іншими модулями і головною програмою. Ці зв'язки указуються в трансляторній директиві Uses.    В даному випадку в Uses головної програми є посилання на модулі MyVar і MyLib, а в Uses модуля MyLib є посилання на модуль MyVar.

Інтерфейсний розділ модуля розташований на початку модуля, відразу за заголовком. Він відкривається трансляторною директивою INTERFACE (директиви транслятора пишуться без крапки з комою). У інтерфейсному розділі описуються всі типи (шаблони), змінні і заголовки процедур, доступні з інших модулів і головної програми. У нашому випадку в інтерфейсному розділі модуля MyVar описані типи і змінні, які можуть бути використані у всіх програмах даного програмного комплексу, а в інтерфейсному розділі модуля  MyLib описані заголовки загальнодоступних процедури PLEX і функції CONV.

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

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

Begin|

<тіло програми ініціалізації>

End|.

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

Контрольні питання:

  1.  Етапи проектування великих програмних комплексів.
  2.  Модульна структура програмних комплексів.
  3.  Переваги виділення глобальних змінних комплексу в окремий модуль.

Завдання для самостійної роботи 

1. Розробити бібліотеку підпрограм MyLib, ескіз якої розглядається в розділі 9.2 (див рис.9.5). Скомпонувати та протестувати CALCULAT - програмний комплекс калькулятора.


Розділ 10. Динамічне виділення пам'яті, покажчики 

10.1. Організація простору оперативної пам'яті в ПК

Програма, яку виконує процесор комп'ютера, може знаходитися або в оперативній памяті- ПОП, або в постійній памяті - ППП.  Частку спільного адресного простору займають адреси ППП, а частку - ПОП. У ППП розташовуються незалежні програми початкового запуску  з базовою системою управління пристроями вводу/виводу – BIOS (basic input/output system, англ).

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

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

Завантажувана програма застосування (*.exe - модуль) створюється на етапі компіляції з  сукупності окремо трансльованих об’єктних модулів (*.tpu – об’єктні модулі Паскаль-програм, *.obj- об’єктні модулі Сі та Ассемблерних-программ) Вона займає|позичає| в ПОП простір, що статично виділяється, під:

  •  Кодову частину|частину| (тіло) програми
  •  Статичну (не змінну в процесі роботи програми) область під пам'ять для змінних і констант, визначуваних в секціях var і const
  •  Область стека

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

Рис.10.1. Розміщення інформації *.exe – модуля в ПОП 

процедур і функцій). Він займає самі старші адреси області, виділеної під програму, і нарощується у бік зменшення адрес. При роботі на МВР стек організується автоматично, тобто прихований від програміста. Проте слід пам'ятати, що при неправильному використанні в програмі рекурсивних  процедур (що викликають самі себе в тілі процедури) зростаючий стек може переповнитися, накривши собою сегмент даних і/або сегмент кодів. Щоб уникнути таких неприємностей рекомендуємо в налаштуваннях транслятора ‘Options\Compiler’ у вікні ‘Runtime errors’ встановити всі види контролю, у тому числі - переповнювання стека.

Після завантаження в ПОП  програми застосування  адресний простір ПОП, що залишився, (динамічна пам'ять), зване 'купою(кіпою)' (heap,англ), в перший момент вільно. Початкова адреса купи зберігається в стандартній змінній HEAPORG, кінець – в змінній HEAPEND.  Поточний кордон незайнятої динамічної пам'яті визначає покажчик HEAPPTR. До початку роботи програми застосування HEAPPTR = HEAPORG. При запитах в програмі додаткової (динамічної) пам'яті необхідна частина адресного простору забирається з купи, а покажчик HEAPPTR нарощується на необхідне число байт.

10.2. Динамічне виділення пам'яті. Типи покажчиків 

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

На Паскалі пам'ять під будь-яку динамічно розміщувану типізовану змінну виділяється процедурою NEW(<имя_типізованого_показчика>), яка в покажчику повідомляє програмі адресу цієї динамічно виділеної області, і просуває покажчик вільної області купи   HeapPtr у бік великих адрес на необхідне число байт. Сам покажчик – це дві комірки типу word . Перше слово (word, 2 байти) – це сегмент (старша частина) адреси, а друге слово – зсув об'єкту, що адресується, в межах сегменту.

При необхідності можна набути значень сегменту і зсуву для будь-якого, у тому числі - динамічно створеного, об'єкту за допомогою функцій SEG(p^) і OFS(p^) відповідно, де p – ім'я покажчика, а p^ - адреса об'єкту, заряджена в покажчик р.

У Паскалі є|наявний| і зворотна функція – створення|створіння| покажчика з|із| двох слів, що містять|утримують| значення сегменту і зсуву|зміщення| адреси об'єкту:

PTR|(SEG,OFS:WORD|): POINTER|

Об'єм пам'яті, що виділяється по new()  , залежить від типу запрошуваних даних. Допустимий будь-який – простий і структурований, тип даних, підтримуваних Паскалем. Це можуть бути одиночні змінні, записи, багатовимірні масиви, у тому числі, масиви записів і т.д.

Розглянемо приклад виділення пам'яті під  матрицю дійсних чисел розміру m рядків х n стовпчиків :

const|

       m=10|; n=100|;

type| 

 tmatr = array[1..m,1..n] of real; {шаблон двовимірного масиву з числом

                                                          рядків- 10 і числом  стовпців -100}

var|

    i,j|: word|;

 matr: ^tmatr; {покажчик для збереження адреси двовимірного масиву        

                                                  типа tmatr, при запуску програми matr:=NIL}

begin|

   new|(matr|); {покажчик matr| заряджений адресою області динамічної

                                  пам'яті   виділеною під двовимірний масив типа|типу| tmatr|}

......

   dispose(matr); {обов’язкове звільнення пам’яті купи!}

   matr:=NIL;

end|.

Покажчик matr заряджає конкретною адресою динамічної пам'яті, взятої з 'купи', за допо-могою виклику процедури NEW(matr).

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

допомогою константи NIL. На рис.10.2, 10.3 наведений приклад використання процедур NEW() і DISPOSE()  і функцій POS(), OFS() з текстом програми і результатом її виконання.

Рис 10.3.

 Як видно|показний| з|із| прикладу|зразка|, в початковому|вихідному| стані|достатку| heapPTR| указує|вказує| на початок купи (початкова адреса купи - в покажчику heapORG|). Тут же продемонстрована можливість|спроможність| зміни вмісту покажчика (до зсуву|зміщення| додали 4). Взагалі, адресна арифметика – це дуже небезпечний інструмент, і для початківців краще їм не користуватися, оскільки|тому що| у вас з'являється|появляється| спокуслива можливість|спроможність| ‘залізти’ в будь-яку точку простору ПОП, у тому числі – оперативну пам'ять резидентних програм ОС.

Далі за допомогою процедури new|() програма виділяє динамічну пам'ять під дві матриці, задані своїми покажчиками matr| і matr1|. Ми бачимо, що покажчик heapORG| залишився без зміни, а heapPTR| наростив свій вміст на величину в байтах, достатню для розміщення цих двох матриць.

Звернення до конкретного елементу (i,j|) матриці з|із| покажчиком matr1| виглядає так:

matr1|[i,j|]^:=pi; {занесення інформації в матрицю} ,       або

rab:=| matr1|[i,j|]^; {використання інформації з|із| матриці }

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

var| p: pointer|;

Використання покажчика, що не типізується, – ще одна лазівка в обхід ‘строгостей’ Паскаля. В розділі 6 ми розглядали запис з варіантами, який дозволяє одну і ту ж область ПОП трактувати як дані одного або іншого типа. Цю ж, і ширшу, можливість ми дістаємо при використанні покажчика, що не типізується. Зарядивши покажчик, що не типізується, адресою з динамічної області, можна привласнити цей покажчик іншому, покажчику, що типізується, і працювати з виділеною областю як з даними певного типа. Ще раз підкреслимо, такі ‘Сі-подібні’ прийоми не відповідають строгому стилю Паскаля і повинні використовуватися з крайньою обережністю.

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

GETMEM|(p, size|)  {резервування пам'яті}

FREEMEM|(p,size|)  {звільнення|визволення| пам'яті}

де    p – ім'я покажчика, що не типізується,

  size| – розмір запрошеної динамічної пам’яті в байтах|визволяє|.

10.3. Використання покажчиків при роботі з|із| процедурами і функціями

На закінчення наведемо практично корисний приклад [1] використання покажчиків для роботи з|із| матрицями надвеликих розмірів.

Як відомо, ДОС- Паскаль для об'єктів будь-якого типа|типу| не може виділяти пам'ять більше 65521 байт. Практично такий об'єм|обсяг| пам'яті запитаний|запросити| в прикладі|зразку| рис.10.2 для кожної з матриць – вже m=110| дає помилку трансляції! Виходом з|із| положення|становища| може бути використання динамічної пам'яті.

Для створення|створіння| в ПОП надвеликої матриці будемо по GETMEM|() виділяти з|із| купи пам'ять під одновимірні|одномірні| масиви - рядки надвеликої матриці. Враховуючи обмеження в 65521 байт, ми зможемо створити рядок з|із| числом елементів в ній типа|типу| real| рівним 65521 div| 6 = 10920 чисел. Кількість таких рядків обмежена розміром купи (HeapOrg| -HeapEnd|),  і залежно від розміру ПОП і довжини одного рядка може бути вельми|дуже| великим.

Створимо список PtrStr-| покажчиків, що не типізуються, з|із| адресами рядків матриці. До окремого елементу усередині|всередині| рядка матриці (число типа|типу| real|) звертатимемося|обертатимемося| за допомогою покажчика pr:^real|, що типізується. Завдання|задача| полягає в заповненні надвеликої матриці випадковими real-числами| і обчисленні|підрахунку| середнього значення по всіх  елементах матриці.

Оскільки ми використовуємо бібліотечний генератор випадкових чисел –  функцію Random, з рівномірним псевдоімовірнісним розподілом дійсних чисел x в діапазоні  0<x<1.0, то слід чекати середнє значення елементів будь-якої  матриці, заповненої в такий спосіб, близьке до 0.5.

Виділимо в підпрограмі, багато разів виконувані групи операндів у вигляді процедури і двох функцій:

  •  GETR|()- функція, що повертає значення елементу матриці
  •   PUTR|() – процедура запису значення в елемент матриці
  •  ADDRR|() – функція отримання|здобуття| адреси елементу матриці.

Приклад|зразок| 10.1:

 Program  BigMatr;

 Uses CRT;

const|

   SizeOfReal=6|; {довжина в байтах змінної речового типа|типу| REAL|}

         m =200; {число рядків матриці}

           n=150|; {число елементів REAL|  в рядку матриці, тобто число стовпців матриці }

var|  

      i,j|  : integer|; {поточні індекси рядка і стовпця}

 PtrStr : array[1..m] of pointer; {масив покажчиків, що не типізуються, для рядків матриці}

        s : real|; { комірка|комірка| накопичення суми}

type   RealPTR= ^Real; { покажчик, що типізується, на змінну REAL}

{*********  Функції і процедури****************************|}

 Function ADDRR(i,j : word) : RealPtr; {отримання адреси елементу матриці}

  begin|

    AddrR:=ptr|(seg|(PtrStr|[i]^),ofs|(PtrStr|[i]^)+(j-1|)*SizeOfReal){обчислюємо|вичисляємо| 

                                                       адресу j-го елемента | |i-го| рядка матриці}

  end|;

Function GETR(i,j: word): real; { набуття значення елементу матриці}

   begin|

      GETR| :=AddrR(i,j|)^ { у змінну-функцію GetR:real| занесли дані, на які

                           указує|вказує| змінна-функція-типізований_покажчик| 

                                                                                        AddrR:^real|}

   end|;

Procedure PUTR(i,j: word; x:real); {занесення значення елементу в матрицю}

   begin|

     ADDRR|(i,j|)^:=x

   end|;

{**********Кінець опису функцій і процедур ***********************}

 Begin {Головна програма}

  for i:=1 to m do         {цикл формування масиву покажчиків

                    рядків матриці і заповнення даними елементів кожного рядка}

    begin|   

      GetMem|(PtrStr|[i],n*SizeOfReal|);{взяли з|із| купи пам'ять для даних

                                                              одного рядка}

      for| j:=1| to| n do| PUTR|(i,j,Random|) {у циклі заносимо випадкові числа в

                                                                 n комірок|комірок| рядка }

    end; {for i..}   { кінець циклу формування масиву покажчиків

                  рядків матриці і заповнення даними елементів кожного рядка}

  s:=0|; {очистили суматор}

  for i:=1 to m do

      for j:=1 to n do s:=s + GETR(i,j);   {подвійний цикл підсумовування  елементів матриці  }

  writeln|(s/(n*m|):12:10);

 End.   {Кінець головної програми}

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

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

Процедури і функції для роботи з динамічною пам'яттю представлені в  Таблиці 10.1

Таблиця 10.1

Формат звернення

Тип результату, що повертається

(для функцій)

Опис

ADDR(X)

POINTER

Повертає адресу аргументу X. Аргумент – змінна будь-якого типа, процедура, функція. Дія функції ADDR аналогічно дії операції узяття адреси -@X

DISPOSE(TP)

- (процедура)

Повертає в купу фрагмент динамічної пам'яті, раніше зарезервований за покажчиком, що типізується, TP.

FREEMEM(p,size)

- (процедура)

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

Size - розмір пам'яті, що звільняється, в байтах.

GETMEM(p,size)

- (процедура)

Резервує за покажчиком p size байтів динамічної пам'яті, що не типізується. Size<= 65521 байт.

MARK(PTR)

- (процедура)

Запам'ятовує  в PTR поточне значення покажчика купи HeapPptr.  Аргумент PTR – покажчик будь-якого типа. Використовується спільно з процедурою RELEASE для звільнення частки купи від PTR до кінця купи.

MAXAVAL

LONGINT

Повертає  розмір в байтах найбільшої безперервної ділянки купи

MEMAVAL

LONGINT

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

NEW(TP)

- (процедура)

Резервує фрагмент купи для розміщення змінної. TP – покажчик, що типізується.

OFS(X)

WORD

Повертає зсув адреси об'єкту X

PTR(SEG,OFS)

POINTER

Формує покажчик, що не типізується, з двох складових – SEG:word (адреса сегменту) і  OFS:word (адреса зсуву в сегменті)

RELEASE(PTR)

- (процедура)

Звільняє простір купи від адреси, поміченої процедурою MARK(PTR) до кінця купи

SEG(X)

WORD

Повертає сегментну частку адреси об'єкту X

SIZEOF(X)

INTEGER

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

Контрольні  питання:

  1.  Розміщення інформаціі *.exe- модуля в оперативній памяті компютера.
  2.  Динамічне виділення памяті, типи покажчиків.
  3.  Як програмувати обробку матриці надвеликих розмірів?
  4.  Процедури і функції для роботи з динамічною памяттю.

Завдання для самостійної роботи

1. Нарисувати  схему алгоритму програми BigMatr (Приклад 10.1)


Розділ 11.  Робота з файлами|виведення|

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

Практично будь-яка, більш-менш складна прикладна програма оперує із зовнішніми даними. Ми знайомі вже з командами введення даних з клавіатури і виводу на екран дисплея. Тепер познайомимося з введенням/виводом даних на зовнішні носії – файли на дисках і потоки даних в каналах так званих логічних пристроїв (консоль, біт-паралельний LPT-порт принтера і біт-послідовні COM-порти телекомунікаційного зв'язку).

11.1. Типи файлів

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

Файловий тип (змінну файлового типу) можна задати в секції var одним з трьох способів:

1)     <имя>=FILE OF<тип>;  {ввод/вивід формату (що типізується)}

2)     <имя>=TEXT;                 {ввод/вивід символьних рядків змінної

                                                                                                      довжини}

3)      <имя>=FILE;                  {безформатний (байтовий) ввод/вивід }

Тут

    <ім'я> - ім'я файлової змінної

<тип> - простий тип (integer, real..) або тип структури,

вказаної в секції TYPE;

FILE OF, TEXT, FILE – резервовані слова, що характеризують тип файлу, а точніше - алгоритм (спосіб) обміну даними програми із зовнішнім носієм.

Відмітимо, що на диску фізичне розміщення інформації для всіх типів файлів  однаково. Диск має декілька несучих поверхонь з доріжками, де зберігаються байти інформації. Байти згруповані в сектори стандартного розміру (старий формат - 512байт/сектор). Інформація кожного сектора захищена CRC – циклічною контрольною сумою. Читання інформації з диска процесор виконує посекторно в свій внутрішній буфер, недоступний програмістові, а потім розподіляє прочитані байти у комірки-змінні програми відповідно до одного з трьох перерахованих вище алгоритмів.

Інформація у файлі, що типізується, записана у вигляді послідовності структур однакового формату. Структурою найчастіше буває запис (record), але може бути і будь-який простий тип (byte, word, integer, real, string)  або структурований тип (array, record). Жорстка структура файлу, що типізується, забезпечує довільний доступ до інформації  будь-якого запису подібно зверненню до інформації в ПОП.

Текстовий файл складається з символьних рядків довільної  довжини. Рядок від рядка відділяється ознакою EOLn –ASCII-коди  #13(CR) і #10(LF), що йдуть підряд. Файл закінчується ознакою кінця файлу – кодом #26(EOF). При читанні з символьного файлу даних в ПОП відбувається перетворення числової інформації з символьного у внутрішній (двійковий) вигляд, а символи EOLn і EOF, що управляють, відкидаються. У текстовому файлі можливий тільки послідовний доступ. При послідовному доступі  читання рядків може виконуватися тільки по-порядку, починаючи з першого рядка, а запис – або з початку файлу, або, як доповнення, - в кінець файлу. Крім того, такий ввід/ виведення виконує перетворення чисел з внутрішнього двійкового формату в зовнішній – символьний, що при великих об'ємах інформації може істотно збільшити час виконання програми.

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

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

Нижче приведена програма, що тестує синтаксис визначення файлових змінних f1-f5|.

Приклад|зразок| 11.1:

program ttypFile; { Тест типів файлів}

 type|

   tproduct=record { шаблон-структура запису для файлу, що типізується}

      name| : string|;

      code| : word|;

      cost| : real|;

                     end|;

    t80= file of string[79]; {шаблон для файлової змінної форматного

                                                                                                  вводу/виводу }

var|

   f1: file of char; {файл, що типізується, із структурою char}

   f2|: text|;            {текстовий файл}

   f3|: file|;             {безформатний файл}

   f4|: t80|;             {файл, що типізується, із|із| структурою string|[79]}

   f5: file of tproduct; { файл, що типізується, із структурою tproduct}

 begin| 

{тіло програми}

end|.

В даному прикладі файлові змінні f1|, f4|, f5| характеризують файли, що типізуються (структуровані). Файл f1| має формат char|, тобто крок структури дорівнює одному байту. Файл f4| має формат string|[79], тобто крок структури дорівнює 80 байтам. Файл f5| має формат запису tproduct|. Спробуйте здогадатися, який крок структури в цьому випадку?

Універсально правильна відповідь: крок формату рівний SizeOf|(tproduct|). Якщо Ви так само подумали, значить, Ви чудово засвоїли  попередній матеріал! Ну, а все-таки, чому ж конкретно дорівнює крок структури в f5|? Якщо Ви правильно відповіли і на це питання, то поздоровляємо Вас, колега! Ви вже відбулися як програміст і можете починати|починати| самостійне плавання.

Тепер давайте разом з тими, що не впоралися|справилися| з|із| питанням порахуємо|полічимо|:

довжина поля name| – 256 байтів (пригадаєте, якщо в string| в квадратних дужках не вказана довжина, то за умовчанням довжина рядка приймається рівною 255 байт плюс 1 байт, де вказана довжина рядка)

довжина поля code| – 2 байти

довжина поля cost| – 6 байт.

Разом: крок структури у файлі f5 - 264 байт.

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

Файл f2| – текстовий, до інформації (рядкам) якого можливий тільки|лише| послідовний доступ. Файл f3| визначений як безформатний.

Відмітимо|помітимо|, що файли, що типізуються і безформатні, зберігають інформацію у внутрішньому форматі ПК, тобто без яких-небудь перетворень. Це – типові двійкові файли.

Текстові файли зберігають інформацію в символьному виді кодування ASCII|, де деякі коди-байти розглядаються|розглядають| як управляючі (EOLn|, EOF|). В принципі ми можемо прочитати будь-який файл всіма трьома алгоритмами. Але|та| якщо у файлі, записаному як двійковий (формат або безформатний), зустрінеться байт з|із| кодом  #13|(CR|) або #26|(EOF|), то при читанні  файлу як символьного ці коди, що управляють, в ПОП не будуть передані.

11.2. Доступ до файлів

Для  доступу до файлу або логічного пристрою необхідно виконати дві дії:

  1.  Пов'язати файлову змінну з  ім'ям файлу на диску або ім'ям логічного пристрою|устрою|.
  2.  Виконати відкриття|відчиняти| файлу.

Файлова змінна зв'язується з ім'ям файлу в результаті звернення до стандартної процедури ASSIGN (призначити, англ.):

ASSIGN|(<имя_файлової_змінної>,<ім’я_файлу| або логич.пристрій>);

Ім'я файлу або логічний пристрій – текстовий рядок, що містить ім'я файлу на диску або логічний пристрій. Наприклад, ASSIGN(f5,’D:\ цех1\ Товари на складі’).

Якщо ім'я файлу задається у вигляді порожнього рядка, наприклад, ASSIGN(f5,’’), то залежно від напряму обміну даними файлова змінна зв'язується із стандартним файлом INPUT (ввід даних з клавіатури) або OUTPUT (виведення на екран). Такий прийом дуже зручний при налагодженні програм. Після закінчення налагодження програми необхідно в ASSIGN поставити правильне ім'я файлу. Якщо файл знаходиться в директорії, відмінній від директорії, звідки ми запускаємо нашу *.exe-програму, необхідно указувати повний шлях до файлу, як показано вище.

11.3. Логічні пристрої|устрої|

Стандартні апаратні засоби ПК, такі як клавіатура, екран дисплея, принтер і комунікаційні канали вводу/виводу, визначаються в Турбо Паскалі спеціальними іменами, які називаються логічними пристроями.

CON – логічне ім'я консолі (клавіатура + дисплей).

Введення з клавіатури буферується: символи у міру натиснення клавіш відображуються на екрані дисплея і поміщаються в спеціальний рядковий буфер, який передається програмі тільки після натиснення на клавішу ENTER. Буферизація введення забезпечує можливість редагування рядка до натиснення ENTER.

PRNлогічне ім'я принтера. Якщо до ПК підключено декілька принтерів, доступ до них здійснюється по логічних іменах LPT1, LPT2, LPT3. При одному принтері імена PRN і LPT1 – синоніми.

AUXлогічне ім'я комунікаційного каналу, який зазвичай використовується для зв'язку ПК з іншими машинами. Такий зв'язок зазвичай буває двоспрямованим, але в Паскаль-програмі в кожен момент часу цей логічний пристрій може використовуватися тільки для передачі даних в одному напрямі. Відмітимо, що в Паскаль-програмі можлива двоспрямована робота з перериваннями (тобто без зупинки обчислювального процесу), але це вимагає використання ‘низькорівневих’ функцій типа PORT() і трансляторної директиви INTERRUPT, наявних в інструментарії Турбо Паскаля [1].  

Якщо комунікаційних каналів декілька, то використовуються імена логічних пристроїв COM1, COM2. При одному каналі імена AUX  і  COM1- синоніми.

Приклад|зразок| скріплення|зв'язування| логічного пристрою|устрою| з|із| файловою змінною:

Var| 

 fi|, fo|: text|;

Begin|

Assign|(fi,’AUX|’);

Assign| (fo,’LPT2|’);

.......

End|.

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

11.4. Відкриття |відчиняти| файлу

Процедура відкриття файлу полягає в:

  •  Пошуку на диску файлу, вказаного в процедурі ASSIGN|()
  •  Читанні заголовка файлу і формуванні прихованого від програміста блоку управління даними (БУД) цього файлу, де указується|вказує| тип файлу (тип алгоритму обробки), адреса файлу в FAT-таблиці|, довжина файлу, поточна позиція покажчика і так далі.

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

Є|наявний| три функціонально різні процедури відкриття|відчиняти| файлів (<ф.п.> - ім'я файлової змінної):

  •  RESET|(<ф.п.>);                 {відкриття|відчиняти| файлу для читання}
  •  REWRITE|(<ф.п.>);{відкриття файлу для запису із|із| 

                                стиранням  попередньої інформації  }

  •  APPEND|(<ф.п.>);   {відкриття|відчиняти| текстового файлу для

                            дозапису  нових рядків в кінець файлу }

Процедура RESET() використовується при відкритті всіх трьох типів файлів на читання. Проте тут є деякі тонкощі. У структурованих і безформатних файлах при цьому можливо не лише читання, але і запис. Крім того, при безформатному введенні/виводі в процедурі RESET(,) потрібно указувати другий параметр – довжину запису. Як правило, указується довжина запису рівна довжині сектора (512 байт) або, що більш універсально, одному байтові. Якщо довжину не указувати, то за умовчанням вона приймається рівною 128 байтам. Для безформатного файлу рекомендуємо завжди указувати RESET(…,1).  

При спробі відкрити раніше неіснуючий файл за допомогою RESET() виникає помилка часу виконання 'Runtime error 002' (‘Немає такого файлу’) і програма знімається. Щоб обійти таку ситуацію, можна перед зверненням до RESET() відключити системний контроль за допомогою трансляторної директиви {$I-}, а після RESET() проаналізувати системну змінну IOResult. Ненульовий вміст  IOResult говорить про те, що читання з вказаного файлу неможливе. Зокрема, якщо IOResult=2, то необхідний файл відсутній, і його при необхідності можна створити за допомогою процедури REWRITE(). Застереження! Системна змінна IOResult очищується при першому зверненні до неї. Тому краще забрати її вміст в свою робочу комірку типа integer і далі вже з цією робочою коміркою проводити багатократні операції (аналіз, роздруківка значення).   

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

Процедура APPEND() використовується для дозапису в кінець текстового файлу.  Процедура APPEND() застосовна тільки до текстових файлів, тобто їх файлова змінна повинна мати типа TEXT. Якщо текстовий файл раніше вже був відкритий за допомогою RESET() або REWRITE(), використання процедури APPEND() приведе до автоматичного закриття цього файлу і відкриття його знов, але вже для додавання записів.

11.5. Процедури вводу/виводу|виведення|

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

  •  READ|(<ф.п.>,<сп.вводу>);     {читання даних типізовааних і              

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

  •  READLN|(<ф.п.>,<симв_сп.вводу>);{читання даних

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

  •  BLOCKREAD|(<ф.п.>,<буф>,<NT>[,<NF|>]); {безформатне читання даних із зовнішнього носія},

де  <ф.п.>  - ім'я файлової змінної,

     <сп.вводу> - список змінних введення  - імена змінних через  кому,

<симв_сп.вводу> - список змінних -  імена змінних (типа|типу| char|, string[|], integer|, real| и.т.п.) через  кому; інформація у вхідному рядку має бути розбита на лексеми – смислові групи символів, відокремлених один від одного одним або декількома пропусками|прогалинами|, якщо число запрошуваних змінних менше числа лексем, то лексеми, що залишилися, до кінця рядка пропускаються, а нова операція READLN| починається з першої лексеми нового рядка,

<буф|> - ім'я буфера прийому байтів інформації,

<NT|>  - кількість записів формату, вказаного в RESET|(,) безформатного файлу, які необхідно прочитати за одне звернення|звертання| BLOCKREAD,|

<NF> - кількість записів формату, вказаного в RESET(,) безформатного файлу, які фактично прочитані за одне звернення BLOCKREAD.

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

Оскільки при читанні з файлу або логічного пристрою можливі помилки передачі даних - досить окремий,  але неприємний випадок, рекомендуємо після кожного введення аналізувати на наявність помилки системну змінну IOResult (IOResult<>0), як це описано вище для процедур відкриття файлу. Це ж зауваження стосується і процедур виводу.

Запис даних у файл виконується за допомогою стандартних процедур:

  •  WRITE|(<ф.п.>,<сп.вывода>; {запис інформації  у файл, що  

                                                                        типізується, або текстовий }

  •  WRITELN|(<ф.п.>,<симв_сп.вывода>); {запис інформації  в  

       текстовий файл з додаванням признаку EOLn (коди #13(CR), #10(LF) )}

  •  BLOCKWRITE|(<ф.п.>,<буф>,<NT>[,<NF|>]); {безформатне

                                                      виведення даних на  зовнішній  носій }

11.6. Навігація вводу/виводу|виведення|

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

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

  1.  Функція  FILESIZE|(<ф.п.>); {повертає значення типа|типу| LONGINT| – кількість  компонентів файлу }
  2.  Функція FILEPOS|(<ф.п.>); {повертає значення типа|типу| LONGINT| –порядковий | номер   компоненту файлу, який оброблятиметься наступним|слідуючим| }
  3.  Процедура SEEK|(<ф.п.>,<Nкомп.>); {переміщає покажчик файлу до необхідного компоненту},

де:

   <ф.п.> - ім'я файлової змінної,

Nкомп. – вираз типа LONGINT, вказуючі номер компоненту файлу, до якого необхідно перейти для подальшої обробки. Перший компонент файлу має номер 0.

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

SEEK|(<ф.п.>, FILESIZE|(<ф.п.>));,  де <ф.п.> - ім'я файлової змінної.

11.7. Закриття файлу

Закриття файлу всіх типів виконується однією процедурою:

    CLOSE|(<ф.п.>).

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

Проблема полягає в нерозумінні механізму буферировання вводу/виводу. Ми вже відзначали, що при вводі/виводі інформація змінних безпосередньо не взаємодіє з даними зовнішнього пристрою. Обмін даними відбувається через програмно недоступний проміжний буфер. Він досить великий, і з боку зовнішнього пристрою інформація прочитується групами секторів – так званими кластерами. Причому виконує цей ввод/вивід не наша програма, а програми операційної системи. Обмін же інформацією між проміжним буфером і змінними програми виконується по записах. Це два асихронно виконуваних обчислювальних процеса. Закриття файлу викликає автоматичне примусове ‘виштовхування’ залишків необробленої інформації проміжного буфера в ту або іншу сторону при записі/читанні   даних.

Характерна ситуація: якщо не виконувати CLOSE – втрачається остання порція інформації, що виводиться на диск. Не сподівайтеся на завіряння розробників трансляторів, що досягнення ‘END.’ - кінця програми, автоматично закриває всі відкриті в програмі файли. Це не відповідає дійсності, в чому зможемо переконатися на наведеному нижче Прикладі 11.2.  Не ризикуйте, своєчасно закривайте файли, з якими закінчена робота.

11.8. Процедури і функції для роботи з|із| файлами

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

Таблиця 11.1.

Формат звернення

Тип результату, що повертається

(для функцій)

Опис

CHDIR(<шлях>)

- (процедура)

Зміна поточного каталогу. Тут <шлях> - рядок - шлях до встановлюваного за умовчанням каталога

DISKFREE(<диск>)

LONGINT

Повертає об'єм в байтах вільного простору на вказаному диску. <диск> - номер диска: 0- пристрою по умовчанню,1,2.-  диск А, диск B..

DISKSIZE(<диск>)

LONGINT

Повертає повний об'єм диска в байтах або -1, якщо вказаний номер неіснуючого диска

EOF(<ф.п.>)

BOOLEAN

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

ERASE(<ф.п.>)

- (процедура)

Знищує файл. Якщо файл був відкритий, то перед виконанням процедури його необхідно закрити.  

FEXPAND(<файл>)

STRING[79]

Повертає файлове ім'я <файл>:string[79], доповнене повним шляхом  до поточного каталога

FLUSH(<ф.п.>)

- (процедура)

Примусово ‘виштовхує’ дані внутрішнього буфера на диск навіть якщо буфер не повністю|цілком| заповнений (см.CLOSE).

Процедура ігнорується, якщо файл був відкритий процедурою RESET.

FSEARCH(<имя>,<сп.кат>)

STRING[79]

Шукає файл в списку каталогів. Тут <ім'я> - ім'я файлу – рядковий вираз,<сп.кат>)- список каталогів - рядковий вираз з іменами каталогів, розділених крапкою з комою.

GETDIR(<вуст.>,<кат.>)

- (процедура)

Визначення імені поточного каталога. Тут <вуст.> - номер дискового пристрою (0,1,2.), <кат.> - змінна типа STRING, в якій повертається шлях до поточного каталогу на вказаному диску.

GETFATTR(<ф.п.>,<атриб.>)

- (процедура)

Дає атрибути файлу в молодшому байті <атриб.>):WORD

GETFTIME(<ф.п.>,<час>)

- (процедура)

Дає час створення або останнього оновлення файлу в змінній. <час>): LONGINT в упакованому форматі (див. по HELP Турбо Паскаля (Ctrl+F1) опис процедури PACKTIME).

IORESULT

WORD

Повертає код завершення останньої операції вводу/виводу. IORESULT=0 – операція завершилася успішно. Для аналізу IORESULT перед операцією вводу/виводу необхідно відключити системний контроль за допомогою трансляторной директиви {$I-}, а після аналізу коду завершення включити системний контроль директивою {$I+}

MKDIR(<каталог>)

- (процедура)

Створює новий каталог на вказаному диску. Тут <каталог>-| 

вираз типа STRING, що задає шлях до створюваного каталогу.

RENAME(<ф.п.>,<нов.им’я>)

- (процедура)

Перейменовує файл. Тут <нов.имя> - рядкове вираз, що містить нове ім'я файлу.

RMDIR(<каталог>)

- (процедура)

Видаляє каталог. Каталог, що видаляється, має бути порожнім.

SETFATTR(<ф.п.>,<атриб.>)

- (процедура)

Встановлює атрибути файлу (див. GETFATTR)

SETFTIME(<ф.п.>,<час>)

- (процедура)

Встановлює нову дату створення або оновлення файлу. Це архаїзм, оскільки час створення/корекції файлу встановлюється автоматично засобами ОС.

11.9. Комплексний приклад|зразок| роботи з|із| файлами

Проілюструємо все викладене вище. Наприклад, необхідно сформувати відомість на отримання стипендії  Вашої групи. Для цього Вам необхідно мати:

  1.  Нормативно-довідкову інформацію - файл ‘ФІО’ студентів групи, що типізується, де компонентом буде запис:

TYPE|   TFIO=| RECORD|

      FIO|: string|[40]; {Прізвище_ им’я_| по батькові студента}

   Nstud|: word|; {ключ|джерело|-ідентифікатор студента – номер залікової книжки}

                        END|;

  1.  Оперативну інформацію, що щомісячно поступає|надходить| з|із| бухгалтерії - типізований файл нарахованої стипендії ‘Стипендія’, де компонентом  буде запис:

TYPE|   Tstpnd=RECORD|

                   Nstud|: word|; { номер залікової книжки студента }

                   Stpnd|: real|;    {нарахована стипендія}

                         END|;

Послідовно виконаємо кроки:

  1.  Формування і запис на диск файлу ‘ФІО’, що типізується (файл нормативно-довідкової інформації).
  2.  Читання з диска файлу ‘ФІО’ і формування масиву TabStpnd|.
  3.  Запис TabStpnd| у файл, що типізується, ‘Стипендія’ (файл оперативної інформації).
  4.  Формування платіжної відомості і запис її в текстовий файл ‘Відомість’.
  5.  Читання з|із| текстового файлу  ‘Відомість’ і ‘роздрук|роздруківка|’ платіжної відомості на екрані дисплея.


Приклад
|зразок| 11.2:

program| VedomStp|; {П-ма формування відомості на щомісячне нарахування стипендії }

 uses|  crt|;

 const| m=4|;

     FFio:array|[1..m] of| string|[40]=('Савченко Л.П.','Сидоренко В.Я.'

      'Щербашин Ю.Д.','Мірошниченко І.В.');{список студентів}

TYPE|

  TFIO=RECORD|

   FIO|: string|[40]; {Прізвище_ им’я_| по батькові студента}

 Nstud|: word|; {ключ|джерело|-ідентифікатор студента – наприклад, номер залікової книжки}

             END|;

Tstpnd=RECORD|

 Nstud|: word|; {ключ|джерело|-ідентифікатор студента – наприклад, номер залікової книжки}

 Stpnd|: real|;    {нарахована стипендія}

             END|;

 var|

   f1|: file| of| TFIO|;   {файл нормативно-довідковій інформації}

   f2|: file| of| Tstpnd|; {файл оперативних даних}

   f3|: text|;                 {файл з|із| текстом відомості}

   z1|: TFIO|;              {робочий запис для f1|}

   z2|: Tstpnd|;            {робочий запис для f2|}

   z3|: string|;              {робочий запис для f3|}

   TabStpnd:array|[1..m] of| TStpnd|; {робочий масив в ПОП для формування інформації f3|}

n: word|; {фактичне число записів у файлі ‘ФІО’}

 i: word|; {змінна циклу – індекс елементу масиву}

 begin|

clrscr|; randomize|; {очищення екрану; зміна стартового числа генератора випадкових чисел}

{**************** STEP1| ***************************************}

 assign|(f1|, 'ФІО'); {прив'язка файлової змінної до конкретного файлу}

 rewrite|(f1|);            {відкриття|відчиняти| файлу на запис}

 for| i:=1| to| m do|

  begin| {формуємо запис для виводу|виведення| в f1|}

   z1|.fio:=ffio[i];

   z1|.Nstud:=random(10000)+1;{ідентифікатор студента (випадкове число)}

   write|(f1,z1|);        {запис на диск}

  end|;

 close|(f1|);  {файл ФІО на диску сформований}

{*************** STEP2| ***************************************}

 reset|(f1|);{знову відкрили|відчиняли| f1|} {read|(TabFio|);  не може так читати!}

i:=0|;     {}

writeln|; {пробільний рядок на екрані}

 while| not| eof|(f1|) do| {читаємо з|із| файлу і пишемо в масив,цикл виконується,

                                     поки|доки| не зустрінемо  EOF-| ознака кінця файлу}

 begin|

  inc|(i);          {інкремент i=i+1|}

  read|(f1,z1|); {читання запису з|із| файлу нормативно-довідковій інформації      

                        (НДІ)}

  TabStpnd|[i].Nstud:=z1.Nstud; {перенесення|перенос| поля ‘Номер студента’ із|із|   

                                 запису НДІ в масив-таблицю}

  TabStpnd|[i].Stpnd:=random*1000-200; {стипендія (випадкове число)}

  writeln|(z1|.fio:20,z1.nstud:8); {вивід|виведення| на екран запису НДІ}

 end|;

 n:=i|;{скільки записів прочитано з|із| файлу в масив TabStpnd|}

  close|(f1|);

{************ STEP3| ***************************************}

 assign|(f2,'Стипендия|');

 rewrite|(f2|);

 writeln|; {пробільний рядок на екрані}

 for| i:=1| to| n do|

  begin| {формуємо запис для виводу|виведення| в f2|}

   z2:=TabStpnd|[i];

   write|(f2,z2|);{запис на диск}

   writeln|(z2|.Nstud:4, z2|.stpnd:10:2);

  end|;

  close|(f2|);{була помилка, без цієї команди інформація

             на диск виводилася без хвоста - без півтора рядків!}

{************* STEP4| ***************************************}

 assign|(f3,'Ведомость|');

 rewrite|(f3|);

 writeln|(f3|',        Відомість нарахування стипендії');    {Запис в символьний

                                       файл f3| рядків з|із|  заголовком і шапкою документа}

 writeln|(f3|);

 writeln|(f3,'-----T-------------------T------T----------------¬|');

 writeln|(f3,'|Nп/п|         ФІО       |Таб.№ |  сума на руки |');

 writeln|(f3,'+----+-------------------+------+----------------+|');

 reset|(f1|); {знов|знову| відкрили|відчиняли| файл НСИ для читання}

 i:=0|;

 while| not| eof|(f1|) do|

  begin|

   inc|(i);

   read|(f1,z1|); {читаємо запис НСИ}

 writeln|(f3,'|',i:3|'.|',z1.fio:19,'|',TabStpnd[i].Nstud:5', |',

            TabStpnd[i].Stpnd:16:2,'|'); { пишемо в f3 символьний рядок}

  end|;

writeln(f3,'L----+-------------------+------+-----------------');{ низ рамки                                                                                                                                                     

                                                                                            документа}

 close|(f1|);

 close|(f3|);

 writeln|; {два пробільні рядки на екрані}

 writeln|;

{********************** STEP5| *****************************}

 reset|(f3|); {відкрили|відчиняли| символьний файл  ‘Відомість’ на читання}

   i:=0|;

 while| not| eof|(f3|) do|

  begin|

   inc|(i);

   readln|(f3,z3|);{читаємо з|із| файлу символьний рядок}

   writeln|(z3|);   {виводимо її на екран (принтер)}

  end|;

   close|(f3|);

{********* Завершення програми *****************************}

  readln|;

end|.

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

Рис.11.1

Контрольні  питання:

  1.  Типи файлів. 
  2.  Доступ до файлів.
  3.  Логічні пристрої. 
  4.  Відкриття файлу.
  5.  Процедури вводу/виводу.
  6.  Навігація вводу/виводу.
  7.  Закриття файлу. Важливість закриття файлів.
  8.  Процедури і функції для роботи з файлами.   

 

Завдання для самостійної роботи

1. Нарисувати блок-схему програми Прикладу 11.2


Розділ 12. Елементарні функції графіки

12.1. Формування зображень на екрані дисплея

Екран дисплея утворений матрицею крапок, що світяться, званих пікселями. Світимістю пікселів можна управляти. У кольорових дисплеях піксель складається з тріади близькорозташованих точок червоного, зеленого і блакитного світіння (RGB – red, green, blue,англ). Управляючи інтенсивністю цих трьох основних кольорів, можна отримувати всі відтінки спектру – від чорного (немає світіння точок тріади) через чисті барви веселки і їх відтінки до білого (однакова інтенсивність світіння точок тріади).

Роздільна здатність екранів сучасних дисплеїв настільки  велика, що неозброєним оком неможливо розгледіти окремі пікселі, не говорячи вже про три точки RGB в кожному пикселі. Матриця пікселів  мого (не дуже сучасного) дисплея має 1536 рядків з 2048 пікселями в кожному рядку.

Кількість градацій світіння пікселя залежить від способу використання розрядності відеопам'яті. Колірний відтінок пікселя може описуватися:

  1.  1 байтом (256 градацій кольору|цвіту|)
  2.  2 байтами (65535 колірних відтінків, т.з. High Color)
  3.  4 байтами (True Color)

У ‘старовинному’ Тубо Паскалі 7.0, коли ще не було багатих можливостей|спроможностей| сучасних дисплеїв, максимальна роздільна здатність була обмежена на рівні 640 пікселів х 480 рядків. На сучасному комп'ютері ‘старовинний’ піксель автоматично моделюється невеликою матрицею (наприклад, 4х4) реальних пікселів.

Другим, істотнішим|суттєвим|, обмеженням Тубо Паскаля 7.0   є|з'являється| обмеженість колірної палітри. Є|наявний| всього 16 градацій кольору|цвіту|, який задається системними константами, що типізуються:

Таблиця 12.1

Ім'я константи

Значення

                            КОЛІР

Black

=

0

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

Blue

=

1

темно-синій

Green

=

2

темно-зелений

Cyan

=

3

бірюзовий

Red

=

4

червоний

Magenta

=

5

фіолетовий

Brown

=

6

коричневий

LightGray

=

7

світло-сірий

DarkGray

=

8

темно-сірий

LightBlue

=

9

синій

LightGreen

=

10

ясно-зелений

LightCyan

=

11

ясно-бірюзовий

LightRed

=

12

рожевий

LightMagenta

=

13

малиновий

Yellow

=

14

жовтий

White

=

15

білий

Додавання старшого біта до байта константи-кольору  (збільшення числа на128) викликає мигтіння об'єкту, намальованого цим кольором.

Для програмування в графічному режимі фірма|фірма-виготовлювач| Борланд розробила універсальну бібліотеку процедур і функцій  GRAPH|.TPU. Цю бібліотеку необхідно згадати в секції  Uses|  Вашої головної|чільної| програми (Uses| CRT|, GRAPH|;). Безпосередньо для управління дисплеєм на фізичному рівні фірма|фірма-виготовлювач| Борланд розробила гаму драйверів, з|із| яких ми на сучасних дисплеях можемо використовувати найдосконаліший|довершений| на той час драйвер EGAVGA|.BGI.

При програмуванні графіки на Тубо Паскалі дисплей переходить з|із| текстового режиму в графічний за допомогою процедури InitGraph|(), а після|потім| виконання процедури CloseGraph| повертається в текстовий режим. Можливе тимчасове повернення в текстовий режим із|із| збереженням|зберіганням| всіх параметрів графічного режиму і збереженням|зберіганням| в пам'яті графічного драйвера EGAVGA|.BGI за допомогою процедури RestoreCrtMode|. Для повернення в графічний режим в цьому випадку використовується процедура SetGraphMode|.

Підпрограми бібліотеки   GRAPH|.TPU  можуть виконувати наступні|слідуючі| дії:

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

12.2. Ініціалізація графічного режиму

Ініціалізація графічного режиму виконується за допомогою звернення до процедури InitGraph(  ). Заголовок цієї процедури має вигляд:

Procedure| InitGraph|(var| Driver,Mode:integer|; Path:String|);

Тут Driver - ціле число (0, 1..,10) тип графічного драйвера; 0 – автовизначення доступного в даній системі драйвера (завжди використовувати в сучасних дисплеях!)

 Mode – режим роботи вибраного графічного драйвера (0, 1..,5); використовувати 2- високий дозвіл VGAHi (640пикселей x 480строк)  

        Path – рядок-константа з символьним ім'ям драйвера і, можливо, повним  маршрутом; порожній рядок (‘’) означає що драйвер EGAVGA.bgi у поточній директорії, де знаходиться|перебуває| виконувана *.exe-программа.

Приклад|зразок| ініціалізації графічного режиму:

InitGraph| (0, 2,' ');{драйвер EGAVGA|.bgi – в директорії виконуваної програми},

або так:

 var| driver|, mode|: integer|;

Driver:=| DETECT|; {константа DETECT=0|}

Mode:=| VGAHI|;     {константа VGAHI=2| }

InitGraph| (Driver|, Mode| ,’d:\TP7min\egavga.bgi’); {драйвер – в корені

                                                                                     директорії TP7min|}

Контроль виконання процедур графіки виконується за допомогою функції GraphResult. Ознакою успішного виконання процедури графіки, зокрема InitGraph(), є нульове значення GraphResult. Коди помилок, що повертаються функцією GraphResult, - негативні числа -1, -2,., -14,  можуть бути розшифровані по HELP Турбо Паскаля цієї функції (Ctrl+F1).

Найчастіше причиною виникнення помилки при зверненні до процедури InitGraph|() є|з'являється| неправильна  вказівка шляху|дорозі| до драйвера EGAVGA|.bgi. У дистрибуції Турбо Паскаля цей драйвер знаходиться|перебуває| в піддиректорії  ..\BGI. Там же знаходяться|перебувають| штрихові шрифти графічного режиму *.chr. У нашій мінімізованій версії TP7min| драйвер EGAVGA|.bgi ми помістили в корінь директорії. Те, що в цілях економії оперативної пам'яті драйвер підвантажується динамічно, часто буває незручним, коли Ви їдете з|із| демонстраційним прикладом|зразком| на чужий комп'ютер. Зручніше помістити копію драйвера і штрихові шрифти в директорію виконуваного модуля (*.exe-программы)

Так само, як у функції IoResult перевірки файлового вводу/виводу, після звернення до GraphResult ознака помилки скидається. Повторне звернення до GraphResult поверне нульовий код завершення, тому для багатократного використання коду завершення необхідне перше звернення до цієї функції запам'ятати в робочій комірці.

12.3. Координати, сторінки, вікна

Положення покажчика в графічному режимі визначається відносно початку координат - лівого верхнього кута екрану дисплея (координати - 0,0). Перше число - зсув в пікселях відносно початку координат по горизонталі, друге число – зсув в пікселях по вертикалі.

Максимальне значення координат екрану можна визначити, використовуючи GetMaxX і  GetMaxY - функції типа word. Поточне положення курсору визначається за допомогою функцій GETX і GETY.

Процедура GetAspectRatio(var x,y:word) повертає у комірках x,y два числа, що дозволяють оцінити співвідношення сторін екрану в пікселях для правильної побудови кіл і квадратів. Наприклад, якщо Ви хочете побудувати квадрат із стороною L пікселів по вертикалі, то це робиться так:

Var| x1,y1,L,dim,high:word|;

GetAspectRatio|(dim|, high|);

Rectangle|(x1,y1|{лівий верхн.кут} (x1+round|(L*| high/dim) (y1+L|){прав.нижн.кут});

Процедура MoveTo(x,y:integer); встановлює покажчик в піксель з координатами (x,y). Процедура MoveRel(DX,DY:integer); переміщає курсор на (DX,DY) пікселів щодо поточного пікселя.

Процедура ClearDevice очищає екран кольором фону, заданим процедурою SetBkColor(см.ниже).

Відеоплата, що управляє формуванням зображення на екрані, має декілька сторінок відеопам'яті. Кожна сторінка відеопам'яті – це віддзеркалення в ПОП матриці пікселів всього екрану. Переадресовуючись по сторінках відеопам'яті, можна дуже швидко змінювати 'картинки' на екрані, створюючи ефект анімації зображення. Процедура SetActivePage(PageNum:Word) робить активною вказану сторінку. PageNum- номер сторінки -  0 або 1. Всі подальші операції вводу/виводу виконуються на цю активну (як правило, невидиму) сторінку. Неприємним обмеженням в бібліотеці GRAPH.TPU Турбо Паскаля є той факт, що при максимальній розподільчий здатності екрану є тільки одна сторінка. Тому для анімації доводиться знижувати розподільчу здатність екрану, зменшивши на 1 число у комірці mode (див. вище Initgraph) і переустановивши графічний режим зниженої розподільчої здатності за допомогою процедури  SetGraphMode(mode:integer), де mode=VGAHi-1.

Після сформування зображення на активній сторінці її можна зробити видимою за допомогою процедури SetVisualPage(PageNnum:word).

В межах кожної сторінки  за допомогою процедури SetVievPort(X1,Y1,X2,Y2:integer;ClipOn:Boolean) можна створювати графічні вікна екрану. Тут (X1,Y1) – координати повнорозмірного екрану верхнього лівого кута вікна, (X2,Y2) - координати нижнього правого кута, Clipon=true – обрізання зображення, що не уміщається у вікні, Clipon=false – немає обрізання. Відлік координат у вікні – від верхнього лівого кута.

Процедура ClearVievPort очищає вікно кольором фону, який в даний момент встановлений процедурою SetBkColor (см.нижче).

12.4. Малювання простих фігур

Процедура  PutPixel(X,Y:integer; Color: word) малює точку кольору Color у позиції (X,Y) екрану. Функція GetPixel(X,Y:integer):word повертає колір пікселя запрошуваної точки екрану.

Процедура  SetColor(Color: word) встановлює поточний колір для ліній, що виводяться, і символів. Функція GetColor: word повертає код  поточного кольору.

Процедура  Line(X1,Y1,X2,Y2:integer) малює лінію між крапками (X1,Y1) і (X2,Y2). Лінія викреслюється поточним кольором і поточним стилем.

Процедура LineTo(X,Y:Integer); малює лінію між поточним положенням курсора і крапкою (X,Y). Процедура зручна для малювання графіків.

Процедура  LineRel(DX,DY:integer) малює лінію від поточної позиції курсору до крапки, віддаленої від поточної на (DX,DY) пікселів.

Процедура  SetLineStyle(Type, Pattern, Thick: word)  встановлює новий стиль викреслювання ліній. Тут Type, Pattern, Thick – відповідно тип, зразок і товщина лінії. Тип лінії задається за допомогою однієї з наступних глобальних іменованих констант, визначених в GRAPH.TPU:

const|

Solidln|    = 0; {суцільна лінія}

DottenLn| =1; {точкова лінія}

CenterLn| =2; {штрих-пунктирная| лінія}

DashedLn=3|; {пунктирна лінія}

UserBitLn=4|; {узор|візерунок| лінії визначає користувач}

Параметр Pattern|  має ненульове значення тільки|лише| для ліній 4-го типа|типу| (призначених для користувача). Кожному з 16 біт цього слова відповідає піксель, що світиться (1) або не світиться (0). Цей зразок|взірець| періодично повторюється по всій довжині лінії.

Параметр Thick| може приймати одне з двох значень: 1 або 3. Для підвищення наочності|наглядний| тексту програми можна використовувати  глобальні іменовані константи, визначені  в модулі Graph| так:

const|

NormWidth| =1;{товщина в один піксель}

ThickWidth| =3;{товщина в три пікселі}

Процедура SetWriteMode(mode:integer) встановлює спосіб взаємодії ліній, що знов виводяться, із зображенням, що вже є на екрані. Якщо mode=0, то піксель лінії, що знов виводиться, заміщає піксель старого зображення (нова лінія виходить на передній план). Якщо mode=1, то піксель лінії взаємодіє з пікселем старого зображення за правилом того, що ‘виключає або’ (XOR). Повторне виведення лінії відновлює значення пікселя старого зображення, тобто старе зображення виходить на передній план. Режим що ‘виключає або’ використовується при анімації, коли необхідно рухомий об'єкт провести  'ззаду ' предметів нерухомого фону.

Процедура Rectangle(X1,Y1,X2,Y2:integer) викреслює прямокутник лівий верхній кут якого має координати (X1,Y1), а правий нижній – координаты(X2,Y2). Прямокутник викреслюється з використанням поточного кольору і поточного стилю ліній.

Процедура DrawPoly(n:word; var Points) викреслює ламану лінію, задану масивом  Points записів типа:

Type                                  {У Вашій програмі PointType        }

   PointType=record|          { можна не описувати                       }

                        x,y| : word|; {а відразу використовувати                        }

                      end|;             {у var| для опису масиву записів}

Тип визначений як глобальний в модулі GRAPH|, і його в програмі можна використовувати без визначення в секції TYPE|, тобто відразу в секції var| описувати масив типа|типу| PointType|:

var Points: array[1..n] of PointType;

Тут n-| число точок-зламів ламаної лінії, включаючи дві крайні крапки|точки|. При викреслюванні використовується поточний колір|цвіт| і поточний стиль лінії.

DrawPoly| – зручний засіб формування рухомих об'єктів складної конфігурації. Для цього досить змінити|зраджувати| на одну і ту ж величину координату x  (або біля|в|, або х і біля|в|) в записах Вашого масиву  Points|.

Процедура Circle(X,Y:Integer; R:word) викреслює коло радіусом R з центром в крапці (X,Y). Коло виводиться поточним кольором, товщина її встановлюється поточним стилем.

Процедура ARC(X,Y:integer; BegA,EndA,R:word) креслить дугу кола радіусу R з центром в (X,Y). Тут BEGA – кут зачала дуги,  ENDA – кут кінця дуги. Кути в градусах відлічуються від горизонтальної осі проти годинникової стрілки.

Процедура Ellipse(X,Y:integer;BegA,EndA,RX,RY:word) викреслює дугу еліпса з центром в (X,Y)  і напівосями RX,RY.

12.5. Управління кольором|цвітом|

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

Процедура SetColor(Color:word) встановлює поточний колір лінійі символів, що виводяться. Color – код кольору (див. Табл.12.1).

Процедура SetBkColor(Color:word) встановлює колір фону всього екрану або поточного вікна екрану.

Процедура SetFillStyle(Fill,Color:word) встановлює стиль (тип і колір) заповнення замкнутих фігур. Тут (Fill) – тип (узор) заповнення, Color- колір. Узор кодується числами 0..12, що відповідає заповненню закрашуваного простору різними символами. Докладнішу інформацію можна отримати по Help (Ctrl+F1) символьного редактора Турбо Паскаля.

Процедура FloodFill(X,Y:integrt; Border:word) заповнює довільну замкнуту фігуру, використовуючи поточний колір і узор. Тут (X,Y) – координати будь-якої точки усередині замкнутої фігури, Border- колір кордону. Якщо фігура не замкнута, заповнення 'розіллється' по всьому екрану. Процедура працює повільно. Розробник рекомендує по можливості використовувати менш універсальну процедуру  FillPoly() – закрашування замкнутого багатокутника. Для закрашення прямокутників ефективно використання процедури Bar(X1,Y1,X2,Y2:integer).

Для стовбчастих діаграм із закрашеною передньою гранню паралелепіпеда можна використовувати процедуру Bar3D(X1,Y1,X2,Y2,Depth:integrer;Top; boolaen). Тут Depth-глибина паралелепіпеда, Top=true – малюється верхня грань паралелепіпеда, Top=false -  верхня грань паралелепіпеда не малюється.

Процедура FillElipse(X,Y,RX,RY: integer)  обводить лінією і заповнює еліпс. Тут (X,Y) – центр еліпса, (RX,RY) – напівосі еліпса. Еліпс обводиться лінією кольору і товщиною, заданих процедурами SetColor і SetLineStyle, а заповнюється відповідно до параметрів процедури SetFillStyle(см.выше).  

Процедура Sector(X,Y:integer; BegA,EndA,RX,RY: word) виводить закрашений еліпсний сектор. Процедура зручна для відображення 3D кругових діаграм. Процедура PieSlice(X,Y,:integer; BegA,EndA,R: word) виводить закрашений сектор кола. Процедура зручна для відображення плоских кругових діаграм.

12.6. Виведення тексту

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

На жаль, в графічному режимі не автоматизований процес виведення числових даних, як це має місце в процедурах  WRITE(), WRITELN() текстового режиму. Тому перед виведенням числових даних на екран доводиться заздалегідь за допомогою процедури STR(X [:WIDTH [:DECIMALS]],ST) (див. Розділ 5, Таблиця 5.6) переводити число X з двійкового (машинного) формату в символьний рядок ST.

Процедура OutText(ST: string) виводить на екран текстовий рядок в поточну позицію курсору (курсор в графічному режимі на екрані не відображується!). Процедура OutTextXY(X,Y: integer;ST: string) виводить на екран текстовий рядок в позицію (X,Y).

Процедура SetTextStyle(Font,Direct,Size: word) встановлює стиль тексту, що виводиться на екран. Тут Font – номер (код) шрифту, Direct – код напряму, Size – код розміру шрифту.

Для вказівки коду шрифту можна використовувати глобальні іменовані константи з|із| бібліотеки GRAPH|:

Таблиця 12.2

Код шрифту

Іменована константа в GRAPH.tpu

Ім'я файлу шрифту в директорії ..\BGI

Опис шрифту

0

DefaultFont

-

Матричний шрифт 8х8. Використовується за умовчанням або за відсутності файлу вказаного шрифту. Русифікований

1

TriplexFont

TRIP.chr

Потрійний шрифт

2

SmallFont

LITT.chr

Зменшений шрифт. Русифікований

3

SanSerifFont

SANS.chr

Прямий шрифт

4

GothicFont

GOTH.chr

Готичний шрифт

5

SCRI.chr

‘Рукописний’ шрифт

6

SIMP.chr

Одноштріхової шрифт типа Courier

7

TSCR.chr

Красивий похилий шрифт типа Times Italic

8

LCOM.chr

Шрифт типа Times Roman

9

EURO.chr

Шрифт типа Courier збільшеного розміру

10

BOLD.chr

Крупний двохштриховий шрифт

Для завдання напряму видачі тексту (Direct) можна використовувати вбудовані константи:

const| 

 HorizDir| = 0; {Зліва-направо}

 VertDir|   = 1; {Знизу-вгору|угору|}

Розмір шрифту, що виводиться, кодується параметром Size, який може мати значення в діапазоні 1..10.

Процедура SetTextJustify(Horiz,Vert:word) задає вирівнювання тексту щодо положення курсору (точніше, положення курсору щодо тексту):

const|

 LeftText|     = 0; {Покажчик зліва від тексту}

CenterText| = 1; {Симетрично зліва|ліворуч| і справа, зверху і знизу}

RightText|   = 2; {Покажчик праворуч від тексту}

BottomText=| 0; {Покажчик під текстом}

TopText|     = 2; {Покажчик над текстом}

    12.7. Анімація

 Турбо Паскаль 7.0 дозволяє 'переміщати' зображення об'єкту по екрану дисплея. Така анімація досягається стиранням попереднього зображення об'єкту і малювання його знов на новій позиції. Стирання здійснюється промальовуванням об'єкту кольором фону (код кольору =0). Розглянемо основні процедури анімації.

Процедура GetImage(X1,Y1,X2,Y2: integer;var Buf) поміщає в буфер Buf  піксельну інформацію прямокутного фрагмента екрану, визначуваного координатами X1,Y1( лівий верхній кут фрагмента) і  X2,Y2 (правий нижній  кут фрагмента). Буфер повинен мати достатній розмір (див.нижче ImageSize), щоб помістити пікселі об'єкту.

Процедура PutImage(X,Y: integer; var Buf; Mode: word) виводить з буфера в задане місце екрану копію фрагмента зображення.

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

const|

 NormalPut| = 0; {Заміна існуючого зображення на копію}

 XorPut|      = 1; {Виключаюче АБО (складання бітів по модулю 2)}

OrPut|        = 2; {Логічне АБО}

AndPut|      = 3; {Логічне І}

NotPut|       = 4; {Інверсія  зображення}

Режим  0 просто заміщає  прямокутний фрагмент екрану на нове зображення.

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

Функція ImageSize(X1,Y1,X2,Y2:integer):word повертає розмір пам'яті в байтах, необхідний для розміщення прямокутного фрагмента зображення.

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

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

Рис 12.1

Контрольні  питання:

  1.  Що таке ‘піксель’, з чого він складається? Розподільча здатність екранів сучасних дисплеїв і як вона використовується в Turbo Pascal’і.
  2.  Ініціювання графічного режиму, відлік координатних осей, управління переміщенням курсора малювання.
  3.  Малювання простих геометричних фігурю
  4.  Вивід тексту в графічному режимі.
  5.  Анімація.

Завдання для самостійної роботи

  1.  Розробити та налаштувати програму мультиплікаційного руху фігури, вид якої  задає викладач для кожного студента окремо. Рух фігури управляється з клавіатури курсорними стрілками (,,,). Обмежити рух фігури так, щоб при русі фігура не виходила за межі екрану.
  2.  Розробити та налаштувати мультиплікаційну гру «Перегони моторних лодок». Лодки стартують по черзі і повинні за найкоротший час оминути острів і досягти лінії фінішу. Поточний напрям пересування лодки повинен співпадати з її віссю симетрії.


РЕКОМЕНДОВАНА  ЛІТЕРАТУРА

  1.  Фаронов В.В. Тубо Паскаль 7.0. Начальный курс.Учебное пособие.-М.:”Нолидж”, 2001, -576с.
  2.  Фарoнoв В. В. Turbo Pascal:Учебное пособие. –СПб.: ”Питер”,  2006.- 368 стр.
  3.  Керниган Б., Ритчи Д. Язык программирования С. Изд.2-е переработанное и дополненное. –М., СПб.,Киев: “Вильямс”, 2007. -304 с.
  4.  Шилдт Г. С++.Базовый курс. –М., СПб.,Киев: “Вильямс”, 2007. -624 с.
  5.  Павловская Т.А. С# . Программирование на языке высокого уровня. Учебник для вузов. –СПб.:”Питер”,2007.-432 с.
  6.  Архангельский А.Я. Программирование в DELPI. Учебник по классическим версиям Delphi. –М.:”Бином”,2006.-1152 с.
  7.  Архангельский А.Я., Тагин М.А. Программирование в С++Builder 6 и 2006. – М.:”Бином-пресс”,2007.-1184 с.
  8.  Троелсен Э. C# и платформа .NET. –СПб.:”Питер”,2006.-796с.
  9.  Шилдт Г. Полный справочник по C#. –М.:”Вильямс”, 2008.-752 с.
  10.  Тихомиров Ю. Visual C++ 6. –СПб.:BHV-Петербург,1999.-496 с.
  11.  Сайлер Б.,Споттс Д. . –М.:“Вильямс”,2007.- 832 с.
  12.  Брукс Ф. Мифический человеко-месяц или как создаются программные комплексы. -М.:Символ-Плюс,2000.-304 с.
  13.  Пильщиков В.Н. Программирование на языке Ассемблера IBM PC. –М.:”Диалог-МИФИ”,2001,-288 с.
  14.  Гук М. Аппаратные средства IBM PC – СПб: Питер, 1996.- 224 с.
  15.  Пахомов Б. Самоучитель С/С++ и Borland C++Builder 2006. – СПб.:БХВ-Петербург,2006.-576 с.
  16.   В.Н.Пильщиков. Сборник упражнений по языку Паскаль.–М: «Наука», 1989. -160 с.


Додаток А

Індивідуальні завдання для виконання компютерних практикумів [16]

Розділ 4. Знайомство з мовою Паскаль

№ вар.

1

2

3

4

5

6

7

8

9

10

11

12

13

Вправа [16]:

3.1

3.2

3.3

3.4

3.5

3.6

3.7

3.8

3.9

3.10

3.11

3.12

3.13

№ вар.

14

15

16

17

18

19

20

21

22

23

24

25

26

Вправа [16]:

3.14

3.15

3.16

3.17

3.18a,b

3.18в,г

3.18д,е

3.18ж,з

3.18и,к

3.19а,б

3.19в,г

3.19д.е

3.19 ж,з

Розділ 5. Прості типи даних в  PASCAL і дії над ними

№ вар.

1

2

3

4

5

6

7

8

9

10

11

12

13

Вправа [16]:

5.6

5.7

5.8

5.13

5.16

5.24

2.26

5.28

5.30

5.31

5.32

5.33

5.38

№ вар.

14

15

16

17

18

19

20

21

22

23

24

25

26

Вправа [16]:

5.41

5.42

5.43

5.45

5.48

5.49

5.50

5.51

5.52

5.53

5.54

5.55

5.56

Розділ 6. Структуровані типи

№ вар.

1

2

3

4

5

6

7

8

9

10

11

12

13

Впр.[16]

8.39,

9.4,

10.25

8.38,

9.5, 10.24

8.37,

9.6, 10.23

8.36,

9.7, 10.22

8.34,

9.8, 10.21

8.32,

9.9, 10.20

8.31,

9.1, 10.19

8.30,

9.11, 10.15

8.29,

9.12, 10.14

8.28,

9.13, 10.13

8.27,

9.14а, 10.12

8.26

9.14б, 10.11

8.24,

9.14в, 10.10

№ вар.

14

15

16

17

18

19

20

21

22

23

24

25

26

Впр.[16]

8.21,9.

14г,

10.9

8.20,

9.16а ,   10.8

8.19,

9.16б, 10.7

8.18,

9.16в, 10.6

8.16,

9.15, 10.5г

8.13,

9.17, 10.5в

8.12,

9.18, 10.5б

8.11,

9.19, 10.5а

8.10,

9.20,

10.4

8.9,

9.21,

 10.3

8.8,

9.22, 

10.2

8.7,

9.23, 

10.1

8.19,

9.16в,

10.5г

Розділ 7. Операції і оператори

№ вар.

1

2

3

4

5

6

7

8

9

10

11

12

13

Впр.[16]

4.10ж,

5.38, 8.43,

9.15а,

10.7,

13.18

4.14б,

5.39,

8.27а,

9.15б,

10.12,

13.19а

4.14г

5.40,

8.27б,

9.15в,

10.13,

13.19б

4.20,

5.44,

8.28,

9.15г,

10.14,

13.19в

5.3а,

6.12,

8.29,

9.16б,

10.15а,

13.19г

5.3б,

6.13,

8.30,

9.16в,

10.15в,

13.20

5.3в,

6.15,

8.31,

9.17,

10.15д,

13.21а

5.3г,

6.16в,

8.33б,

9.18,

10.15е,

13.21б

5.4,

6.16г,

8.33в,

9.21а,

10.16а,

13.22а

5.5,

6.17,

8.33г,

9.21б,

10.16б,

13.22б

5.11а,

6.18,

8.34,

9.22,

10.16в,

13.27а

5.11б,

6.19б,

8.36а,

9.23б,

10.16г,

13.27б

5.14,

6.19и,

8.36б,

9.23в,

10.16д,

13.27в

№ вар.

14

15

16

17

18

19

20

21

22

23

24

25

26

Впр.[16]

4.1в,

5.17б,

8.5,

9.24,

10.16е,

13.9

4.1е,

5.17в,

8.17,

9.26,

10.17а,

13.12

4. 1ж, 5.35,

8.19,

9.28,

10.17б,

13.13

4.2а,

5.17г,

8.21б,

9.29,

10.17в,

13.14а

4.2б,

5.17д,

8.21в,

9.31,

10.17г,

13.14в

4.2в,

5.20,

8.26а,

9.33,

10.17д,

13.15а

4.9,

5.21,

8.26б,

9.34,

10.17е,

13.15б

4.10а,

5.24,

8.38б,

9.35,

10.17ж,

13.15в

4.10б,

5.29б,

8.38в,

9.36,

10.17з,

13.16г

4.10в5.34,

8.32,

9.27,

10.17и,

13.17

4.10г,

5.36,

8.37,

9.25а,

10.18а,

13.16в

4.10д,

5.37,

8.38а,

9.25б,

10.18б,

13.16б

4.10е,

5.46,

8.26в,

9.25в,

10.1в,

13.16а

Розділ 8. Процедури і функції

№ вар.

1

2

3

4

5

6

7

8

9

10

11

12

13

Впр.[16]

11.42

11.39

11.38

11.37

11.36

11.35

11.31

11.30

11.26

11.21

11.20

11.19

11.17

№ вар.

14

15

16

17

18

19

20

21

22

23

24

25

26

Впр.[16]

11.16

11.15

11.13г

11.13в

11.13б

11.13а

11.12

11.11

11.5

11.4

11.3

11.2

11.1

Розділ 11. Читання/запис файлів

№ вар.

1

2

3

4

5

6

7

8

9

10

11

12

13

Впр.[16]

15.5

15.8

15.9

15.10

15.11

15.13

15.15

15.16

15.18

15.19

15.20

15.21в

15.21б

№ вар.

14

15

16

17

18

19

20

21

22

23

24

25

26

Впр.[16]

15.21г

15.21д

15.21е

15.21ж

15.21з

15.27

15.28

15.32

15.34

15.35

15.37

15.38

15.41


ПРЕДМЕТНИЙ ВКАЗІВНИК |середовища|

A

API - application program interface, інтерфейс прикладних програм -20

application programsБ прикладні програми – 7,20

Assembler, від assemble – збирати, вмонтовувати -18

C

compile  – збирати -19

H

heap-купа,англ.,136

M

MMI -  man-machine interface  - 20,22

O

OS - operation system – 10

R

RAM – random access memory - 10

ROM – read only memory- 10

run-time errors – 25

А

активізація (виклик) підпрограми - 21 

Асемблер-18

Б

бібліотеки стандартних підпрограм (БСПП) – 22

В

валідация програмного продукту - 25

вектори схемних і програмних переривань – 134

вираз – 49

Г

галуження програми- 107,

головна програма -34, 121

Д

двійковий (бітовий) формат- 11,

двійкової системи числення - 12

двонаправлена робота з перериваннями - 141

завантажувана програма застосування (*.exe - модуль) – 134

З

заголовок програми- 24

запис з варіантами,140

запис- 88

змінна файлового типу – 146

змінна циклу - 30

І

ітерація- 29

К

компілятор -21

конструктор множини - 93

коректне завершення операцій виводу на диск -  157

Л

логічні пристрої вводу/виводу – 151

М

масиви- 82, 137, 141

множини – 92

мова низького рівня - 20

мови|язики| високого рівня (МВР)- 7

монітор застосування – 27

Н

неявне (автоматичне) приведення типів- 56

О

об’єктні модулі - 134

об'єктний код - 21

об'єктно-орієнтоване програмування (ООП) – 17, 21

оператор

  •  безумовної передачі управління GOTO - 109
  •   виклику процедури – 49
  •   галуження по двох напрямах – 107
  •   галуження по множині напрямів – 108
  •   дострокового переривання циклу BREAK – 110
  •  пропуску кінцевих операторів циклу CONTINUE,110
  •  привласнення – 49,56,65,99
  •  рахункового циклу - 106
  •   циклу з перевіркою в кінці циклу умови виходу з циклу - 106
  •  циклу з попередньою перевіркою умови - 107

оператори альтернативного вибору – 107

операторні дужки - 32

операції – 49

      - арифметичні - 49

  •  відношення (порівняння) – 56
  •  логічні – 53, 54

операційна система ( ОС) – 10

П

передача  параметрів за адресою – 117,118

передача параметрів за значенням - 117

повний шлях до файлу - 151

позиційні системи числення - 12

помилки часу виконання - 25

початковий (символьний) текст – 21, 42

Правила роботи  з Замовником - 124

прикладні програми - 11

пристрій оперативної пам’яті ( ПОП) - 8,9,10

пристрій постійної пам'яті( ППП ) – 8,10

пріоритет операцій - 104

програма обробки переривань(ПОПі) - 24,

програмне|програмової| середовище - 21

проміжний буфер - 147,157

процедури і функції – 114

Р

розділ виконуваного коду - 24

розділ опису даних -24

роздільна здатність,167

рядки - 20 ,121

С

сегмент даних - 11

сегмент кодів - 11

середовище візуального програмування - 21

система команд - 11

складений оператор – 33, 46

список  фактичних параметрів - 114

список формальних параметрів – 115

Т

технологія низхідного програмування - 23

типи даних прості - 48

типи даних структуровані – 82

Ф

формальні і фактичні параметри, 115

функція – 114

Ц

цикл, змінна циклу - 46

цілі числа – 56,57

Ч

числа з плаваючою комою (дійсний тип) - 56, 61


Рис.10.2.

Молодші адреси

Программа(*.exe –модуль:

сегмент кодів, сегмент статич. даних)

Область кіпи,  зайната под дінамично створені змінні

Системна область

Кіпа(Heap), вільна область

Системна область

HeapEnd

  

HeapPtr

HeapOrg

Старші адреси

Рис.9.1. Блок-схема алгоритму калькулятора

1

Рис.5.1.

Об`екти

Процедури

Рядки

Вказники

Файли

Множини

Записи

Тип-діапазон

Перераховуваний

Символьний

Масиви

Структурировані

ТИПИ ДАНИХ

Прості

Порядкові

Дійсні

Логичний

Цілі

Рис.3.3. Структура ПЗ  застосування користувача ьского приложения

ОПm

СПn

СПn+1

МО-

НИ-

ТОР

СПk

СП1

ОП1

Бібліо-

тека

стандарт-

них

підпрог-

рам

Стартова секція

Головна       Оброблювальні         Службові                   БСПП       програма     подпрограми           підпрограми

                              (ОП)                        (СП)

ПО застосування користувача

 Виклик 

підпрограми 

         B

 Виклик 

підпрограми 

         A

1

Рис.3.2. Приклад схеми алгоритму

8

10

9

u>w

7

6

5

4

3

2

11

Виведення на друк результатів

Блок D

лінійних

обчислень

Аналіз: u>=w?

Блок C

лінйних

обчислень

u<w

u=w

STOP

Аналіз: x>z?

Так

Ні

Введення даних

x,z з клавіатури 

Запрошення на дісплеї

START

L1:

2

USB-

порт 

НГМД

Дисплей

ETHERNET

LPT

Принтер

НЖМД

COM1

COM2

Мережевий адаптер

   Клавіатура

Відео

адаптер

Контролер вводуиводу

ППП

ПОП

Процесор

Позначения:

ПОПпристрій оперативної памяті

ПППпристрій постійної памяті

НЖМД (НГМД) – накопичувач на жорсткомунучкому) магнітному диску 

COM1, COM2 – біт-послідовні порти телекомунікаційного вводуиводу

LPT – байт-послідовний порт  подключення  принтера (плотера)

USB- біт- послідовний порт подключення накопичувача на flash- пам‘яті 

ETHERNET локальна обчислювальна мережа

Рис.1.1. Структурна схема персонального комп`ютера

  8   

12

STOP

10

9

7

6

Вивід результату на дисплей

     ‘+’              ‘-’     ‘/ ’      ‘*’       ‘div’        ‘mod’

Блок арифметичних обчислень

  Case OP of ….

Цикл: i=1..2

Функція Conv перекладу лек- семи у число

Так

Ні 

Так 

2

признак STOP?

11

кінець строки? ('=') ?

5

START

Ні 

3

6 а

Ввод строки обчислень

з клавіатури

Запрошення на дисплеї до вводу

L1:

Процедура  PLex лексичного анализу строки

           

4

Цикл: i=1..2

Стек

      до вводу: Введіть x,z

Рис.3.1. Граф роботи програмних застосувань користувача

Програма ik

Програма… ….

Програма i2

Програма i1

ПОП1

ПОП2

ПОП3

ПОП4 

ПОПj , j=5..m

ПОПk,k=m+1..n

Миша

Диски

Клавіатура

Таймер

Сопроцесор

Монітор

застосування i

Монітор прило-

женияi

Монітор прило-

женияi

Зовнішні

сигнали

Програми обробки

переривань (ПОПi)

Диспетчер

задач

Ghjuhfvvf Программа i1

Програма j2

Програма j1

Додатки  користувачів

Операційна система

COM-порти




1. Учёт уставного и добавочного капитала
2. Вероятностные расчеты в ДНК-дактилоскопии
3. История государства которая изучает устройство государства государственные органы и механизмы управлен
4. во включает в себя мероприятия по изучению состояния земель планированию организации их рационального исп
5. Контрольная работа Развивающиеся страны в системе международных экономических отношений
6. Цель работы - Приобрести навыки создания простейших программ на языке Паскаль с использованием тольк
7. Сельский батюшка Обычно хотя бы несколько дней своего долгожданного отпуска я провожу на своей малой
8. Именно в это время были созданы многие памятники выдающимся русским людям надгробия возникли оригинальные
9. ХРОНИКА ВРЕМЕН ЕКАТЕРИНЫ II КНИГА ПЕРВАЯ Валентин ПИКУЛЬ Аннотация В романе запечатлены важнейш
10. Форми і методи краєзнавчої роботи
11. реферат дисертації на здобуття наукового ступеня доктора історичних наук Донецьк ~
12. Развертывание систем персонального радиовызова
13. Реферат по дисциплине- ldquo;Экологияrdquo; Р а б о т у проверил Р а б о т у выпо
14. РОССИЙСКИЙ УНИВЕРСИТЕТ КООПЕРАЦИИ КАЗАНСКИЙ КООПЕРАТИВНЫЙ ИНСТИТУТ ФИЛИАЛ ЭКО
15. Влияние грызунов на рельеф и процессы лесовостановления
16. Камская государственная инженерноэкономическая академия в г
17. рии предприятий устанавливают специальные щиты
18. ВОРОНЕЖСКАЯ ГОСУДАРСТВЕННАЯ МЕДИЦИНСКАЯ АКАДЕМИЯ имени Н
19. Атмосфера Тропосфера Метеорология
20. Внешнеполитические полномочия парламентов (зарубежных стран)