Поможем написать учебную работу
Если у вас возникли сложности с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой - мы готовы помочь.

Предоплата всего

Подписываем
Если у вас возникли сложности с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой - мы готовы помочь.
Предоплата всего
Подписываем
МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ
НАЦІОНАЛЬНИЙ ТЕХНІЧНИЙ УНІВЕРСИТЕТ УКРАЇНИ
"КИЇВСЬКИЙ ПОЛІТЕХНІЧНИЙ ІНСТИТУТ"
«ОСНОВИ ПРОГРАМУВАННЯ ТА
АЛГОРИТМІЧНА МОВА PASCAL»
Навчальний посібник
Київ НТУУ “КПІ”
2010
ОСНОВИ ПРОГРАМУВАННЯ ТА АЛГОРИТМІЧНА МОВА PASCAL. Навчальний посібник
/Укл.: доц. Ю.Д. Щербашин, ст.викл. Д.С. Смаковський.
-К.: НТУУ “КПІ”, 2010 , - с. 197
Навчальне видання
Укладачі: Щербашин Юрій Дмитрович
Смаковський Денис Сергійович
Відповідальній редактор д.т.н С.О.Лукяненнко
Рецензенти: доц. В.М. Медведєва
доц. В.Я.Сидоренко
доц. Є.В.Щербаков
ЗМІСТ
[1] ВСТУП
[2] [2.1] Розділ 1. Архітектура сучасних ПК [2.1.1] 1.1. Структурна схема ПК . [2.1.2] 1.2. Загальні|загальні| принципи роботи комп'ютера [2.1.3] 1.3. Позиційні системи числення [2.2] Завдання для самостійної роботи
[2.3] [2.4] Розділ 3. Загальні|загальні| принципи програмування [2.4.1] 3.1. Вимоги до професії [2.4.2] 3.2. Мови|язики| програмування і програмне|програмова| середовище|середовище| [2.4.3] 3.3. Структура програмних комплексів
[2.4.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] [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] [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] [3.5.1] 6.1. Масиви [3.5.2] 6.2. Записи [3.5.3] 6.3. Рідко використовувані типи [3.5.4] 6.4. Іменування констант, константи, що типізуються [3.6] Завдання для самостійної роботи
[3.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] [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] [3.13.1] 10.1. Організація простору оперативної пам'яті в ПК [3.13.2] 10.2. Динамічне виділення пам'яті. Типи покажчиків [3.13.3] 10.3. Використання покажчиків при роботі з|із| процедурами і функціями [3.14] Завдання для самостійної роботи
[3.15] [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] [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 локальна обчислювальна мережа.
Виділені курсивом слова в тексті мають зсилки на Предметний показник, наведений в кінці посібника, що облекшує користування книгою як довідником.
Автори вдячні зав. кафедри автоматизації проектування енергетичних процесів та систем КПІ професору Лукяненко С.О. та доценту тієї ж кафедри Медведєвій В.М. за цінні методичні зауваження щодо змісту навчального посібника.
Обчислювальна техніка і інформаційні технології переживають період бурхливого розвитку. Потужність сучасного переносного персонального комп'ютера (ПК) на декілька порядків перевищує потужності суперкомп'ютерів 60-80-х. Проте принципи побудови, так звана архітектура комп'ютера, змінилися незначно.
Комп'ютер це цифровий автомат, що керується програмою. Він здатен виконувати:
На рис.1.1. наведена спрощена структурна схема сучасного комп'ютера.
Роботою комп'ютера управляє програма послідовність команд, що примушують процесор виконувати згадані вище дії. Стартова програма, яка починає виконуватися відразу ж при включенні комп'ютера, записана в енергонезалежному пристрої постійної пам'яті, - ППП (ROM read only memory, англ.). Ця програма зчитує з нульової доріжки жорсткого диска програму-завантажувач, поміщає її в пристрій оперативної памяті - ПОП, (RAM random access memory, англ.) і передає управління цій програмі. Завантажувач зчитує з диска і запускає програмне забезпечення операційної системи - ОС, (OS - operation system, англ.), що здійснює управління обчислювальним процесом. Під управлінням ОС зчитуються в ПОП і запускаються прикладні програми (application programs, англ.).
В першому, грубому розгляданні можна рахувати, що для роботи будь-якої, прикладної або системної, програми завантажувач виділяє в ПОП дві області:
сегмент кодів область, де розміщується код завантажуваної на виконання програми,
сегмент даних область, де розміщуються оброблювані цією програмою дані.
Під управлінням програми процесор безпосередньо або через універсальний контролер вводу/виводу здійснює управління всіма зовнішніми пристроями, як показано на рис.1.1.
Вся інформація в комп'ютері обробляється і зберігається в двійковому (бітовому) форматі, і немає будь-якої відмінності між кодами команд і кодами даних. Процесор розрізняє їх контекстно команди знаходяться в області сегменту кодів, а дані в області сегменту даних.
Мінімальною одиницею інформації, що адресується, в сучасних комп'ютерах, прийнятий байт (byte 8 двійкових розрядів-біт). Адресний простір ПОП починається з нульової адреси. Частину адресів спільного адресного простору займає ППП і буфер відеопам'яті дисплея.
Код кожної команди, розташованої в ПОП (ППП) за певною адресою, містить:
Сукупність команд зі всіма можливими кодами операцій - так звана система команд, різна для процесорів різних виробників. В даний час найбільш поширена система команд процесорів фірми Intel, якими оснащена більшість ПК.
Як зазначено вище, комп'ютер працює з даними в двійковому форматі. Коротко ознайомимося з особливостями двійкової системи числення, де окремі розряди можуть набувати тільки два значення: 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. Перевести в шіснадцяткову та двійкову системи десяткове число, яке дорівнює сумі Вашого дня, місяця та року народження.
Мови програмування високого рівня (МВР) з'явилися вже на перших етапах становлення обчислювальної техніки. Першою такою поширеною МВР, була розроблена американськими фахівцями в середині 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++ підтримує як традиційну технологію програмування, засновану на використанні підпрограм, так і нову технологію об'єктно-орієнтованого програмування (ООП), що використовує апарат спадкоємства властивостей і інкапсуляції, локалізації зони дії змінної, що значно підвищує надійність програмного продукту.
Заглядаючи в не настільки вже віддалене майбутнє інформаційних технологій, що бурхливо розвиваються, можна сформулювати основні вимоги до перспективної мови програмування високого рівня:
Цим вимогам в більшій або меншій мірі відповідають сучасні версії мов PASCAL і С(С++).
Контрольні питання:
Один із законів Паркінсона наголошує: “У кожній відладженій програмі є, як мінімум, одна помилка. Правило зберігає силу після виправлення цієї помилки”.
Це не жарт - це гірка правда. Але, є різні типи помилок. Відомий анекдот програміста:
- Майкрософт для нової класної версії Windows випустив документ виявлених помилок. Там їх ціла тисяча!
- А в моїй програмі тільки єдина помилка!
- Ну, і як?
- Та, програма не працює!
Важка ти, доля програміста! Персональний комп'ютер його основний робочий інструмент. Цей інструмент складний і вимагає від майстра певних здібностей і досить обширних спільних і спеціальних знань. Отже, про професійні здібності і спільні знання.
По-перше, програміст повинен мати добру пам'ять. Ця якість необхідна для запам'ятовування імен змінних і одномоментного бачення як можна більшого фрагмента програми, що відладжується.
По-друге, програміст повинен мати чітке логічне мислення, вміти в думках імітувати роботу відладжуваної програми, працювати замість комп'ютера. Досвідчений програміст, створивши черговий блок програми, в думках відтворює роботу цього блоку, в думці отримує оцінки результатів роботи блоку, а потім запускає на виконання програму із знов створеним блоком і порівнює очікувані результати з фактичними. Швидкість мислення істотної ролі не відіграє. Часто тугодуми досягають більших успіхів, ніж скорострільні вундеркінди, за рахунок своєї методичності, працьовитості і цілеспрямованої завзятості.
По-третє, програміст має бути спостережливим. Ця якість дуже допомагає тоді, коли не вдається логічно обчислити причину помилки. В цьому випадку програміст варіює вхідними даними або намагається використовувати інший варіант програмного блоку. Якщо він спостережливий, то може відмітити реакцію, яку він не чекав як відгук на такі варіації. “…Я змінив знак другого операнда, а результат змінився замість очікуваної одиниці на мінус одиницю! Що б це означало?.” Далі до аналізу ситуації підключається апарат логічного мислення.
У важких випадках деякі програмісти, не знайшовши причину помилки, просто переписують програму заново. Як не дивно, це інколи допомагає. Але ми не прихильники таких методів стрілянини по площах. Справжній, добросовісний програміст докопуватиметься до причини помилки. В крайньому випадку, він виконає покрокову відладку, ретельно оцінюючи результати кожного кроку до тих пір, поки помилка не буде спіймана. При цьому дуже часто помилка виявляється абсолютно в іншому програмному блоці, а не в тому, на якому було зосереджено увагу програміста (тому і не допомагало логічне мислення!).
І, нарешті, по-четверте, висококласний програміст повинен володіти наочною галуззю знань, для якої розробляє свої програми:
Незалежно від спеціальності по диплому, на всьому протязі професійної кар'єри програміст має бути готовий освоювати все нові і нові галузі знань. Одним словом, “Вік живи - вік навчайся ”!
Як відомо, технічні засоби комп'ютера працюють в двійковому форматі представлення даних і команд. Програмувати в двійковому форматі дуже громіздко. Тому з самого зародження обчислювальної техніки використовувалися символічні мови програмування символьні (текстові) рядки, зрозумілі людині-програмістові, які спеціальна програма-транслятор переводить в двійковий код, зрозумілий комп'ютеру, - так званий машинний код.
Можливості системи команд якнайповніше використовує мова Асемблера (Assembler, від assemble збирати, вмонтовувати, англ.) так звана мова низького рівня. У загальному випадку один символьний рядок Асемблера, як правило, породжує одну машинну команду.
До поширених сучасних професійних універсальних мов високого рівня відносять ПАСКАЛЬ (Pascal) [1,2] і Сі (C, С++, C#) [3,4,5]. Вони відрізняються компактнішим описом програми, ніж Асемблер. Один символьний рядок МВР породжує в середньому 5-6 команд машинного коду.
Подальше зниження трудомісткості програмування було досягнуте за рахунок створення програмного середовища, що включає:
В даний час транслятори, як правило, об'єднуються з компонувальниками і називаються компіляторами (compile збирати, англ.)
До сучасного програмного середовища відносяться: DELPHI (мова Паскаль) [6], Borland С++ Builder 6 (мова C++) [7], С# технології .NET Framework (мова C# - читається: Сі шарп або Сі дієз) [8,9], Visual C++[10], Visual Basic [11].
Це так зване програмне середовище візуального програмування, яке в значній мірі автоматизує процес складання програм людино-машинної взаємодії (введення даних, відображення результатів обробки даних, управління ходом обчислень), що збільшило продуктивність фахівців-програмістів ще в кілька разів. Одночасно, за рахунок широкого використання в програмному середовищі технології так званого об'єктно-орієнтованого програмування (ООП) вдалося значно підвищити надійність програмного забезпечення і, відповідно, збільшити об'єм і функціональні можливості програмного продукту.
Велика програма (програмний комплекс) складається з головної програми, з якої починається робота програмного комплексу, і набору підпрограм, що виконують окремі обчислювальні функції. Якоюсь мірою головна програма подібна до змісту книги з введенням: у ній міститься перелік підпрограм і порядок їх виклику, а також дані, що інформаційно поєднують ці підпрограми. Окремі розділи книги це підпрограми першого рівня. У свою чергу, вони можуть містити параграфи підпрограми другого рівня, обслуговуючі старших за ієрархією, і так далі
Текст книги може посилатися на інші книги, зокрема, на довідники. У нашій термінології це бібліотеки стандартних підпрограм (БСПП). Кожна мова високого рівня має свій набір БСПП, що значно полегшує роботу програміста, оскільки не доводиться кожного разу заново винаходити велосипед. Зазвичай бібліотеки стандартних підпрограм сучасних МВР містять наступні підпрограми:
Процес розробки складного програмного комплексу починається з розбиття початкового завдання на окремі, більш-менш самостійні підзадачі, які розбиваються на ще дрібніші підзадачі і так далі поки об'єм підзадачі нижнього рівня ієрархії буде осяжно малим, не більше 1-2 сторінок тексту на МВР.
Зазвичай використовується технологія низхідного програмування [12]: у програмі, старшій за ієрархією, робляться виклики підпрограм, але замість реальної підпрограми ставиться підпрограма - заглушка, що лише імітує роботу справжньої підпрограми.
Після відладки старшої програми по черзі замінюємо заглушки реально працюючими підпрограмами, продовжуючи безперервно тестувати весь програмний комплекс. Технологію низхідного програмування на конкретному прикладі ми розглянемо в розділі 9.
Символьні тексти програмного комплексу можуть зберігатися в декількох окремих символьних файлах з розширеннями:
*.pas- для Pascal - програм
*.c для програм на Сі
*.cpp- для програм на C++
*.cs для програм на C#
*.bas для програм на Бейсику
*.asm для програм на Асемблері.
Для складних програмних комплексів кількість таких символьних файлів з початковим текстом може досягати декількох сотень і навіть тисяч з розміщенням в кожному з них текстів декількох десятків підпрограм. Сучасне програмне середовище дозволяє компонувати програмні комплекси, окремі символьні файли яких написані на різних мовах.
У тексті програми на МВР розрізняють 3 розділи:
У мові Паскаль заголовок програми завжди розміщується першим. У нім же розділ опису даних завжди передує розділу опису виконуваного коду. У Сі та Бейсику це обмеження зняте, і нові змінні можна оголошувати упереміж з виконуваним кодом.
Заголовок програми (підпрограми) містить:
Розділ опису даних містить імена і типи даних (змінних і констант).
Розділ виконуваного коду містить кодову частину тіло програми. Тіло головної програми містить здебільше коди викликів підпрограм з невеликими вкрапленнями машинних команд, що аналізують код завершення викликаної підпрограми або пересилають результати в інші області пам'яті або інші підпрограми. Тіло підпрограм нижнього рівня містить тільки коди машинних команд.
Програмування і налагодження програм на МВР може бути представлене послідовністю кроків:
а) аналізуються вхідні дані програми на предмет неточностей
б) аналізується алгоритм роботи
в) виконується налагоджувальний роздрук результатів, у важких випадках покрокове виконання програми.
При позитивних результатах тестового прогону програми готуються складніші тести, що всебічно перевіряють створений програмний продукт, - так звана валідация програмного продукту.
Будь-яке прикладне програмне забезпечення - це комплекс взаємопов'язаних програм, які виконуються під управлінням монітора застосування. Монітор - центральне ядро програмного комплексу, виконує циклічний опит зовнішніх сигналів, наприклад, клавіатури, і залежно від виду сигналу (наприклад, символу клавіші, що натиснута) запускає на виконання ту або іншу оброблювальну програму застосування. Після закінчення роботи програми управління знов передається монітору або здійснюється завершення роботи прикладної програми.
У сучасних середовищах візуального програмування (Delphi, Visual C, Borland C++Builder, Microsoft.net C#) функція монітора максимально автоматизована і прихована від розробника прикладної програми, що спростило програмування застосувань. Проте, такий компонент застосування, створений автоматично або вручну, завжди існує і необхідно розуміти механізм роботи програмного комплексу застосування в середовищі сучасної операційної системи.
На рис 3.1. представлений граф роботи прикладних програм в середовищі операційної системи.
У кожен момент часу однопроцесорний комп'ютер виконує команди програми одного із застосувань або команди програм операційної системи. Під час появи сигналу від одного із зовнішніх пристроїв (рис.3.1.) виникає апаратне переривання поточного обчислювального процесу, і управління передається відповідній програмі обробки переривань (ПОПі).
Програма обробки переривань запам'ятовує адресу поточної команди і поточний вміст регістрів спільного призначення перерваної програми, обмінюється даними із зовнішнім пристроєм і передає отримані дані диспетчерові завдань, який передає управління і дані монітору відповідного застосування. Монітор застосування викликає необхідну програму. Після виконання програми застосування система повертається до перерваного обчислювального процесу.
Обчислювальний процес може бути лінійним, коли оператори мови (машинні команди) виконуються послідовно, одна за одною, а може бути таким, що розгалужується. Розгалуження виникає після аналізу деякої умови. Залежно від результату аналізу може виконуватися та, або інша лінійна гілка, усередині якої теж може бути аналіз умов і галуження обчислювального процесу і так далі.
На рис.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.2. це гілка повторень, що йде від блоку аналізу 7 до блоку введення початкових даних 2. Цикл виконання блоків 2-7 повторюватиметься поки змінні u і w будуть рівні. При нерівності цих змінних програма завершиться виводом на друк якихось результатів обчислень в одному з блоків 8,9. На блок-схемах гілка, що створює цикл, змальовується лінією із стрілкою.
Циклічне виконання одних і тих же операцій (ітерація) характерна ознака автоматів, як механічних, так і електронних (комп'ютерів). У програмуванні цикли використовуються в ітеративних алгоритмах чисельного аналізу, а також при обробці масивів даних. Приклади масивів даних:
У циклі за допомогою одного і того ж програмного блоку відбувається послідовна обробка елементів масиву. Як індекс (номер) елементу масиву найчастіше використовується так звана змінна циклу, що модифікується при кожному повторенні циклу.
Найбільш поширена помилка починаючих програмістів вихід значення змінної циклу за допустимий діапазон зміни індексу масиву. При цьому непередбаченим чином спотворюються дані сусідніх масивів. Виникає найнеприємніша з помилок програмістів назвемо її мерехтливою помилкою, коли при одному поєднанні вхідних даних програма дає правильний результат (наприклад, число працівників цеху менше максимально передбаченого), а при іншому неправильний (на роботу прийняли ще декілька працівників, що перевершило ліміт масиву).
У сучасних трансляторах передбачена можливість включення автоматичного (без участі програміста) контролю індексу масиву на діапазон допустимих змін. Природно, ця опція (додаткова можливість) з прихованим від програміста програмним кодом вимагає від комп'ютера додаткових обчислювальних витрат, але вони, як показує практика, не настільки великі. Тому настійно рекомендуємо користуватися цією опцією у всіх випадках, виключаючи, можливо, програми з надвеликим об'ємом обчислень, наприклад, при програмуванні вирішення тривимірних завдань матфізики або візуалізації рухомих тривимірних зображень.
Цикл може бути утворений чотирма способами:
Цикл з умовним переходом на мітку утворюється в результаті виконання умовного оператора, що перевіряє деяку умову (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.3 представлений приклад структури програмного забезпечення застосування користувача.
Як видно з рис.3.3, звернення до процедур і функцій бібліотеки стандартних підпрограм може виконуватися як з рівня головної програми, так і з рівнів оброблювальних і службових підпрограм.
Відмітимо, що в завантажувальний *.exe - модуль застосування користувача з БСПП поміщаються тільки необхідні підпрограми. Одна і та ж підпрограма з БСПП, ОП, СП може викликатися з декількох точок програм різних рівнів, що значно скорочує об'єм завантажуваного модуля. Так до службової підпрограми Сп1 звертаються монітор і дві оброблювальні програми ОП1, ОПm, а до СПk звертаються ОП1 і СПn+1. У свою чергу, СПk звертається до двох бібліотечних функцій.
3.10. Типи підпрограм
Підпрограма відособлений програмний блок, що виконує певну обчислювальну роботу.
Результат виконання підпрограми може бути переданий в викликаючу програму через регістр процесора. Така підпрограма називається функцією. У мовах високого рівня ім'я функції є ім'ям цього результату і може використовуватися в арифметичних і логічних виразах спільно із звичайними змінними. Приклад бібліотечна функція обчислення сінусу аргументу x, sin(x). Підпрограми, що в явному вигляді не передають результат в викликаючу програму, називаються процедурами. Приклад - процедура очищення екрану дисплея CLRSCR.
Контрольні питання:
Освоєння технології програмування найлегше почати з dos-версії мови фірми Борланд - Turbo Pascal 7.0. Хай вас не бентежить той факт, що ви на сучасному ПК з сучасною операційною системою використовуєте програмне забезпечення 30-річної давності, розроблене для операційної системи DOS Microsoft. Про правильність роботи старого програмного забезпечення поклопоталися розробники Біла Гейтса. Основоположною концепцією фірми Microsoft є сумісність нових операційних систем із старим матзабезпеченням. Саме концепція еволюційного розвитку програмного забезпечення дозволила фірмі Microsoft завоювати і впродовж декількох десятиліть утримувати провідну позицію в розробці операційних систем для персональних комп'ютерів.
Для початку роботи створимо мінімально можливу версію інструментального середовища Turbo Pascal, яка в архівному стані легко уміщається навіть на дискеті 3,5. Це корисно виконати з двох міркувань:
Отже, на будь-якому диску, наприклад на 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].
Тепер, коли ми розуміємо структуру програми на МВР (див. розділ 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 не призводить до аварійного завершення програми. Зясувати причину аварійного завершення програми вже при не дуже великих значеннях n .
У мові Паскаль прості типи даних можуть бути:
У ширшому трактуванні під даними розуміють всі іменовані об'єкти, використовувані в мові Турбо Паскаль [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.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 |
Числа з плаваючою комою (дійсний тип), як і цілі, відносяться до простого типа.
Проте дійсний (речовий) тип не є перераховуваним, тобто до них не застосовні функції 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.
Логічний тип (булевий - англ., boolean, по імені англійського математика Д.Буля) відноситься до типу порядкових і може набувати тільки 2 значення: TRUE (істина) або FALSE (неправда). При цьому :
Ord(False)= 0
Ord(True)= 1
Succ(False)= True
Pred(True)= False
False < True
Тип boolean виникає при виконанні операцій порівняння величин двох змінних для подальшого розгалуження програми по декількох напрямах.
Значеннями символьного типу є множина всіх символів ПК. Кожному символу приписується ціле число в діапазоні 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).
Символьний рядок основний тип, спеціально пристосований для обробки символьних даних, це послідовність (одновимірний масив) символів з можливістю зміни довжини рядка від 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 і оператором привласнення (:=) дуже зручні при сортуванні символьних рядків, оскільки при їх використанні програма працює з рядками як з цілісними об'єктами.
Тип-діапазон є підмножина свого базового порядкового типу. Він задається межами своїх значень усередині базового типу:
<мин.знач>..<макс.знач>
Наприклад:
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 за межі допустимого діапазону.
Перераховуваний тип відноситься до типу порядкових. Він задається перерахуванням тих значень - імен, які він може отримувати. Кожне значення іменується деяким ідентифікатором і розташовується в списку, що обрамоване круглими дужками, наприклад:
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.).
Константи можуть входити у вирази в правій частині операторів привласнення, використовуватися в операціях порівняння, а також використовуватися як фактичні параметри при виклику процедур і функцій. Як константи в Тубо Паскалі можуть використовуватися цілі десяткові і шістнадцяткові числа, дійсні числа, символи, рядки символів, конструктори множин (див. розділ 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() при програмному формуванні рамки документа, оскільки немає іншого способу.
Підсумок розгляду порядкових і дійсних типів, їх властивостей і дій над ними ілюструється програмою 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. На основі завдання самостійної роботи розділу 4 (вправа 4.1) модернізувати програму обчислення факторіалу для якомога більшого значення n.
Якщо дані простого типу мають по одному значенню-елементу, то дані структурованого типу характеризуються множинністю елементів. Змінна або константа структурованого типу завжди має декілька елементів, кожен з яких може бути як простим типом, так і структурованим.
Масиви складаються з елементів одного типу (простого або структурованого). Для опису масивів використовується ключове слово 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.
На відміну від масиву запис це структура даних, що складається з фіксованого числа, як правило, різнорідних компонентів, званих полями. Поля запису іменуються, так що є можливість звертатися до будь-якого з них по імені.
Структура оголошення типа запису :
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]) містить знак числа і старші розряди, тобто порядок розташування байтів в ПОП перевернений, але усередині байта порядок убування старшинства бітів прямій (тобто зліва-направо).
Множини це набори однотипних, логічно зв'язаних в одну групу об'єктів. Кількість елементів, що входять в множину, може мінятися в межах 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, але не еквівалентна їй.
Над множинами визначені наступні операції:
При роботі з множинами окрім операцій можна використовувати 2 процедури:
При цьому, природно, елемент I та множина S повинні належати одному базовому типу.
Робота з множинами специфічний розділ математики і в практиці програмування на Паскалі зустрічається досить рідко.
Якщо одна і та ж константа, наприклад, розмір вектора, зустрічається в декількох місцях, то логічно привласнити їй ім'я, і в тексті програми багато разів використовувати це ім'я. При необхідності зміни константи досить змінити її значення в розділі визначення константи без будь-якого корегування тексту тіла програми.
Секція опису констант розташовується в будь-якому місці розділу опису змінних/констант, починається з ключового слова 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
Контрольні питання:
Оператор це закінчена програмна конструкція, що виконує певні дії над змінними. У операторові змінні об'єднані операціями. Кожен оператор закінчується крапкою з комою.
Як відомо, тіло програми складається з:
Оператор привласнення має структуру:
<имя_змінної> := <вираз>; ,
де: := - операція привласнення,
<имя_змінної> - змінна будь-якого типу (див. рис.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.
Над цілими і дійсними числами Паскаль допускає усі 4 арифметичні операції, виділяючи в особливу групу цілочисельне ділення і залишок від цілочисельного ділення:
На відміну від інших МВР Паскаль гранично строгий до спільного використання в операціях різних типів даних. Транслятор аналізує типи даних у виразі праворуч від знаку операції привласнення (:=) і приводить всі операнди до старшого типа. Якщо операнди типа 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.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.
Операції відношення (порівняння) : =, <, <= >, >=, <> використовуються для вироблення булевої умови (true, false) в так званих операторах з перевіркою умови (if, while, repeat…until). Тип результату виконання операції відношення логічний (true, false).
Операції відношення застосовні до всіх простих типів (див. Розділ 5). Порівнювати між собою можна змінні однакового типа. Допустимо також порівняння дійсних чисел з цілими.
Операції відношення:
a=b перевірка: перша змінна рівна другій?,
a<b перевірка: перша змінна менше другої?,
a<=b - перевірка: перша змінна менше або рівна другої?,
a>b - перевірка: перша змінна більше другої?,
a>=b - перевірка: перша змінна більше або рівна другої?,
a<>b - перевірка: порівнювані змінні не рівні?.
Дія дужок в арифметичних і логічних виразах на мові Паскаль відповідає загальноприйнятим правилам. За відсутності дужок операції виконуються відповідно до їх пріоритету (див.Табл.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), поки не набудете необхідних професійних навичок, щоб відчувати небезпечні місця програми. А їх в Сі таких 'вовчих ям', більш ніж достатньо.
Підкреслимо, що при програмуванні великих несистемних (прикладних) програмних комплексів функціональні можливості Паскаля і Сі абсолютно рівноцінні! Так чи слід “стріляти з гармати по горобцях”?
Закінчивши розгляд операцій в мові Паскаль, перейдемо тепер до розгляду складніших програмних конструкцій операторів. Оператор привласнення ми розглянули вище при описі операції привласнення. Тепер розглянемо решту операторів Паскаля.
У мові Паскаль є три різні оператори, за допомогою яких можна запрограмувати цикл - багатократне повторення фрагмента програми, не використовуючи міток і оператора 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.
Оператори альтернативного вибору забезпечують галуження програми по декількох напрямах. У Паскалі є 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-операторами з складними умовами порівняння.
Оператори передачі управління дозволяють порушити послідовність виконання команд. Наприклад, в блоці команд оператора циклу перейти на кінець циклу або достроково перервати цикл. До операторів цього типу в Паскалі відносяться:
Оператор безумовної передачі управління на поміченого оператора має структуру:
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. Скласти блок-схему алгоритму для програми Прикл.7.3.
Підпрограма самостійний фрагмент програми, що має власне ім'я і пов'язаний з основною програмою лише за допомогою декількох параметрів. Згадка цього імені в тексті програми викликає виконання (активізацію) цього фрагменту. Відразу після активізації підпрограми починають виконуватися її оператори. Після виконання останнього оператора підпрограми управління повертається в основну програму.
Використання підпрограм дозволяє зменшити програмний код за рахунок багатократного виклику з різними значеннями параметрів підпрограми в тілі основної програми і, головне, дозволяє створювати добре структурований програмний продукт. У структурованих програмах зазвичай легко просліджується основний алгоритм, вони простіше у відладці і менш чутливі до помилок програмування.
У Паскалі підпрограми підрозділяються на процедури і функції. У мові Сі поняття процедури відсутнє, тобто всі підпрограми є функціями.
Процедурою в Паскалі називається особливим чином оформлений фрагмент програми, що має власне ім'я. Формат опису процедури:
Procedure <имя_процедури>(<список_форм._парам.>); {заголовок
процедури}
<розділ опису локальних змінних>
<тіло процедури, обмежене операторними дужками begin…end;>
Виклик процедури в тілі програми це згадка імені процедури із списком фактичних параметрів в круглих дужках. Приклад виклику процедури:
writeln(x,y); .
Характерною ознакою оператора виклику процедури є відсутність в цьому операторові символу операції привласнення (':=').
На відміну від процедури функція повертає значення, тип якого вказується в додатковому полі заголовка ' :<тип_повертаєм_значения> '. Функція використовується в операторах привласнення як звичайна змінна. Приклад використання функції: y:=sin(x)+5.3;
Формат опису функції:
Function<имя_функции>(<список_форм._парам.>):<тип_повертаєм.значен.>;
<розділ опису локальних змінних>
<тіло процедури, обмежене операторними дужками begin.. end;>
Поле ' (<список_форм._парам.>) ' заголовка процедури або функции це обмежений круглими дужками список формальних параметрів, розділених один від одного комою або точкою з комою (приклад див нижче).
Формальними параметрами можуть бути імена (або адреси) змінних і/або констант - простих і структурованих з вказівкою їх типа, а також імена процедур і функцій зі своїми параметрами. Формат списку формальних параметрів:
(<Імя_змін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 '. Тому, кому важко з відповіддю на це питання, радимо повторно пропрацювати відповідні розділи.
У Паскалі, також як і в Сі, можуть бути використані два принципово різні механізми передачі фактичних значень параметрів в підпрограму, що викликається:
Передача в підпрограму копії фактичного параметра.
Передача в підпрограму адреси фактичного параметра.
У першому випадку будь-які зміни параметра в підпрограмі не впливають на його значення в визиваючій програмі, оскільки в підпрограмі ми маємо справу з копією. У другому випадку зміна параметра в підпрограмі, тобто занесення інформації за адресою, де зберігається фактична змінна, змінюють значення цієї змінної в визиваючій програмі. Перший спосіб (універсальний), званий способом передачі параметрів за значенням, максимально захищає визиваючу програму від помилок в підпрограмі. Другий спосіб (спеціальний), званий способом передачі параметрів за адресою, вимагає від програміста більшої відповідальності, оскільки такі підпрограми можуть змінювати, у тому числі, псувати інформацію головної програми. Проте, передача параметра за адресою - це єдиний спосіб передачі зміненої інформації з процедури у визиваючу програму.
Спосіб передачі параметрів за адресою в процедуру (функцію) задається в описі заголовка процедури (функції) за допомогою ключового слова 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 в цьому випадку обов'язкова вказівка конкретних розмірів масиву, що неприйнятно для підпрограм універсального призначення із змінним числом елементів масиву. В цьому випадку, як і в мові Сі, використовується апарат покажчиків, який розглядається в подальших розділах.
Параметри-функції і параметри-процедури відносяться до так званого процедурного типу (див. рис.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. Нарисувати схему алгоритму прикладу 8.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. Ескіз програми
Як бачимо, у нас вже є:
Наступний крок - виділення в особливу групу глобальних змінних і підпрограм і створення окремих *.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.
Зазвичай над проектом працює декілька програмістів, які частенько не знаходяться не лише в одному приміщенні, але навіть не на одному континенті (велика ти, сила Інтернету!). Вже це одне викликає необхідність розбиття програмного продукту на окремі модулі, щоб забезпечити паралельну розробку частин проекту.
У великих проектах число програмних модулів може складати декілька сотень і вони можуть бути написані на різних алгоритмічних мовах. Проте, в кожному програмному комплексі є модуль головної програми, з якого починається робота комплексу, як показано вище в прикладі ескізного опрацювання проекту.
Тепер залишилося роз'яснити, що таке програмний модуль і як він влаштований. Програмний модуль це окремо трансльований *.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. Розробити бібліотеку підпрограм MyLib, ескіз якої розглядається в розділі 9.2 (див рис.9.5). Скомпонувати та протестувати CALCULAT - програмний комплекс калькулятора.
Програма, яку виконує процесор комп'ютера, може знаходитися або в оперативній памяті- ПОП, або в постійній памяті - ППП. Частку спільного адресного простору займають адреси ППП, а частку - ПОП. У ППП розташовуються незалежні програми початкового запуску з базовою системою управління пристроями вводу/виводу BIOS (basic input/output system, англ).
Відзначимо, що в ППП не може знаходитися інформація, що оперативно змінюється. Для цієї мети можуть використовуватися регістри процесора і ПОП. Проте оперативний пристрій, що запам'ятовує, не володіє властивістю енергонезалежності, тобто при виключенні живлення комп'ютера інформація в ПОП пропадає. Проте, в працюючому комп'ютері велика частка програм, у тому числі програми операційної системи і програми застосувань користувача, розташовуються в ПОП. На рис.9.1 приведена схема розміщення інформації в адресному просторі ПОП.
Системні області зайняті під резидентні програми операційної системи і вектори схемних і програмних переривань, де указується адреса запуску відповідної програми обробки переривань.
Завантажувана програма застосування (*.exe - модуль) створюється на етапі компіляції з сукупності окремо трансльованих обєктних модулів (*.tpu обєктні модулі Паскаль-програм, *.obj- обєктні модулі Сі та Ассемблерних-программ) Вона займає в ПОП простір, що статично виділяється, під:
Стек це група робочих комірок ПОП, з якими процесор за допомогою спеціальних команд працює як з набором регістрів за правилом 'останнім прийшов - першим вийшов'. Основне призначення стека прискорення обробки інформації при зверненні до підпрограм (саме в стеку передаються фактичні параметри
Рис.10.1. Розміщення інформації *.exe модуля в ПОП
процедур і функцій). Він займає самі старші адреси області, виділеної під програму, і нарощується у бік зменшення адрес. При роботі на МВР стек організується автоматично, тобто прихований від програміста. Проте слід пам'ятати, що при неправильному використанні в програмі рекурсивних процедур (що викликають самі себе в тілі процедури) зростаючий стек може переповнитися, накривши собою сегмент даних і/або сегмент кодів. Щоб уникнути таких неприємностей рекомендуємо в налаштуваннях транслятора Options\Compiler у вікні Runtime errors встановити всі види контролю, у тому числі - переповнювання стека.
Після завантаження в ПОП програми застосування адресний простір ПОП, що залишився, (динамічна пам'ять), зване 'купою(кіпою)' (heap,англ), в перший момент вільно. Початкова адреса купи зберігається в стандартній змінній HEAPORG, кінець в змінній HEAPEND. Поточний кордон незайнятої динамічної пам'яті визначає покажчик HEAPPTR. До початку роботи програми застосування HEAPPTR = HEAPORG. При запитах в програмі додаткової (динамічної) пам'яті необхідна частина адресного простору забирається з купи, а покажчик HEAPPTR нарощується на необхідне число байт.
При розробці універсальних програм, коли заздалегідь невідомі розміри масивів, неможливе статичне використання пам'яті під змінні. В цьому випадку необхідну пам'ять для даних, заздалегідь не визначеного розміру, необхідно виділяти динамічно в процесі роботи програми, з вільного простору купи.
На Паскалі пам'ять під будь-яку динамічно розміщувану типізовану змінну виділяється процедурою 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 розмір запрошеної динамічної памяті в байтах.
На закінчення наведемо практично корисний приклад [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.
Виділимо в підпрограмі, багато разів виконувані групи операндів у вигляді процедури і двох функцій:
Приклад 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. Нарисувати схему алгоритму програми BigMatr (Приклад 10.1)
Приступаємо до розділу головного джерела помилок початкуючого програміста. На жаль, більшість авторів підручників по Паскалю і Сі приділяють незаслужено мало уваги проблемі вводу/виводу. Тут, окрім розуміння логіки роботи програмних операторів, необхідне розуміння механізму обміну даними із зовнішніми пристроями, що має свої нюанси. Рекомендуємо найуважнішим чином пропрацювати цей розділ, експериментуючи на комп'ютері. Вся інформація цього розділу, якісно засвоєна, - це база для освоєння вводу/виводу в інших мовах, зокрема в С (С++).
Практично будь-яка, більш-менш складна прикладна програма оперує із зовнішніми даними. Ми знайомі вже з командами введення даних з клавіатури і виводу на екран дисплея. Тепер познайомимося з введенням/виводом даних на зовнішні носії файли на дисках і потоки даних в каналах так званих логічних пристроїв (консоль, біт-паралельний LPT-порт принтера і біт-послідовні COM-порти телекомунікаційного зв'язку).
Файлом називається іменована область зовнішньої пам'яті на дисках або потік даних логічного пристрою. Програма може працювати одночасно з декількома файлами. Кожен файл складається з компонентів одного типа. Типом компонентів може бути будь-який тип Тубо Паскаля (див. рис.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), то при читанні файлу як символьного ці коди, що управляють, в ПОП не будуть передані.
Для доступу до файлу або логічного пристрою необхідно виконати дві дії:
Файлова змінна зв'язується з ім'ям файлу в результаті звернення до стандартної процедури ASSIGN (призначити, англ.):
ASSIGN(<имя_файлової_змінної>,<імя_файлу або логич.пристрій>);
Ім'я файлу або логічний пристрій текстовий рядок, що містить ім'я файлу на диску або логічний пристрій. Наприклад, ASSIGN(f5,D:\ цех1\ Товари на складі).
Якщо ім'я файлу задається у вигляді порожнього рядка, наприклад, ASSIGN(f5,), то залежно від напряму обміну даними файлова змінна зв'язується із стандартним файлом INPUT (ввід даних з клавіатури) або OUTPUT (виведення на екран). Такий прийом дуже зручний при налагодженні програм. Після закінчення налагодження програми необхідно в ASSIGN поставити правильне ім'я файлу. Якщо файл знаходиться в директорії, відмінній від директорії, звідки ми запускаємо нашу *.exe-програму, необхідно указувати повний шлях до файлу, як показано вище.
Стандартні апаратні засоби ПК, такі як клавіатура, екран дисплея, принтер і комунікаційні канали вводу/виводу, визначаються в Турбо Паскалі спеціальними іменами, які називаються логічними пристроями.
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 логічне ім'я 'порожнього' пристрою. Воно зазвичай використовується при налагодженні програми і трактується як пристрій-приймач інформації необмеженої ємкості.
Процедура відкриття файлу полягає в:
БУД будується при кожному відкритті файлу. За допомогою декількох ASSIGN() і процедур відкриття можливі одночасні відкриття одного і того ж файлу в декількох місцях програми і незалежна робота з його даними в кожному потоці.
Є три функціонально різні процедури відкриття файлів (<ф.п.> - ім'я файлової змінної):
стиранням попередньої інформації }
дозапису нових рядків в кінець файлу }
Процедура 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() приведе до автоматичного закриття цього файлу і відкриття його знов, але вже для додавання записів.
Після відкриття файлу з'являється можливість виконання безпосередньо процедур обміну даними із зовнішнім носієм. Читання даних з файлу виконується за допомогою стандартних процедур:
текстових файлів}
текстових файлів}
де <ф.п.> - ім'я файлової змінної,
<сп.вводу> - список змінних введення - імена змінних через кому,
<симв_сп.вводу> - список змінних - імена змінних (типа char, string[], integer, real и.т.п.) через кому; інформація у вхідному рядку має бути розбита на лексеми смислові групи символів, відокремлених один від одного одним або декількома пропусками, якщо число запрошуваних змінних менше числа лексем, то лексеми, що залишилися, до кінця рядка пропускаються, а нова операція READLN починається з першої лексеми нового рядка,
<буф> - ім'я буфера прийому байтів інформації,
<NT> - кількість записів формату, вказаного в RESET(,) безформатного файлу, які необхідно прочитати за одне звернення BLOCKREAD,
<NF> - кількість записів формату, вказаного в RESET(,) безформатного файлу, які фактично прочитані за одне звернення BLOCKREAD.
З розгляду формату звернення в процедурі BLOCKREAD стає зрозумілою наша рекомендація указувати в RESET(,) довжину запису рівної 1: при одиничній довжині відповідь в <NF> завжди буде правильною, навіть якщо останній сектор файлу заповнений не повністю (а це буває практично завжди!).
Оскільки при читанні з файлу або логічного пристрою можливі помилки передачі даних - досить окремий, але неприємний випадок, рекомендуємо після кожного введення аналізувати на наявність помилки системну змінну IOResult (IOResult<>0), як це описано вище для процедур відкриття файлу. Це ж зауваження стосується і процедур виводу.
Запис даних у файл виконується за допомогою стандартних процедур:
типізується, або текстовий }
текстовий файл з додаванням признаку EOLn (коди #13(CR), #10(LF) )}
виведення даних на зовнішній носій }
По аналогії з кораблеводінням, називатимемо навігацією вводу/виводу визначення поточного положення покажчика (корабля) і курс мети його переміщення. Природно, навігаційні можливості файлів послідовного доступу (текстових) обмежені. Але по двійкових файлах ми маємо можливість 'плавати ' у будь-якому напрямі.
У текстовому файлі ми маємо єдину можливість навігації - перехід на кінець файлу по команді APPEND для дозапису у файл. Для двійкових файлів (що типізуються і безформатних) є три підпрограми навігації:
де:
<ф.п.> - ім'я файлової змінної,
Nкомп. вираз типа LONGINT, вказуючі номер компоненту файлу, до якого необхідно перейти для подальшої обробки. Перший компонент файлу має номер 0.
Приклад. Щоб перемістити покажчик в кінець файлу, що типізується або безформатного, необхідно написати:
SEEK(<ф.п.>, FILESIZE(<ф.п.>));, де <ф.п.> - ім'я файлової змінної.
Закриття файлу всіх типів виконується однією процедурою:
CLOSE(<ф.п.>).
Процедура CLOSE забезпечує коректне завершення операцій вводу/виводу з відкритим файлом. За цією безневинною фразою криється величезний досвід помилок і марних зусиль програмістів в боротьбі з непокірним вводом/виводом.
Проблема полягає в нерозумінні механізму буферировання вводу/виводу. Ми вже відзначали, що при вводі/виводі інформація змінних безпосередньо не взаємодіє з даними зовнішнього пристрою. Обмін даними відбувається через програмно недоступний проміжний буфер. Він досить великий, і з боку зовнішнього пристрою інформація прочитується групами секторів так званими кластерами. Причому виконує цей ввод/вивід не наша програма, а програми операційної системи. Обмін же інформацією між проміжним буфером і змінними програми виконується по записах. Це два асихронно виконуваних обчислювальних процеса. Закриття файлу викликає автоматичне примусове виштовхування залишків необробленої інформації проміжного буфера в ту або іншу сторону при записі/читанні даних.
Характерна ситуація: якщо не виконувати CLOSE втрачається остання порція інформації, що виводиться на диск. Не сподівайтеся на завіряння розробників трансляторів, що досягнення END. - кінця програми, автоматично закриває всі відкриті в програмі файли. Це не відповідає дійсності, в чому зможемо переконатися на наведеному нижче Прикладі 11.2. Не ризикуйте, своєчасно закривайте файли, з якими закінчена робота.
Окрім основних стандартних підпрограм управління вводом/виводом бібліотека Турбо Паскаля представляє цілий набір додаткових процедур і функцій, що розширюють функціональні можливості управління вводом/виводом. У Таблиці 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(<ф.п.>,<час>) |
- (процедура) |
Встановлює нову дату створення або оновлення файлу. Це архаїзм, оскільки час створення/корекції файлу встановлюється автоматично засобами ОС. |
Проілюструємо все викладене вище. Наприклад, необхідно сформувати відомість на отримання стипендії Вашої групи. Для цього Вам необхідно мати:
TYPE TFIO= RECORD
FIO: string[40]; {Прізвище_ имя_ по батькові студента}
Nstud: word; {ключ-ідентифікатор студента номер залікової книжки}
END;
TYPE Tstpnd=RECORD
Nstud: word; { номер залікової книжки студента }
Stpnd: real; {нарахована стипендія}
END;
Послідовно виконаємо кроки:
Приклад 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. Нарисувати блок-схему програми Прикладу 11.2
Екран дисплея утворений матрицею крапок, що світяться, званих пікселями. Світимістю пікселів можна управляти. У кольорових дисплеях піксель складається з тріади близькорозташованих точок червоного, зеленого і блакитного світіння (RGB red, green, blue,англ). Управляючи інтенсивністю цих трьох основних кольорів, можна отримувати всі відтінки спектру від чорного (немає світіння точок тріади) через чисті барви веселки і їх відтінки до білого (однакова інтенсивність світіння точок тріади).
Роздільна здатність екранів сучасних дисплеїв настільки велика, що неозброєним оком неможливо розгледіти окремі пікселі, не говорячи вже про три точки RGB в кожному пикселі. Матриця пікселів мого (не дуже сучасного) дисплея має 1536 рядків з 2048 пікселями в кожному рядку.
Кількість градацій світіння пікселя залежить від способу використання розрядності відеопам'яті. Колірний відтінок пікселя може описуватися:
У старовинному Тубо Паскалі 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 можуть виконувати наступні дії:
Ініціалізація графічного режиму виконується за допомогою звернення до процедури 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 поверне нульовий код завершення, тому для багатократного використання коду завершення необхідне перше звернення до цієї функції запам'ятати в робочій комірці.
Положення покажчика в графічному режимі визначається відносно початку координат - лівого верхнього кута екрану дисплея (координати - 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 (см.нижче).
Процедура 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.
Як зазначено вище, колір пікселя, що окремо виводиться, задається безпосередньо в процедурі. Решта всіх примітивів малюється кольором, що заздалегідь встановлюється процедурою 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; {Покажчик над текстом}
Турбо Паскаль 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
Контрольні питання:
Індивідуальні завдання для виконання компютерних практикумів [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
оператор
оператори альтернативного вибору 107
операторні дужки - 32
операції 49
- арифметичні - 49
операційна система ( ОС) 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-порти