Процедури та функції в мові Паскаль. Сфера дії
описів b>
p>
В
мовою Паскаль (як ви вже зрозуміли з попереднього матеріалу) існують поняття
процедури та функції. Процедури і функції можна визначити як замкнуті
програмні одиниці, що реалізують деякий алгоритм. Фактично процедура або
функція - це майже програма, майже - тому що вона не може виконуватися
самостійно, а завжди викликається якоюсь іншою процедурою або функцією.
Програми, які ми до цих пір писали, теж були процедурами, правда,
кілька особливими - головними процедурами. Програма може містити будь-яку
кількість процедур і функцій, але вона завжди містить одну і тільки одну
головну процедуру, з якої починається виконання програми. p>
Структура
процедури або функції дуже схожа на структуру головної процедури, вона також
містить розділ описів і розділу операторів; розділ операторів починається з
BEGIN і закінчується END; (але не END. - Як у головної процедури). Єдиним
новим оператором для вас буде оператор заголовка, з якого починається будь-яка
процедура і функція. Всі процедури і функції записуються в розділі описів
будь-якої іншої процедури або функції, у тому числі і головною процедури.
Оператор заголовка процедури має вигляд: p>
PROCEDURE ім'я (список параметрів); p>
Тут
ім'я - ім'я процедури (будь-який ідентифікатор), список параметрів може
відсутнім, але якщо він є, записується в круглих дужках після імені
процедури і має вигляд: p>
[VAR] ім'я, ... ім'я: тип; p>
........................... p>
[VAR] ім'я, ... ім'я: тип p>
Тут
ім'я - імена параметрів, кожен параметр може використовуватися усередині процедури
як звичайна змінна відповідного типу. Тип - ім'я типу, але не опис
користувацького типу; скажімо, опис параметра у вигляді x: 1 .. 5 невірно, але,
якщо вище описаний відповідний тип: TYPE MyType = 1 .. 5, то параметр можна
описати у вигляді x: MyType. Ключове слово VAR перед описом параметрів означає
в даному випадку, що всі параметри до ";" або до ")" --
параметри-змінні, якщо ж VAR відсутній, то параметри є
параметрами-значеннями. Сенс цих понять ми розглянемо трохи пізніше. P>
Процедури
викликаються в інших процедурах і функції за допомогою вже відомого вам
оператора виклику: p>
ім'я (список аргументів); p>
Список
аргументів задається в тому і тільки в тому випадку, коли в заголовку процедури
задано список параметрів. Аргументи в списку розділяються комами і можуть бути
будь-якими виразами, якщо відповідний параметр є параметр-значення, або
тільки іменами змінних, якщо відповідний параметр є
параметр-змінна. Кількість аргументів завжди має збігатися з
кількістю параметрів, і тип аргументу повинен бути таким же, як тип
параметра. При виклику процедури значення відповідних аргументів передається
параметрах, і таким чином процедура одержує інформацію з викликає
процедури або функції. Запишемо програму, що використовує процедуру, яка буде
акуратно виводити значення змінної: p>
PROCEDURE OutVar (x: Real; Name: Char); p>
BEGIN WRITELN ( 'Variable', Name, 'дорівнює
', x); END; p>
VAR a, b, c, d: Real; p>
BEGIN WRITE ( 'Введіть змінні a, b, c, d'); READ (a, b, c, d); p>
OutVar (a, 'a'); OutVar (b, 'b');
OutVar (c, 'c'); OutVar (d, 'd'); p>
END. P>
Наша
процедура OutVar отримує з головної процедури дійсне число x і символ
Name, але нічого не передає назад. Тепер спробуємо написати процедуру,
яка по заданих значень x і y обчислює cos (x) + cos (y) і cos (x)-cos (y): p>
PROCEDURE T (x, y: Real; Cplus, Cminus: Real); p>
BEGIN Cplus: = cos (x) + cos (y); Cminus: = cos (x)-cos (y); END; p>
VAR p, m: Real; p>
BEGIN T (1.235,0.645, p, m); WRITELN (p: 7:3, m: 7:3); END. P>
Запустимо
цю програму і - замість правильного результату 1.129, -0.470 - отримаємо у кращому
випадку нулі. Справа в тому, що через параметри-значення (а Cplus і Cminus описані
в нашій процедурі як параметри-значення!) неможливо передати інформацію з
процедури, але лише у процедуру. Щоб правильно вирішити нашу задачу, слід
Cplus і Cminus описати в заголовку як параметри-змінні: p>
PROCEDURE T (x, y: Real; VAR Cplus, Cminus: Real); p>
BEGIN Cplus: = cos (x) + cos (y); Cminus: = cos (x)-cos (y); END; p>
Таким
чином, вхідні параметри процедури можуть бути і параметрами-значеннями й
параметрами-змінними, а вихідні параметри - тільки параметрами-змінними.
Для того, щоб глибше зрозуміти це правило, з'ясуємо, що ж відбувається з
параметрами та аргументами при виклику процедури. У момент дзвінка для кожного
параметра-значення в спеціальній області пам'яті, званої стеком (за контроль
переповнення стека відповідає описана вище опція компілятора Stack cheking),
створюється його копія - змінна відповідного типу, якій присвоюється
значення аргументу. Надалі процедура працює з цією копією, і при виході
з процедури копія знищується. Таким чином, ніякі зміни
параметра-значення не можуть бути відомі за межами процедури. По-іншому
обробляються параметри-змінні: у процедуру передається не значення
аргументу, а його адресу, і вона працює з аргументом (тепер зрозуміло, чому
аргумент, що відповідає параметру-змінної, повинен бути тільки ім'ям
змінної: він повинен мати адресу). Так що всі зміни параметра на самому
справі відбуваються з аргументом і відомі в зухвалому процедурою. p>
Функція,
на відміну від процедури, завжди обчислює деяке значення скалярного типу,
яке всередині функції повинно бути присвоєно імені функції. Заголовок функції
має вигляд: p>
FUNCTION ім'я (список параметрів): тип; p>
В
іншому функції аналогічні процедурам. Звернення до функції здійснюється з
допомогою покажчика функції: p>
ім'я (список параметрів) p>
Покажчик
функції може використовуватися як і будь-яке інше вираження того ж типу, але це
не оператор, на відміну від оператора виклику. Запишемо приклад функції: p>
FUNCTION Na3 (x: LongInt): Boolean; p>
(
функція перевіряє, чи x ділиться на 3) p>
BEGIN Na3: = x MOD 3 = 0; END; p>
VAR L: LongInt; p>
BEGIN WRITE ( 'Введіть ціле число'); READ (L); p>
WRITE ( 'Число', L); p>
IF NOT Na3 (L) THEN WRITE ( 'не'); p>
WRITELN ( 'ділиться на 3 !'); p>
END. p>
В
будь-якої процедури і функції можна використовувати надзвичайно корисну стандартну
процедуру Exit без параметрів для негайного виходу в зухвалу процедуру. p>
Всі
процедури і функції Паскаля є рекурсивними, тобто можуть викликати самі
себе, жодних зусиль з боку програміста для цього не потрібно. В якості
прикладу запишемо функцію, яка обчислює n! p>
FUNCTION Factorial (n: Byte): Real; p>
BEGIN IF n <= 1 THEN Factorial: = 1 p>
ELSE
Factorial: = n * Factorial (n-1); p>
END; p>
Але
це, звичайно, дуже погана функція, набагато краще записати цей алгоритм так: p>
FUNCTION Factorial (n: Byte): Real; p>
VAR i: Byte; f: Real; p>
BEGIN f: = 1; FOR i: = 2 TO n DO f: = f * i; p>
Factorial: = f; p>
END; p>
Отже,
ми знаємо, що програма може містити багато процедур і функцій, і в кожній з
них можуть бути описані типи, константи і змінні. Але не всі з них можуть
бути використані в будь-якому місці програми, кожне опис має строго
певну сферу дії. Нехай процедура А знаходиться всередині процедури В --
домовимося називати процедуру А внутрішньої по відношенню до В, а процедуру В --
осяжний по відношенню до А. Якщо ж ні процедура А не знаходиться всередині В, ні В
не знаходиться всередині А, то ці процедури - зовнішні по відношенню один до одного.
Сфера дії опису будь-якого об'єкта включає ту процедуру, де він описаний
(починаючи з місця опису) і всі внутрішні процедури, якщо там даний
ідентифікатор не описаний. У принципі, це дає можливість передавати інформацію
у процедури та функції, минаючи параметри, тобто користуватися у внутрішній
процедурі змінними, описаними в осяжний процедурі, але такий стиль
програмування вважається ненадійним. Намагайтеся, якщо це можливо, все
змінні, що використовуються у процедурі, описувати в цій процедурі. p>
Для
чого потрібні процедури та функції, коли і як їх слід застосовувати? Багато
починаючі програмісти уникають процедур і функцій, стверджуючи, що "без
них простіше ". Насправді обійтися без функцій і процедур легко тільки в
самих тривіальних програмах. Скільки-небудь складна програма, записана
"одним шматком", вимагає при налагодженні від програміста величезних зусиль,
які найчастіше все одно пропадають марно. Обов'язково використовуйте у своїх
програмах процедури і функції! Гарна програма повинна містити головним
чином звернення до процедур і функцій. Звичайно, не існує ніяких
жорстких правил, що визначають, коли використовувати функції, а коли ні, але автор
цієї книжки може запропонувати кілька нестрогим, але корисних рецептів: p>
--
виділяйте в процедуру (функцію) невеликий логічно завершений фрагмент
алгоритму; p>
--
не змішуйте в одній процедурі (функції) введення-виведення даних та обчислювальні
алгоритми; p>
--
називайте свої процедури (функції) мнемонічний іменами; p>
--
якщо алгоритм, який ви вирішили виділити в процедуру (функцію), все ще
занадто складний, оформіть фрагмент цього алгоритму в іншій процедурі (функції); p>
--
якщо алгоритм повинен обчислити одне скалярний значення, нехай це буде
функція, а не процедура; p>
--
якщо у вашій програмі зустрічаються багато разів вкладені цикли або
"багатоповерхові" умовні оператори, це вірна ознака того, що вам потрібні
процедури (функції); p>
--
якщо текст вашої програми не вміщується на одному екрані - подумайте про
процедурах; p>
--
використовуйте в процедурах та функціях процедуру Exit. p>
Список літератури h2>
Для
підготовки даної роботи були використані матеріали з сайту http://elib.albertina.ru/
p>