Процедури та функції
У мові Паскаль, як і в більшості мов програмування, передбачені засоби, що дозволяють оформлювати допоміжний алгоритм як підпрограму. Це буває необхідно тоді, коли який-небудь підалгоритм неодноразово повторюється в програмі або ж є можливість використовувати деякі фрагменти вже розроблених раніше алгоритмів. Крім того, підпрограми застосовуються для розбиття великих програм на окремі смислові частини відповідно до модульного принципу в програмуванні.
Для використання підалгоритму в якості підпрограми йому необхідно привласнити ім'я і описати алгоритм за правилами мови Паскаль. Надалі, при необхідності викликати його в програмі, роблять виклик підпрограми вказуючи в потрібному місці імені відповідного підалгоритму зі списком вхідних і вихідних даних. Такий запис призведе до виконання вхідних в підпрограму операторів, що будуть працювати із зазначеними даними. Після виконання підпрограми програма продовжує роботу з тієї команди, яка безпосередньо слідує за викликом підпрограми.
У мові Паскаль є два види підпрограм - процедури та функції.
Процедури і функції розміщують в розділі описів програми. Для обміну інформацією між процедурами і функціями і іншими блоками програми існує механізм вхідних і вихідних параметрів. Вхідними параметрами називають величини, які передаються із блоку викликів до підпрограми (вихідні дані для підпрограми), а вихідними – ті, що передаються з підпрограми до блоку викликів (результат роботи підпрограми).
Одна і та ж підпрограма може викликатися неодноразово, виконуючи одні і ті ж дії з різними наборами вхідних даних. Параметри, що використовуються під час запису тексту підпрограми в розділ описів, називають формальними, а ті, що використовуються під час її виклику -фактичними.
Опис і виклик процедур і функцій
Структура опису процедур і функцій деякою мірою схожа на структуру Паскаль-програми: у них також є заголовок, розділ описів і виконувана частина. Розділ описів містить ті ж підрозділи, що і розділ описів програми: описи констант, типів, міток, процедур, функцій, змінних. Виконувана частина містить, власне, оператори процедур.
Формат опису процедури має вигляд:
procedure ім'я процедури (формальні параметри); розділ опису процедур begin виконувана частина процедури end;
Формат опису функції:
function ім'я функції (формальні параметри): тип результату; розділ опису функції begin виконувана частина функції end;
Формальні параметри в заголовках процедур і функцій записують у вигляді:
var ім'я параметру: ім'я типу
і відокремлюються один від одного крапкою з комою. Ключове слово var може бути відсутнім (про це далі). Якщо параметри однотипні, то їх імена можна перераховувати через кому, вказуючи загальне для них ім'я типу. Під час опису параметрів можна використовувати лише стандартні імена типів, або імена типів, визначені за допомогою команди type. Список формальних параметрів може бути відсутнім.
Виклик процедури здійснюється оператором, що має наступний формат:
ім'я процедури (список фактичних параметрів);
Список фактичних параметрів - це їх перерахування через кому. Під час виклику фактичні параметри ніби підставляються замість формальних, що стоять на тих же місцях у заголовку. Таким чином відбувається передача вхідних параметрів, потім виконуються оператори виконуваної частини процедури, після чого відбувається повернення в блок викликів. Передача вихідних параметрів відбувається безпосередньо під час роботи виконуваної частини.
Виклик функції в Турбо Паскаль може відбуватися в аналогічний спосіб, окрім того є можливість здійснити виклик всередині якогось виразу. Зокрема ім'я функції може стояти в правій частині оператора присвоєння, в розділі умов оператора if і т.д.
До повернення в блок викликів необхідно додати наступну команду в виконувану частину функції, для того, щоб передати в блок викликів вихідне значення функції
ім'я функції: = результат;
Під час виклику процедур і функцій необхідно дотримуватися наступних правил.
- кількість фактичних параметрів має збігатися з кількістю формальних;
- відповідні фактичні та формальні параметри повинні збігатися по порядку
проходження і по типу.
Зауважимо, що імена формальних і фактичних параметрів можуть збігатися. Це не призводить до проблем, так як відповідні їм змінні все одно будуть різні із-за того, що зберігаються в різних областях пам'яті. Крім того, всі формальні параметри є тимчасовими змінними - вони створюються в момент виклику підпрограми і знищуються в момент виходу з неї.
Розглянемо використання процедури на прикладі програми пошуку максимуму з двох цілих чисел.
var x,y,m,n: integer; procedure MaxNumber(a,b: integer; var max: integer); begin if a>b then max:=a else max:=b; end; begin write('Введіть x,y '); readln(x,y); MaxNumber(x,y,m); MaxNumber(2,x+y,n); writeln('m=',m,'n=',n); end.
Аналогічну задачу, але уже з використанням функцій, можна вирішити так:
var x,y,m,n: integer; function MaxNumber(a,b: integer): integer; var max: integer; begin if a>b then max:=a else max:=b; MaxNumber := max; end; begin write('Введіть x,y '); readln(x,y); m := MaxNumber(x,y); n := MaxNumber(2,x+y); writeln('m=',m,'n=',n); end.
Передача параметрів
У стандарті мови Паскаль передача параметрів може здійснюватися в два способи – по значенню і по посиланню. Параметри, що передаються по значенню, називають параметрами-значеннями, що передаються по посиланню - параметрами-змінними. Останні відрізняються тим, що в заголовку процедури (функції) перед ними ставиться службове слово var.
Якщо використовується перший спосіб (передача за значенням) значення фактичних параметрів копіюється у відповідні формальні параметри. При зміні цих значень в ході виконання процедури (функції) вихідні дані (фактичні параметри) змінитися не можуть. Тому таким способом передають дані тільки із блоку викликів в підпрограму (тобто вхідні параметри). При цьому в якості фактичних параметрів можна використовувати і константи, і змінні, і вирази.
Якщо використовується другий спосіб (передача по посиланню) всі зміни, що відбуваються в тілі процедури (функції) з формальними параметрами, призводять до негайних аналогічним змінам відповідних їм фактичних параметрів. Зміни відбуваються із змінними блоку викликів, тому по посиланню передаються вихідні параметри. В разі виклику відповідні їм фактичні параметри можуть бути тільки змінними.
Вибір способу передачі параметрів при створенні процедури (функції) відбувається у відповідності до сказаного вище: вхідні параметри потрібно передавати за значенням, а вихідні - по посиланню. Практично це зводиться до розстановки в заголовку процедури (функції) зарезервованого слова var перед всіма параметрами, які позначають результат роботи підпрограми. Однак, у зв'язку з тим, що функція повертає тільки один результат, в її заголовку використовувати параметри-змінні не рекомендується.
Локальні і глобальні ідентифікатори
Використання процедур та функцій в Паскалі тісно пов'язано з деякими особливостями роботи з ідентифікаторами (іменами) в програмі. Зокрема, не всі імена завжди доступні для використання. Доступ до ідентифікатора в конкретний момент часу визначається тим, у якому блоці він описаний.
Імена, описані в заголовку або розділі описів процедури або функції називають локальнимидля цього блоку. Імена, описані в блоці, що відповідає всій програмі, називають глобальними. Слід пам'ятати, що формальні параметри процедур і функцій завжди є локальними змінними для відповідних блоків.
Основні правила роботи з глобальними і локальними іменами можна сформулювати так:
- Локальні імена доступні (вважаються відомими, "видимими") тільки всередині того блоку, де вони описані. Сам цей блок та всі інші, що вкладені в нього, називають областю видимості для цих локальних імен.
- Імена, описані в одному блоці, можуть збігатися з іменами з інших: тих, що утримують даний блок і тих, що вкладені у нього. Це пояснюється тим, що змінні, описані в різних блоках (навіть якщо вони мають однакові імена), зберігаються в різних областях оперативної пам'яті.
Глобальні імена зберігаються в області пам'яті, що називається сегментом даних (статичним сегментом) програми. Вони створюються на етапі компіляції і можуть бути використані будь-коли, за увесь час роботи програми.
На відміну від них, локальні змінні зберігаються в спеціальній області пам'яті, яка називаєтьсястек. Вони є тимчасовими, оскільки створюються в момент входу в підпрограму і знищуються при виході з неї.
Ім'я, що описане в блоці, "закриває" співпадаючі з ним імена з блоків, що містять даний. Це означає, що якщо в двох блоках, один з яких міститься всередині іншого, є змінні з однаковими іменами, то після входу у вкладений блок робота відбуватися з локальною для даного блоку змінною. Змінна з тим же ім'ям, описана в зовнішньому блоці, стає тимчасово недоступною і це продовжується до моменту виходу з вкладеного блоку.
Рекомендується всі імена, що мають в підпрограмах суто внутрішнє, допоміжне призначення, робити локальними. Це запобігає змінам глобальні об'єкти з такими ж іменами.