- •Основи програмування мовою Паскаль
- •Часть 1. Основы языка Паскаль 2
- •Часть 2. Элементы профессионального программирования на Паскалі 62
- •Частина 1. Основи мови Паскаль
- •1. Алгоритм і програма
- •1.1. Алгоритм
- •1.2. Властивості алгоритму
- •1.3. Форми запису алгоритму
- •1.4. Програма й програмне забезпечення
- •1.5. Етапи розробки програми
- •2. Дані в мові Паскаль
- •2.1 Константи
- •2.2 Змінні й типи змінних
- •3. Арифметичні вирази
- •4. Лінійний обчислювальний процес
- •4.1 Оператор присвоювання
- •4.2 Оператор уведення
- •4.3 Оператор виведення
- •4.4 Керування виводом даних
- •4.5 Вивід на друк
- •5. Структура простої програми на Паскалі
- •6. Компілятор і оболонка Turbo Pascal
- •7. Обчислювальний процес, що розгалужується, і умовний оператор
- •7.4. Короткий умовний оператор
- •If логічний_вираз then оператор1;
- •7.5. Повний умовний оператор
- •If логічний_вираз then оператор1
- •7.7. Вкладені умовні оператори
- •7.9. Приклади програм з умовним оператором
- •8. Директиви компілятора й обробка помилок уведення
- •9. Оператор циклу. Цикли із передумовою і після-умовою
- •10. Цикл із лічильником і дострокове завершення циклів
- •11. Типові алгоритми табулювання функцій, обчислення кількості, суми й добутку
- •11.1 Алгоритм табулювання
- •11.2 Алгоритм організації лічильника
- •11.3 Алгоритми нагромадження суми й добутку
- •12. Типові алгоритми пошуку максимуму й мінімуму
- •13. Розв'язок навчальних завдань на цикли
- •14. Одномірні масиви. Опис, уведення, вивід і обробка масивів на Паскалі
- •15. Розв'язок типових завдань на масиви
- •Частина 2. Елементи професійного програмування на Паскалі
- •16. Кратні цикли
- •16.1 Подвійний цикл і типові завдання на подвійний цикл
- •16.2 Оператор безумовного переходу
- •17. Матриці й типові алгоритми обробки матриць
- •18. Підпрограми
- •18.1 Процедури
- •18.2 Функції
- •18.3 Масиви як параметри підпрограми
- •18.4 Відкриті масиви
- •19. Безлічі й перечислимые типи
- •20. Обробка символьних і строкових даних
- •20.1. Робота із символами
- •20.2 Робота з рядками
- •21. Текстові файли
- •21.1 Загальні операції
- •21.2 Приклади роботи з файлами
- •21.3 Робота з параметрами командного рядка
- •22. Записи. Бінарні файли
- •23. Модулі. Створення модулів
- •23.1. Призначення й структура модулів
- •Implementation
- •23.2. Стандартні модулі Паскаля
- •24. Модуль crt і створення простих інтерфейсів
- •25. Модуль Graph і створення графіки на Паскалі
- •Додаток 1. Таблиці Ascii-Кодів символів для операційних систем dos і Windows
- •Додаток 2. Основні директиви компілятора Паскаля
- •Додаток 3. Основні повідомлення про помилки Паскаля
- •Додаток 4. Додаткові лістинги програм
- •Додаток 5. Розширені коди клавіатури
- •Ascii‑ коди
- •Розширені коди
- •Додаток 6. Правила гарного коду
- •Додаток 7. Рекомендована література
Додаток 5. Розширені коди клавіатури
Натискання клавіші перетвориться у двухбайтовый код, називаний скан‑ ASCII‑ кодом. Цей код міститься в буфер клавіатури, звідки Ваша програма може вважати його за допомогою переривання системи BIOS. Старший байт двухбайтового коду називається скан‑ кодом і є відображенням фактично натиснутої клавіші. Скан‑ код не відбиває стан клавіш Shift, Ctrl або Alt і не є унікальним. Крім скан‑ кодів натискання, існують коди відпускання клавіш, що відрізняються на шестнадцатеричное значення 80 убік збільшення. Молодший байт повного коду, називаний ASCII‑ кодом, також не є унікальним, але повна комбінація скан і ASCII‑ кода унікальна. Деякі клавіші не мають ASCII‑ коду й замість нього вертається нуль. Такі двухбайтовые коди називаються розширеними. При прийманні коду натиснутої клавіші через DOS остання відокремлює від загального значення скан‑ код. Крім того русифікатор, що працює в системі,‑ може додатково транслювати скан коди‑ буквених клавіш в ASCII коди російських букв.
Виходячи зі сказаного, при використанні стандартної функції Readkey, що працює з ASCII‑ кодами клавіш, у загальному випадку є правильної наступна схема обробки на Паскалі:
Ch := Readkey; {Читання символу в байт Ch}
if Ch = #0 then begin
{Якщо немає ASCII‑ коду,
прочитати додатково розширений код}
Ch := Readkey;
{Обробка розширеного коду}
end
else
{Обробка ASCII‑ коду}
На Паскалі десятковий код може бути записаний у вигляді #N, деN– число, наприклад,#65 ('A' латинська). ASCII‑ коди основних друкованих символів можна довідатися з Додатка 1, інші потрібні коди приводяться далі.
Ascii‑ коди
ENTER |
13 |
Пробіл |
32 |
ESC |
27 |
Backspace |
8 |
Tab |
9 |
|
|
Розширені коди
Клавіша |
Код |
Код з Shift |
Код з Ctrl |
Код з Alt |
F1 |
59 |
84 |
94 |
104 |
F2 |
60 |
85 |
95 |
105 |
F3 |
61 |
86 |
96 |
106 |
F4 |
62 |
87 |
97 |
107 |
F5 |
63 |
88 |
98 |
108 |
F6 |
64 |
89 |
99 |
109 |
F7 |
65 |
90 |
100 |
110 |
F8 |
66 |
91 |
101 |
111 |
F9 |
67 |
92 |
102 |
112 |
F10 |
68 |
93 |
103 |
113 |
Стрілка нагору |
72 |
|
|
|
Стрілка вниз |
80 |
|
|
|
Стрілка вліво |
75 |
|
|
|
Стрілка вправо |
77 |
|
|
|
Insert |
82 |
|
|
|
Delete |
83 |
|
|
|
Home |
71 |
|
119 |
|
End |
79 |
|
117 |
|
Page Up |
73 |
|
132 |
|
Page Down |
81 |
|
118 |
|
Додаток 6. Правила гарного коду
Написання гарного й ефективного програмного коду — ціле мистецтво, багато в чому, на жаль, подзабытое у зв'язку з вибуховим ростом потужності обчислювальних обладнань, що викликали зниження вимог до якості алгоритмів. Це невеликий додаток не може замінити вивчення спеціалізованих дисциплін, начебто "Технології програмування" або "Теорії алгоритмів і формальних мов", але проходження викладеним тут принципам дозволить починаючому програмістові звикати не просто "вирішувати завдання", а робити це можливо більш гарним і економічним з погляду обчислювальних витрат способом.
1. Структурируйте й вирівнюйте код, принаймні так, як сказано в главі 5. Протягом усієї книги я теж форматував лістинги у звичному для себе стилі. Краще звикнути структурировать текст, зрушуючи будь-які вкладення й розгалуження коду одним‑ двома пробілами вправо. Програма при цьому не "роз'їдеться" далеко вправо на складних блоках, а вид тексту, відкритого в будь-якому редакторі, не буде залежати від розміру відступу табуляції.
2. Давайте змінним осмислені імена. Змінна з іменем Length, або, у крайньому випадку,Dlina, сама нагадає про своє призначення, на відміну відL. C іншої сторони, не забороняється використовувати стандартні скорочення –Sдля площі,Pдля периметра,a,bіc– для сторін трикутника. Будь-які індекси природно виглядають із іменами i,j,kі т.д. Але якщо індекс позначає, наприклад, номер місяця в році, куди естественней назвати йогоmonth, чомуi. Хоча Паскаль і не розрізняє регістр букв в іменах змінних і службових словах – дотримуйте його скрізь. Більшість професійних мов регістр символів розрізняють.
3. Існує безліч угод про іменах змінних — можна сперечатися про їхні гідності й недоліках, але безперечно одне — дотримання однакового стилю іменування набагато полегшує розуміння й модифікацію програми. У складних проектах осмислених імен змінних може виявитися недостатньо, тоді на допомогу прийдуть префікси. Так, якщо все імена всіх змінн, що ставляться до таблиці "Студенти", починаються наst_, а всі динамічні покажчики мають в імені префіксp_( від англ. "pointer" – покажчик), читати таку програму буде набагато простіше.
4. Створюючи будь-яку змінну, зверніть увагу на наступні моменти:
який тип значень може ухвалювати змінна, чи нельзя замінити її перерахуванням, безліччю або іншим "скороченим" типом даних?
чи є обмеження на припустимі значення, якщо так, де і як вони будуть враховані?
що відбудеться при переповненні значення або спробі дати змінної неприпустиме значення?
5. Закривайте блоки відразу. Такий блок, як
if умова then begin
end
else begin
end;
або
while умова do begin
end;
пишеться відразу, а тільки потім галузі алгоритму або тіло циклу наповнюються вмістом. Це допоможе не заплутатися в складному коді й полегшить дотримання наступного принципу.
6. Не залишайте непрацюючий додаток "на завтра". Блочно‑ модульна структура програми дозволяє завжди уникнути цього. Підпрограма може бути порожньою "заглушкою", Ви можете використовувати нічого умови, що не роблять, порожні блоки, коментарі, але поточний код повинен компілюватися, якщо завтра Ви не прагнете половину робочого дня затратити на відновлення в пам'яті недоробленого сьогодні.
7. Доводите програму до відсутності попередженькомпілятора, а не тільки помилок. Невідомо, як позначаться насправді ці "безневинні" нагадування. У мові Си конструкція видуif a:=0припустима й викличе лише попередження "Possibly incorrect assignment" — хоча в результаті зміннаaзавждибуде одержувати значення 0 і галузі алгоритму, прив'язана до цієї умови, буде завжди виконуватися.
8. Вибирайте більш короткі типи даних там, де це доречно: часто Byteможе замінитиWordабоInteger, аString[20]— простоString.
9. Застосовуйте можливо більш ефективний алгоритм розв'язку — насамперед, оцінка ефективності пов'язана із залежністю числа виконуваних операцій від розмірності даних. Подвійний цикл повної обробки всіх елементів матриці простий у вивченні, але далеко не завжди є кращим розв'язком при роботі з реальним завданням – адже трудомісткість цього алгоритму рівна n2, де n — розмірність матриці.
10. Вибирайте менш трудомісткі операції. Так, n divkкраще, чимTrunc(n/k), аInc(i);краще, чимi:=i+1;. У всіх випадках порядкові оператори й операнды працюють швидше, чим дійсні. Тому обходитеся порядковими даними скрізь, де це можливо. Особливо уникайте без необхідності розподілу на дійсні числа.
11. Не забувайте про погрішності при роботі з речовинними числами. Хрестоматійне while x<=2.5 do …— погано, якщоx— речовинний. З іншого боку,while abs(x-2.5)<epsвиглядає громіздко й вимагає зайвих обчислень. Найкращеwhile x<=2.5+eps, оптимизирующий компілятор однаково перетворить2.5+epsу константу.
12. Використовуйте стандартні функції мови, на якій пишете. Уявна економія ресурсів, досягнута написанням власних підпрограм нижнього рівня, обернеться трудноуловимыми помилками в більших проектах. Після п'яти‑ десяти років практики це стає ясно кожному програмістові, хоча експерименти із власними інтерфейсами й машинно‑ орієнтованими програмами бувають цікаві й навіть корисні на етапі навчання.
13. Стежите за умовами. Якщо Ви перевіряєте те саме умова кількаразова — скоріше всього, у Вашої програми не в порядку з логікою. Приклад з розділу 7.7 показує це наочно.
14. Не забувайте про взаємовиключні умови. Складений умовний оператор if … else ifабо жcaseу таких випадках набагато краще набору коротких умовних операторів.
15. Найчастіше при написанні довгих фрагментів коду зручніше обробляти помилки у вигляді
if помилка then завершення;
обробка;
чим за схемою
if вірно then обробка
else завершення;
Взагалі, уникайте elseрядків, що перебувають, через 100послусвого if — це утрудняє сприйняття навіть гарне структурованої програми.
16. Уникайте в циклах обчислень, що не залежать від їхніх параметрів! Вирази начебто Sin(Pi/n), поміщене в цикл, деnне міняється, виглядає безглуздо. Адже кожне обчислення синуса ( як і інших стандартних функцій) — це трудомістке розкладання в ряд Фур'є, виконуване машиною.
17. Використовуйте математику там, де це доречно для скорочення трудомісткості коду й числа порівнянь. Перевірити, що змінні xіyмають один знак, можна так:
if (x>0) and (y>0) or (x<0) and (y<0) then …,
а можна й у вигляді
if (x*y>0) then …
18. Припиняйте цикли, коли результат уже досягнуться. Пріоритет засобів при цьому наступний:
використання циклів repeat-untilабоwhile-doзамістьfor;
оператори breakабоexit;
в останню чергу – goto, і тільки у випадках, описаних у розділі 16.2.
19. Тимчасовий "робітник" масив того ж порядку, що створюваний або прочитаний з файлу — майже завжди не кращий розв'язок. Його використання говорить про те, що завдання вирішується "у чоло" і не кращим способом. Припустимим уважається використання одномірного робочого масиву при обробці матричних даних — якщо розмірність його не перевищує більшої з размерностей матриці.
20. Іменуйте розмірні константи масивів! Нікому не потрібні кілька циклів з верхніми границями-"близнюками". А що, якщо розмірність оброблюваних даних прийде змінити?
21. Передавайте значення підпрограмам переважно за адресою, а не за значенням. Для матричних і векторних даних намагайтеся робити це завжди. Застосування векторних даних має пріоритет перед матричними.
22. Не робіть підпрограми залежними від глобальних даних. Недотримання цього правила суттєво зменшити ймовірність повторного використання коду Вами або іншим розроблювачем.
23. Не пишіть підпрограм, що повертають більш одного об'єкта — скаляра, вектора або матриці. У крайньому випадку, можна окремим параметром передавати або повертати розмірність векторних даних. Уникайте підпрограм, які нічого не повертають. Розробка складних підпрограм полегшує, якщо їх "крапка виходу", що й вертається значення зазначені єдиним і останнім оператором. Для переходу з тіла підпрограми в крапку повернення в цьому випадку не грішно використовувати навіть goto:
function Test (a,b:integer):integer;
label End_of_Test;
var error:integer;
begin
error:=0;
if (a<0) or (b<0) then begin
error:=1;
goto End_of_Test;
end;
. . .
End_of_Test:
Test:=error;
end;
24. Потрібно привчити себе не тільки правильно називати змінні й функції, але й виділяти всі логічні частини завдання при проектуванні ієрархії підпрограм. Наприклад, якщо функція шукає в наборі даних елемент за якоюсь ознакою, і створює новий у тому випадку, коли шуканий елемент виявлений, то краще розділити її на дві — функцію пошуку й функцію створення нового вузла, яка буде викликатися з першої. Досить дотримуватися подібних немудрих прийомів, щоб підвищити сопровождаемость програми в рази. Якщо подивитися на запитання з іншого боку, не змушуйте одну підпрограму виконувати кілька функцій — вона виявиться пошук з погляду повторного використання коду. Так, визначення довжини ламаної лінії можна реалізувати однієї підпрограмою, але набагато краще, якщо завдання розбите на підпрограми обчислення довжини й обчислення відстані між двома крапками.
25. При роботі з динамічними об'єктами пишіть код так, щоб відкриті об'єкти завжди закривалися, як тільки вони стануть не потрібні. В ідеалі порядок закриття об'єктів повинен бути зворотним стосовно порядку відкриття (останній об'єкт, що зайняв пам'ять, звільняє її першим). Слід також уникати функцій перерозподілу раніше виділеної динамічної пам'яті.
26. Перевірити логікові своєї програми легше всього за принципом "Одне виправлення — одне місце в програмі". Якщо при додаванні в меню нового пункту або, ще гірше, простій зміні розмірності одномірного масиву доводиться переписувати трохи вилучених друг від друга фрагментів коду – програма написана погано.
27. Якщо написана Вами програма не працює або працює "криво", помилка лежить на вашій совісті, а комп'ютер з компілятором ні в чому не винуваті. "Налагодження", при якій програміст хаотично міняє те одне, те інше місце в коді й на яку йде до 90% часу написання, насправді — свідчення не занадто якісної роботи. Добре написаній програмі потрібна не стільки налагодження, скільки тестування на різних припустимих, неприпустимих і "прикордонних" наборах даних. До речі, обмірковування й написання тестів дотестируемого кода сприяє й поліпшенню, і більшої стійкості кінцевого продукту.
Резюмуючи, можна сказати, що все більші програми на світі написані тільки за рахунок одного — правильного структурування коду. І гарний програміст — не той, хто "знає мови", а той, хто вміє писати, що легко читається, розуміється код, що й модифікується, максимально використовуючи стандартні засоби мови розробки.