Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Основи програмування Паскаль.docx
Скачиваний:
51
Добавлен:
12.05.2015
Размер:
511.7 Кб
Скачать

18.2 Функції

Про параметри-змінних часто говорять, що підпрограма повертаєїхній значення, підкреслюючи тим самим, що вони є (абоможутьбути) вихідними даними деякого обчислювального процесу.

Поширені підпрограми, що вимагають повернення всього одного вихідного параметра, що є скаляром( тобто, єдиним значенням, а не вектором або матрицею). У цих випадках замість підпрограми-процедури використовується підпрограма-функція, що повертає скалярний результат своєї роботи в основну програму. Тому для функції в її заголовку необхідно вказатитипрезультату, що вертається, а в тілі функції повинен бути присутнім хоча б один оператор присвоювання, у лівій частині якого записується ім'я функції:

Function Ім'я (Список формальних параметрів):Типрезультата;

{вище - заголовок підпрограми}

Var опису локальних змінних;

Begin

{Тіло функції}

Ім'я:=Вирази1;

End;

Тут Вирази1 повинне мати той же тип, що й зазначений у заголовкуТипРезультата, а операторІм'я:=Вирази1; не зобов'язано бути останнім у тілі функції. Оскільки результат виконання функції вертається в основну програмучерез її ім'я, то звертання до функції записується аналогічно стандартним функціяму вигляді операнда вирази, що стоїть праворуч від знака присвоювання:

Результат:=Вирази2;

Вирази2може полягати тільки з виклику функції видуІм'я(список фактичних параметрів)або включати цей виклик як частина більш складного вирази., зміннаРезультатповинна відповідати типу функції. У записі вирази повинні бути дотримані всі вивчені раніше правила відповідності типів.

Усі, сказане вище про узгодження формальних і фактичних параметрів, а також про параметри-значеннях і змінних, повною мірою ставиться й до функцій.

Фактично, стандартні підпрограми Паскаля також діляться на функції й процедури, залежно від способу їх виклику. Так, writelnставиться до стандартнихпроцедур, аsin– дофункцій. Правда, деякі зі стандартних підпрограм мають змінне число параметрів, що заборонене користувацьким підпрограмам.

Зрозуміло, при використанні функцій ніхто не забороняє повертати більш одного значення через параметри-змінні, подібні тим, що ми вивчили для процедур. Можна сказати, що функції в Паскалі – це процедури, здатні повертати додаткове скалярне значення. У багатьох інших мовах програмування спеціального поділу на процедури й функції немає.

Щоб остаточно усвідомити не-синтаксичні відмінності між функціями й процедурами, узагальнимо їх у таблиці:

Процедура

Функція

Викликається окремим оператором

Викликається з вирази праворуч від знака присвоювання

Використовує параметри-значення й змінні

Використовує параметри-значення й змінні, додатково доступний параметр-змінна з іменем, що збігаються з іменем функції

Напишемо й викличемо найпростішу функцію, що знаходить максимальний із двох своїх дійсних аргументів:

Function Max (a,b:real):real;

Begin

If a>b them Max:=a

Else Max:=b;

End;

Викликати цю функцію ми могли б так:

Var x,y,z,r,t:real;

. . .

Read (x,y,z);

r:=max(x,y); {Максимальне зі значень x,y записали в r}

t:=max(max(x,y),z); {Максимальне зі значень x,y,z записали в t}

Останній виклик ілюструє, що, як і стандартні функції, функції, написані програмістом, можуть викликатися з як завгодно складних виразів – за умови, що ми будемо дотримувати правил відповідності параметрів. Написану нами функцію maxневажко було б реалізувати й у вигляді процедури:

Procedure Max (a,b:real; var c:real);

Begin

If a>b them c:=a

Else c:=b;

End;

Однак, при виклику цієї процедури постійно довелося б передавати "зайвий" параметр c, службовець тільки для зберігання, що вертається значення.

Ми вже знайомі з оператором Halt;, що дозволяють аварійно (або просто з нескінченного циклу) завершити програму. Негайно завершити поточнийблок, у тому числі й підпрограму-функцію або процедуру, дозволяє операторExit;.

Тепер приклади.

Пр.Використовуючи підпрограму, обчислити суму перших k членів ряду 1+1/n.

Сума ряду – це скаляр, природнім виглядає використання підпрограми-функції. Застосувавши відомі алгоритми, складемо програму:

function sum (k:integer):real;

var i:integer;

s:real;

begin

s:=0;

for i:=1 to k do s:=s+1/i;

sum:=s;

end;

var k:integer;

s:real;

begin

write ('Уведіть число кроків:');

readln (k);

s:=sum(k);

writeln ('Сума=',s:8:3);

end.

Зверніть увагу — незважаючи на те, що функція Sumобчислює єдину величинуs, ми були б не має права написати в ній операторfor i:=1 to k do sum:=sum+1/i;- аджеsum– це ім'я функції, і праворуч від знака присвоювання воно було б сприйняте як спроба функціїsumвикликати саму себе, причому, без дотримання правил відповідності параметрів. Тому нам знадобилася "проміжна" зміннаs.

Проте, рекурсивніфункції, що викликає самі себе, існують і будуть коротко розглянуті трохи нижче.

Пр.Обчислити значення вирази, де z(x)= sin 2x + ln |x|.

Очевидно, що повторне обчислення вирази z(x) з різними значеннями аргументу x неефективно, куди зручніше написати підпрограму-функцію, що вважає по формулі z(x)= sin 2x + ln |x| :

function z(x:real):real;

begin

z:=sin(2*x)+ln(abs(x));

end;

begin

write ('Відповідь=', (z(3)+2*sqr(z(5)))/(z(0.1)+1):6:2);

readln;

end.

Як видне із прикладу, використання функції дозволило виконати розрахунки єдиним оператором (з обліком того, що writeln"уміє" друкувати значення обчислених виразів).

На закінчення розділу скажемо кілька слів про рекурсію. Рекурсивними називають функції, здатні повторно викликати самі себе. З погляду програмування, у цьому немає нічого дивного – просто при повторному вході у функцію в програмному стеці створюється її нова копія й розрахунки виконується заново зі зміненим значенням параметра функції. Потім функція перевіряє значення параметра, при необхідності змінює його й знову повторно викликає сама себе. Зрозуміло, щоб уникнути зациклення, при деякім значенні параметра повинне бути передбачене завершення обчислювального процесу. Використання рекурсії доцільно скрізь, де розрахункинаступногозначення деякої функції залежить від їїпопередньогозначення. Так, класичний приклад на рекурсію – розрахунки факторіала (факторіал цілого позитивного числаn, позначуванийn!, дорівнює добутку всіх чисел від1доNвключно). Використовуючи очевидну формулуn!=n*(n-1)!, напишемо наступну рекурсивну функцію:

Function Factorial (n:integer):longint;

begin

if n<2 then Factorial:=1

else Factorial:=n*Factorial(n-1);

end;

Тип функції longintвикористаний, тому що факторіал дуже швидко росте й уже 8!=40320, тобто, більше максимального значення типуinteger. Ця функція, як неважко побачити, при значенні аргументу, меншому двох, повертає одиницю, а а якщо ні, то повертає свій аргументn, помножений на факторіал відn-1. Нескладний тест функції міг би виглядати так:

begin

writeln ('10!=',Factorial(10));

end.

Рекурсія зручна при складанні різного роду переборних стратегій. Так, ігрове завдання складання шляхи по "лабіринту" найкраще вирішується рекурсивно – адже всякий такий шлях – це крок плюс новий шлях, зменшений на один крок.

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