- •Основи програмування мовою Паскаль
- •Часть 1. Основы языка Паскаль 2
- •Часть 2. Элементы профессионального программирования на Паскалі 62
- •Частина 1. Основи мови Паскаль
- •1. Алгоритм і програма
- •1.1. Алгоритм
- •1.2. Властивості алгоритму
- •1.3. Форми запису алгоритму
- •1.4. Програма й програмне забезпечення
- •1.5. Етапи розробки програми
- •2. Дані в мові Паскаль
- •2.1 Константи
- •2.2 Змінні й типи змінних
- •3. Арифметичні вирази
- •4. Лінійний обчислювальний процес
- •4.1 Оператор присвоювання
- •4.2 Оператор уведення
- •4.3 Оператор виведення
- •4.4 Керування виводом даних
- •4.5 Вивід на друк
- •5. Структура простої програми на Паскалі
- •6. Компілятор і оболонка Turbo Pascal
- •7. Обчислювальний процес, що розгалужується, і умовний оператор
- •7.4. Короткий умовний оператор
- •If логічний_вираз then оператор1;
- •7.5. Повний умовний оператор
- •If логічний_вираз then оператор1
- •7.7. Вкладені умовні оператори
- •7.9. Приклади програм з умовним оператором
- •8. Директиви компілятора й обробка помилок уведення
- •9. Оператор циклу. Цикли із передумовою і після-умовою
- •10. Цикл із лічильником і дострокове завершення циклів
- •11. Типові алгоритми табулювання функцій, обчислення кількості, суми й добутку
- •11.1 Алгоритм табулювання
- •11.2 Алгоритм організації лічильника
- •11.3 Алгоритми нагромадження суми й добутку
- •12. Типові алгоритми пошуку максимуму й мінімуму
- •13. Розв'язок навчальних завдань на цикли
- •14. Одномірні масиви. Опис, уведення, вивід і обробка масивів на Паскалі
- •15. Розв'язок типових завдань на масиви
- •Частина 2. Елементи професійного програмування на Паскалі
- •16. Кратні цикли
- •16.1 Подвійний цикл і типові завдання на подвійний цикл
- •16.2 Оператор безумовного переходу
- •17. Матриці й типові алгоритми обробки матриць
- •18. Підпрограми
- •18.1 Процедури
- •18.2 Функції
- •18.3 Масиви як параметри підпрограми
- •18.4 Відкриті масиви
- •19. Безлічі й перечислимые типи
- •20. Обробка символьних і строкових даних
- •20.1. Робота із символами
- •20.2 Робота з рядками
- •21. Текстові файли
- •21.1 Загальні операції
- •21.2 Приклади роботи з файлами
- •21.3 Робота з параметрами командного рядка
- •22. Записи. Бінарні файли
- •23. Модулі. Створення модулів
- •23.1. Призначення й структура модулів
- •Implementation
- •23.2. Стандартні модулі Паскаля
- •24. Модуль crt і створення простих інтерфейсів
- •25. Модуль Graph і створення графіки на Паскалі
- •Додаток 1. Таблиці Ascii-Кодів символів для операційних систем dos і Windows
- •Додаток 2. Основні директиви компілятора Паскаля
- •Додаток 3. Основні повідомлення про помилки Паскаля
- •Додаток 4. Додаткові лістинги програм
- •Додаток 5. Розширені коди клавіатури
- •Ascii‑ коди
- •Розширені коди
- •Додаток 6. Правила гарного коду
- •Додаток 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.
Рекурсія зручна при складанні різного роду переборних стратегій. Так, ігрове завдання складання шляхи по "лабіринту" найкраще вирішується рекурсивно – адже всякий такий шлях – це крок плюс новий шлях, зменшений на один крок.
При написанні рекурсивних функцій слід ураховувати, що рекурсивні виклики досить швидко заповнюють стек і загрожують його переповненням. Тому основна проблема при написанні такої функції – відітнути свідомо зайві вкладені виклики. Для цього використовують додаткові перевірки умов, що визначають, чи доцільно поглиблювати далі поточний рівень вкладень.