Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

О.О.П / ооп / 4_кол / Лекції / ООП (6. Функції користувача)

.doc
Скачиваний:
23
Добавлен:
30.05.2020
Размер:
384 Кб
Скачать

Лекція: (4 год.)

Тема: Функції в Сі++

План:

  1. Функції в Сі (визначення функції, звернення до функції);

  2. Прототип функції.

  3. Використання бібліотечних функцій

  4. Рекурсивні визначення функцій

  5. Передача значень через глобальні змінні

  6. Класи пам'яті

А тепер нам належить розібратися з питанням про те, як в Сі/Сі++ реалізується механізм підпрограм. Згадаємо про те, що в Паскале існують два різновиди підпрограм : підпрограми-процедури і підпрограми-функції. Той і інший тип підпрограм описується усередині основної програми і компілюється разом з нею. Реалізація механізму підпрограм в Сі/Сі++ істотно відрізняється від аналогічної реалізації в Паскале.

Визначення функції. Звернення до функції. У Сі використовується лише один тип підпрограм — функція. Тут взагалі не прийнято використовувати термін «підпрограма», тому що функція є основною програмною одиницею в Сі, мінімальним виконуваним програмним модулем. Всяка програма обов'язково включає основну функцію з ім'ям main. Якщо в програмі використовуються і інші функції, то вони виконують роль підпрограм.

Розглянемо приклад. Потрібно скласти програму знаходження найбільшого значення з трьох величин — max (a, b, с). Для її вирішення можна використовувати допоміжний алгоритм знаходження максимального значення з двох, оскільки справедлива рівність: max (а, b, с) = max (max (a, b) с).

Ось програма рішення цієї задачі з використанням допоміжної функції.

Приклад 1.

Формат визначення функції наступний:

тип ім'я_функції (специфікація_параметрів)

{тіло_ функції}

Тип функції — це тип повертаного функцією результату. Якщо функція не повертає ніякого результату, то для неї вказується тип void.

Ім'я функції — ідентифікатор, що задається програмістом або main для основної функції.

Специфікації параметрів — це або «порожньо», або список імен формальних параметрів функції з вказівкою типу для кожного з них.

Тіло функції — це або складений оператор, або блок.

Тут ми уперше зустрічаємося з поняттям блоку. Ознакою блоку є наявність описів програмних об'єктів (змінних, масивів і так далі), які діють в межах цього блоку. Блок, як і складений оператор, обмежується фігурними дужками.

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

Оператором повернення з функції в точку її виклику являється оператор return. Він може використовуватися у функціях в двох формах:

return; чи return вираз;

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

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

Формат звернення до функції (виклику функції) традиційний:

ім'я_функції(список_фактичних_параметрів)

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

Між формальними і фактичними параметрами при виклику функції повинні дотримуватися правила відповідності по послідовності і по типах. Фактичний параметр — цей вираз того ж типу, що і у формального параметра, що відповідає йому. Стандарт мови Сі допускає автоматичне перетворення значень фактичних параметрів до типу формальних параметрів. У Сі++ таке перетворення не передбачене. Тому надалі ми строго наслідуватимемо принцип відповідності типів.

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

Правило відповідності по кількості, обов'язкове в Паскале, в Сі в деяких випадках може не дотримуватися. Більше того, в Сі можливі функції зі змінним числом параметрів. Прикладом таких функцій є бібліотечні функції printf() і scanf().

Прототип функції.

Виявляється, зовсім не обов'язково було в попередньому прикладі поміщати повне визначення функції МАХ() перед основною частиною програми. Ось інший варіант програми, що вирішує ту ж саму задачу.

Приклад 2.

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

int MAX(int x, int у);

Крапка з комою у кінці прототипу ставиться обов'язково! Можна було б записати прототип і в тілі основної функції разом з описами інших програмних об'єктів в ній. Питання про розміщення описів пов'язане з поняттям зони видимості, який буде обговорений трохи пізніше.

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

Приклад 3.

А тепер зіставимо програму на Паскале для обчислення найбільшого загального дільника для суми, різниці і твору двох чисел з аналогічною програмою на Сі++.

Приклад 4.

Може виникнути питання: якщо основна частина програми є функцією, то хто (чи що) її викликає? Відповідь полягає в наступному: програму викликає операційна система при запуску програми на виконання. І в принципі main -функция зовсім не обов'язково повинна мати тип void. Наприклад, вона може повертати операційній системі ціле значення 1 в якості ознаки благополучного завершення програми і 0 — в «аварійному» випадку. Обробка цих повідомлень здійснюватиметься системними засобами.

Використання бібліотечних функцій.

Бібліотечними називаються допоміжні функції, що зберігаються в окремих файлах. Стандартні бібліотеки входять в стандартний комплект системи програмування на Сі/Сі++. Крім того, програміст може створювати власні бібліотеки функцій. Раніше вже говорилося про те, що для використання стандартних функцій необхідно підключати до програми заголовні файли відповідних бібліотек. Робиться це за допомогою директиви претранслятора #include з вказівкою імені заголовного файлу. Наприклад, #include <stdio.h>. Усі заголовні файли мають розширення h (від англійського header). Тепер повинно бути зрозуміло, що ці файли містять прототипи функцій бібліотеки. На стадії претрансляции відбувається підстановка прототипів перед основною функцією, після чого компілятор в змозі контролювати правильність звернення до функцій. Самі програми, що реалізовують функції, зберігаються у формі об'єктного коду і підключаються до основної програми на стадії редагування зв'язків (при роботі компонувальника).

Розглянемо програму рішення наступної задачі : знаючи декартові координати вершин опуклого чотирикутника, вичислити його площу (мал. 45).

