Лекція №9 Тема: Процедури та функції План заняття: Процедури без параметрів Процедури з параметрами (параметри-значення) Функції Побічні ефекти функції Процедури без параметрів Часто виникає ситуація, коли в різних місцях програми доводиться виконувати один і той же ж алгоритм, що має самостійне значення. Це може бути, наприклад, відшукання найбільшого спільного дільника двох натуральних чисел, упорядкування компонентів вектора за зростанням чи спаданням, розв'язування систем алгебричних рівнянь тощо. Якщо цей алгоритм досить складний і є доволі великим фрагментом програми, то нераціонально виписувати його кожного разу в тому місці програми, де його треба використовувати. У більшості мов програмування, у тім числі в мові Паскаль, такий алгоритм можна виділити з основної програми і записати його тільки один раз, зобразивши у вигляді самостійного програмного об'єкта, який називають процедурою. Процедуру визначають за допомогою опису, що розміщений у розділі опису процедур і функцій. Вона має таку ж структуру, як і програма, тобто складається із заголовка і блоку -тіла процедури. Заголовок починається службовим словом procedure, містить ім'я, що відповідає цій процедурі, а також може містити параметри - деяку додаткову інформацію, яка полегшує використання цієї процедури. Для активізації процедури в потрібному місці програми записують оператор її виклику. Його зображають іменем процедури і, можливо, списком параметрів, за допомогою яких конкретизують дію процедури, яку викликають. Розглядаючи різні способи використання процедур, братимемо для прикладів таку задачу: за заданими дійсними значеннями х і у обчислити и=тах(х+у, х*у), v=max(0.5, и). Розробимо програму max: program max; var x, у, u, v: real; a, b, s: real; begin read(x,y); a:=x+y; b:=x*y; if a>b then s:=a else s:=b; u:=s; a:=0.5; b:=u; if a>b then s:=a else s:=b; v:=s; writeln('u=',u,' v=',v) end. У цій програмі умовні оператори цілковито збігаються. Щоб уникнути дворазового записування однакового оператора в розділі операторів програми, оголосимо його процедурою. Надамо цій процедурі ім'я тах2а: pocedure max2a; begin if a>b then s:=a else s:=b end; З використанням цієї процедури програма матиме такий вигляд : program max; var x, у, u, v: real; a, b, s: real; procedure max2a: begin if a>b then s:=a else s:=b end; begin read(x,y); a:=x+y; b:=x*y; max2a; u:=s; a:=0.5;b:=u; max2a; v:=s; writeln('u=',u,' v=',v) end. Виконання кожного з операторів max2a зводиться до виконання тіла процедури з цим іменем. Перевага застосування процедури стає очевидною, коли тіло складається зі значної кількості операторів, однак і в цьому випадку програма стала компактнішою і наочнішою порівняно з попереднім варіантом. Процедури з параметрами (параметри-значення) Описана процедура тах2а не дуже зручна в користуванні, оскільки для неї жорстко зафіксовані вхідні дані а та b так, що перед кожним звертанням до процедури цим змінним потрібно присвоїти значення, з яких треба вибрати більше. Щоб уникнути цього обмеження, в мові Паскаль передбачено змогу не фіксувати вхідних даних, з якими повинна працювати процедура, а зробити їх параметрами процедури, які конкретизуватимуться під час кожного звертання до процедури. Стосовно процедури тах2а введемо формально два ідентифікатори, наприклад r1 і r2, якими відобразимо значення, які порівнюють і з яких вибирають більше, і щодо них запишемо тіло процедури: begin if r1>г2 then s:=r1 else s:=r2 end Ці ідентифікатори називають формальними параметрами процедури. Під час кожного звертання до процедури її формальні параметри конкретизуються. Тому, щоб виділити ці параметри з-поміж Інших змінних процедури, їх явно зазначають у заголовку процедури і впорядковують. Для кожного параметра потрібно вказати його тип, тобто тип того значення, що його відображає цей формальний параметр. Тоді наша процедура матиме вигляд procedure max2b(r1, г2: real); begin if r1>r2 then s:=r1 else s:=r2 end; Під час звертання до неї оператор цієї процедури містить її ім'я, за яким у круглих дужках зазначений список фактичних параметрів - значень або виразів, за якими обчислюють значення, що присвоюються формальним параметрам процедури. Типи формальних і фактичних параметрів повинні збігатися. Оскільки в нашому випадку тип формальних параметрів real, тому фактичним параметром може бути будь-який арифметичний вираз. Відповідність між формальними і фактичними параметрами визначається шляхом їх зіставлення в обох списках: перший за порядком фактичний параметр відповідає першому формальному, другий фактичний параметр відповідає другому формальному і т.д. Тепер наведену вище програму можна записати так: program max; var x, у, u, v: real; s:real; procedure max2b(r1, r2: real); begin if r1>r2 then s:=r1 else s:=r2 end; begin read(x,y); max2b(x+y,x*y); u:=s; max2b(0.5,u); v:=s; writeln('u=',u,' v=',v) end. Отже, в процедурі є свої внутрішні змінні, імена яких збігаються з формальними параметрами. Ці змінні діють тільки протягом виконання процедури. Під час входження в процедуру їм присвоюються значення, задані відповідними фактичними параметрами в операторі процедури. Функції У математиці за допомогою функцій задають залежності одних величин від інших, які називають аргументами. Такі залежності бувають у вигляді таблиць, графічні, аналітичні тощо. В алгоритмічних мовах розглядають лише функції, для яких можна задати алгоритм визначення їхніх значень. Мова Паскаль допускає тільки такі функції, значення яких належать до простих типів. Для визначення функцій використовують опис функцій, який розміщують у розділі опису процедур і функцій. Загальний вигляд опису функцій такий: function<ім'я_функції>(<список_фомальних_параметрів>):<тип_функції>; <блок> Іменем функції може бути довільний ідентифікатор. Список формальних параметрів визначають так само, як і для процедур, допустимі функції без параметрів. Параметрами функції можуть бути як параметри-значення, так і параметри-змінні, тобто конкретні аргументи функції можна викликати як значеннями, так і за іменем. У цьому випадку аргументи можуть мати різні типи, не обов'язково прості. Як бачимо, щодо цього функції нічим не відрізняються від процедур. Заголовок функції завершується іменем типу значення описуваної функції, причому зазначають тільки ім'я типу, а не його визначення. Тому типи значень функції повинні бути або стандартними, або попередньо описані з зазначенням їхнього імені. У блоці описуваної функції повинен бути хоча б один оператор типу <ім'я функції> := <вираз> Це означає, що за значення функції прийнято значення присвоюваного виразу. Таких операторів присвоєння може бути декілька, проте хоча б один повинен виконуватись у процесі виконання процедури. Як остаточне значення функції приймають результат останнього за часом виконання оператора присвоєння. Наприклад, функцію f(n) = п! можна описати так: function FACT(n: integer): integer; var і, k: integer; begin k:=1; for i:=1 to n do k:=k*i; FACT:=k; end; Як відомо, у мові Паскаль є набір стандартних функцій, які описувати не потрібно. Можна вважати, що ці описи попередньо вставляє транслятор у розділ опису процедур і функцій трансльованої програми. Звертатися до функції можна за допомогою виклику. Виклик-це ім'я функції, після якого в круглих дужках може бути список фактичних параметрів. Наприклад, sin(x+y), FACT(10). Виклик функції використовують як операнд деякого виразу. Наприклад, для обчислення p=(k+1)! можна застосувати описану функцію обчислення факторіала і записати в програмі p:=FACT(k+1). Як бачимо, застосування процедур і функцій подібне. Однак процедури дають змогу виконувати обчислення, результатом яких є декілька значень, тоді як результатом функції є одне значення. Побічні ефекти функції Мова Паскаль допускає застосування таких функцій, які, крім обчислення конкретної функції, можуть виконувати ще деякі додаткові дії, результат яких виявляється поза межами функції. Наприклад, унаслідок виконання функції можуть змінюватися глобальні щодо до неї змінні. Таке явище називають побічним ефектом функції. Побічний ефект функції може бути корисним і зручним або ж завдавати шкоди. Тому функції з таким ефектом треба застосовувати дуже обережно. Особливо вони нерекомендовані в програмах, призначених для значного поширення з наступним їхнім супроводом. Наведемо простий приклад функції з побічним ефектом. Нехай у програмі описані змінні var k, r: integer; У розділі опису процедур і функцій опишемо функцію обчислення факторіала, однак іншим способом, ніж раніше використану FACT: function FACT1(n: integer): integer; var m: integer; begin m:=1; k:=1; repeat m:=m*k; k:=k+1; until k>n; FACT1=m end; ........ k:=5; r:=FACT1(10); writeln(r, k): Одержимо результат r= 10!, а також значення k= 11, оскільки воно зміниться в тілі функції. Цей побічний ефект з'явився внаслідок того, що в тілі функції не описано k, Побічний ефект може виявлятися і в тому, що функція змінюватиме значення фактичного параметра, який викликають іменем, оскільки має безпосередній доступ до нього.