НОУ ІНТУІТ, Лекція, Підпрограми
Ціль лекції
Освоєння роботи з підпрограмами, з параметрами посилання, параметрами за значенням, з достроковим виходом із програм і підпрограм, з областю видимості змінних.
Підпрограми
Спочатку мови програмування були простішими, вони виконувались строго зверху-вниз, один оператор за іншим. Такі мови ще називалилінійними. Типовий приклад лінійних мов – Бейсік. Єдину можливість організувати хоч якусь логіку в таких мовах надавав оператор безумовного переходу GOTO, який залежно від умови "перестрибував" на заздалегідь розставлені мітки. У сучасних мовах програмування GOTO теж залишився, мабуть, для любителів антикваріату. Але його застосування може призвести до трудно виявлених логічних помилок часу виконання (run-time errors). Використання GOTO у сучасному програмуванні вважається поганим тоном. Ми не вивчатимемо цю можливість, оскільки для організації логіки є куди "просунутіші" кошти! Одним із таких засобів єпідпрограми.
Іншими словами, підпрограми подібні до будівельних цеглинок, з яких виходить будівля - програма. Без підпрограм можна обійтися, якщо ви пишете невелику навчальну програму на кілька десятків рядків коду. А якщо це серйозна програма, з парою сотень модулів, у кожному з яких можуть бути тисячі рядків коду? Як таку програму написати, не розбиваючи завдання окремі частини? Підпрограми допомагають покращити код, структурувати його. Тому мови високого рівня, які дозволяють використовувати підпрограми, називаютьпроцедурно-орієнтованимимовами. І наш компілятор FPC також відноситься до таких мов.
Підпрограми бувають двох типів:процедуритафункції- перші просто виконують свою роботу, другі ще й повертають результат цієї роботи.
Насправді ми вже неодноразово використовували процедури. Наприклад, коли генерували подію натискання кнопки. Ця подія – процедура. Процедура починається з ключового слова procedure і має наступний синтаксис:
Більшість зазначеного синтаксису є необов'язковою - процедура може мати параметрів, констант, користувальницьких типів даних, змінних тощо. - вона може бути дуже простою, наприклад:
Таку процедуру можна викликати з будь-якого місця програми, але процедура обов'язково повинна бути описана вище - інакше компілятор не знатиме про неї. Є ще можливість попередньо оголосити процедуру, але про це трохи згодом. Отже, якщо ця процедура описана вище, ми можемо викликати її, просто вказавши її ім'я:
Компілятор перейде до процедури та виконає її код (у даному випадку – виведе повідомлення про помилку). Після цього компілятор повернеться назад, і виконає оператор, який наступить за викликом процедури.
Параметри підпрограм – досить важлива тема, поговоримо про це детальніше. У процедуру (або функцію) можна передати якісь вихідні дані, щоб процедура їх обробила. Такі дані називаютьсяпараметрами, абоформальними параметрами. Приклад - користувач ввів якесь число (а насправді рядок з цифрових символів), нам потрібно подвоїти його, а результат повідомити користувача. Описати таку процедуру можна так:
оголошує процедуру Udvoenie з параметром рядкового типу st. Це означає, що тепер ми можемо викликати процедуру, передавши їй як параметр якийсь рядок. Параметр st умовно вважатимуться внутрішньої змінної процедури, у яку компілятор скопіюєпередану процедурі рядок. Цей спосіб передачі в підпрограму називаєтьсяпараметром за значенням. Допустимо, надалі ми викликали процедуру таким чином:
Компілятор здійснить виклик процедури, передавши параметр st вказане значення '123.4' . Або ж ми можемо викликати процедуру інакше, передавши в неї значення, яке зберігається в якійсь іншій рядковій змінній:
Результат буде таким самим. Тут важливо пам'ятати, що тип значення, що передається обов'язково повинен збігатися з типом параметра. Якщо параметр у нас string, то і передавати йому потрібно значення типу string. Компілятор копіює це значення параметра . Іншими словами, якщо всередині процедури ми змінимо значення параметра st, це ніяк не позначиться на змінній myst, оскільки ми змінимо копію даних, а не дані.
Ходімо далі. А далі ми оголошуємо речову змінну r :
Тут вона необхідна, адже нам потрібно помножити значення параметра на два, тому ми змушені будемо перетворити рядкове уявлення числа в теперішнє число – адже рядок на два не помножиш! Результат помістимо в r:
Службовим словом begin ми починаємо тіло процедури. Стандартною функцією StrToFloat(st) ми перетворимо рядкове значення параметра st у число, і надамо це число змінної r . Далі все просто:
Ми подвоює значення r , результат цього поміщаємо знову в r , потім стандартною функцією FloatToStr(r) перетворюємо отримане число в рядок, і виводимо цей рядок у повідомленні ShowMessage() . Ось, власне, і все.
Тепер ми зможемо викликати цю процедуру, коли необхідно, і передавати різні цифри у вигляді рядка. А вже процедура сама подбає про всі необхідні перетворення, про подвоєння числа та виведення результатів на екран.
До речі,самі дані, які ми передаємо в підпрограму, називаютьсяаргументамиабофактичними параметрами. У прикладі виклику процедури
змінна myst-аргумент.
Як параметри в процедурі можна використовувати не одну, а безліч змінних. Якщо вони мають однаковий тип, їх імена розділяють комами, а тип вказується в кінці відразу всіх параметрів. Наприклад:
Якщо параметри мають різні типи, їх розділяють крапкою з комою:
Проте, розбавимо теорію практикою, і попрацюємо з процедурами реальному прикладі. ВідкрийтеLazarusз новим проектом. Як завжди, назвемо головну форму (властивість Name ) fMain , збережемо проект у папку09-01, при цьому назвемо проект, наприклад,MyPodprog, а модулю дамо ім'яMain.
В якості Caption форми напишемо
Наше завдання: отримати від користувача дійсне число, подвоїти його і результат вивести на екран. Користувач може ввести і ціле число, але процедура обробить його як речове (пам'ятаєте про перетворення типів у минулій лекції?), наприклад, якщо користувач введе 3, процедура отримає 3.0. В результаті обчислення вийде 6.0, але FloatToStr() кінцеві нулі не виводить, тому користувач побачить на екрані просто 6.
Гаразд, зараз потрібно вирішити, як отримати у користувача число. Для цього використовуємо компонент TEdit, який нам уже знайомий з минулих лекцій. Для початку встановимо мітку TLabel з текстом, що пояснює
а поруч встановимо TEdit. Імена у TLabel і TEdit залишимо за замовчуванням, TEdit називатиметься Edit1 . Не забудьте очистити властивість Text .
Нижче встановіть просту кнопкуTButton, у Caption якої напишіть текст:
Зрозуміло, будуть інші приклади. Підрівняйте компоненти, за необхідностізмініть їх розміри. Наша форма має виглядати приблизно так:

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

Зверніть увагу, ми передаємо в підпрограму значення , яке ввів користувач і яке зберігається у властивості Text компонента Edit1 :
Жодних додаткових змінних у цьому випадку створювати не потрібно. Збережіть проект та запустіть його на виконання. Спробуйте ввести ціле число. Потім речове. Зверніть увагу: якщо у вас встановлена українська версія Windows, то як роздільник речовинного числа нам потрібно вводити кому, а не точку! Пам'ятаєте про глобальну змінну DecimalSeparator?
Якщо ж ви випадково чи навмисно ввели точку, то вийде повідомлення про помилку, подібне до цього:
Нічого страшного, натисніть кнопку "Зупинка", потім виберіть команду головного меню "Запуск -> Скинути наладчик". Lazarus закриє проект, що завис, і ви зможете запустити його знову. Схожа помилка виникне, якщо ви спробуєте подвоїти порожній рядок. Якщо ж ви ввели числа правильно, то програма відпрацює як потрібно незалежно, ціле це було число, або речове. Не закривайте поки що проект, він нам ще знадобиться.