Математичне рішення цієї задачі наступне. Позначимо координати вершин чотирикутника так: (х1, у1) (х2, у2) (х3, у3) (х4, у4). Площу чотирикутника можна вичислити як суму площ двох трикутників. У свою чергу, площа кожного трикутника обчислюється за формулою Герона. Для застосування формули Герона треба знайти довжини сторін. Довжина сторони між першою і другою вершинами обчислюється за формулою:

Аналогічно обчислюються довжини інших відрізків.

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

Нижче приведена програма рішення поставленої задачі.

Приклад 5.

У цій програмі використовуються функції з трьох стандартних бібліотек із заголовними файлами iostream.h, math.h і conio.h. З першими двома ми вже зустрічалися раніше. Третя бібліотека (файл conio.h) містить функції, призначені для управління виводом на екран в символьному режимі. Вона є аналогом модуля CRT в Турбо Паскале. У програмі з цієї бібліотеки використовується функція clrscr () — очищення екрану.

Ще одним новим елементом в приведеній програмі є рядок

typedef double D;

Службове слово typedef є специфікатором типу, що дозволяє визначати синоніми для позначення типів. В результаті в даній програмі замість довгого слова double для позначення того ж самого типу можна вживати одну букву D. Цей опис діє глобально і поширюється як на основну, так і на допоміжні функції.

Звернемо увагу на ще одно обставину. У функції Geron є звернення до функції Line, а в основній функції — звернення тільки до функції Geron. Для компілятора важливо, щоб перед зухвалою функцією був присутнім або прототип, або визначення функції, що викликається. Тому якщо з цієї програми прибрати прототип функції Line, то помилки не буде. Але якщо одночасно з цим поміняти місцями визначення функцій Line і Geron, то компілятор видасть повідомлення про помилку.

Рекурсивні визначення функцій.

Як і в Паскале, в мовах Сі/Сі++ допускається рекурсивне визначення функцій. Проілюструємо визначення рекурсивної функції на класичному прикладі обчислення факторіалу цілого позитивного числа.

У випадку якщо при виклику функції буде заданий негативний аргумент, вона поверне нульове значення — ознаку невірного звернення.

Передача значень через глобальні змінні.

Зоною дії опису програмного об'єкту називається частина програми, в межах якої діє (враховується) цей опис. Якщо змінна описана усередині деякого блоку, то вона локалізована в цьому блоці і з інших блоків, зовнішніх по відношенню до даного, «не видна». Якщо опис змінною знаходиться поза блоком і передує йому в тексті програми, то цей опис діє усередині блоку і називається глобальним. Глобальна змінна «видно» з блоку. Наприклад:

double x ;

int funcl()

(int у;... }

void main()

{float у;...}

Змінна x є глобальною по відношенню до функцій funcl, main і, отже, може в них використовуватися. У функціях funcl і main є локальні змінні з однаковим ім'ям у. Проте це різні величини, ніяк не пов'язані один з одним. Оскільки змінна х є загальною для обох функцій, то вони можуть взаємодіяти через х один з одним.

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

Приклад 6.

Результат виконання функції MAX заноситься в глобальну змінну z, яка «видно» також і з основної функції

Тому при другому зверненні ця змінна грає одночасно роль аргументу і результату. Тут оператор звернення до функції виглядає подібно до звернення до процедури в Паскале, а глобальна змінна z грає роль var -параметра.

Класи пам'яті.

Під всяку змінну, використовувану в програмі, має бути виділене місце в пам'яті ЕОМ. Виділення пам'яті може відбуватися або на стадії компіляції (компонування) програми, або під час її виконання. Існують 4 класи пам'яті, що виділяється під змінні :

• автоматична (ключове слово auto);

• зовнішня (extern);

• статична (static);

• регістрова (register).

Під глобальні змінні виділяється місце в зовнішній пам'яті (не треба думати, що йдеться про магнітну пам'ять; це оперативна пам'ять класу extern). Глобальну змінну можна оголосити або поза програмними блоками, або усередині блоку з ключовим словом extern. Зазвичай це робиться в тих випадках, коли програмний модуль зберігається в окремому файлі і, отже, окремо компілюється.

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

Приклад 7.

Тут обмін значеннями між основною і допоміжною функцією func() відбувається через загальну глобальну змінну var, для якої під час компіляції виділяється місце в зовнішньому розділі пам'яті. В результаті виконання цієї програми на екран виведеться число 50.

Локальні змінні, оголошені усередині блоків, розподіляються в автоматичній пам'яті, працюючій за принципом стека. Виділення пам'яті відбувається при вході виконання програми у блок, а при виході з блоку пам'ять звільняється. Ключове слово auto писати необов'язково (мається на увазі за умовчанням).

Статична пам'ять виділяється під змінні, локалізовані усередині блоку, але на відміну від автоматичної пам'яті не звільняється при виході з блоку. Таким чином, при повторному входженні у блок статична змінна зберігає своє колишнє значення. Приклад оголошення статичної змінної :

f()

{static int schet=10; ...}

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

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

Нарешті розглянемо приклад, в якому використовуються різні способи опису змінних.

Приклад 8.

Вправи

1. Знайти помилку в програмі:

2. Визначити результат виконання програми :

3. Скласти програму для обчислення площі кільця по значеннях внутрішнього і зовнішнього радіусів, використовуючи функцію обчислення площі круга.

4. Дано три цілі числа. Визначити, сума цифр якого з них більша. Підрахунок суми цифр організувати через функцію.

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

6. Описати рекурсивну функцію stepen (x, n) від речового х (х ≠ 0) і цілого n, яка обчислює величину xn згідно з формулою

7. Дані натуральні числа п і т; знайти НОД(n, т). Скласти рекурсивну функцію обчислення НОД, засновану на співвідношенні НОД(n, m) = HOД(m, r), де r — залишок від ділення n на т (n > т).

11