- •Int main() /* головна обов’язкова функція, де ключове слово int означає, що функція main() повертатиме у точку виклику результат цілого типу*/ 6
- •Засоби розробки с програм
- •Директиви препроцесора.
- •Using namespace std; // вказуємо, що будемо працювати з іменами із стандартної бібліотеки
- •Запитання
- •Тема 2. Данні
- •Команда присвоєння. Правила узгодження типів.
- •Запитання
- •Тема 3. Операції та вирази
- •Тема 4. Потоки. Введення - виведення даних
- •Форматування даних
- •Введення-виведенні засобами бібліотеки сstdіo
- •Тема 5. Адреси даних. Вказівники. Динамічна пам’ять
- •Тема 6. Файли
- •Тема 7. Розгалуження
- •Логічні вирази та логічні операції.
- •Команда ?
- •Тема 8. Цикли
- •Команда циклу з післяумовою do-while має вигляд
- •Тема 9. Функції (1)
- •Тема 10. Функції (2)
- •Тема 11. Масиви
- •Тема 12. Рядки
- •Тема 13. Структури, списки, стеки, черги, об’єднання
- •Тема 14. Виняткові ситуації
- •Http://www.Rate1.Com.Ua/strannosti/2633/ Самі фатальні помилки в програмному забезпеченні
- •Помилки під час виконання (виняткові ситуації, виключення) Exceptions - це помилки, що виникають у випадку, коли програма намагається виконати неприпустиму операцію.
- •Тема 15. Графіка
- •Написание простых графических программ
- •Http://www.Rsdn.Ru/article/opengl/ogltut2.Xml Графическая библиотека OpenGl
Тема 9. Функції (1)
Типи функцій. Мова програмування С++ дає можливість реалізувати концепцію структурного аналізу алгоритмів.
Структурний аналіз - попередє опрацювання складної задачі чи громіздкого алгоритму та поділі його на окремі простіші частий. У С++ ці частини реалізуються за допомогою функцій. Окремі функції об’єднують у спільну програму. У відкомпільованому вигляді така програма утворює модуль.
Розрізняють:
головну функцію main(), що обов’язково входить до кожної програми і повертає ціле значення. Визначення void main() {/*... */} ніколи не було в C++, так само як і не було навіть в CEven if your compiler accepts "void main()" avoid it, or risk being considered ignorant by C and C++ programmers. http://www.stroustrup.com/bs_faq2.html#void-main
Навіть якщо ваш компілятор приймає “void main()”, уникайте цього, бо програмісти С і C++ вважатимуть вас неосвіченим.
стандартні функції мови описані (визначені) у бібліотеках. (зокрема, математичні функції sin(), соs() з бібліотеки math.h).
функція користувача - це поіменована група команд, яка оголошена у файлі заголовків (або в основній програмі) та описана у модулі (в основній програмі). До функції можна звернутись (викликати) з будь-якого місця програми необхідну кількість разів.
Прості програми не потребують використання функцій користувача.
2. Оголошення функцій користувача. Кожну функцію користувача перед першим викликом передусім необхідно оголосити (задекларувати, створити прототип, сигнатуру(набір характеристик)). За стандартом ISO/ANSI прототипи функцій оголошують у спеціальних файлах заголовків. У програму ці файли приєднують за допомогою директиви #include, наприклад:
#include <conio.h>
#include "MyHeader.h"
Прототипи стандартних функцій розміщені у папці INCLUDE. Синтаксис мови дає змогу розмістити прототип також і в основній програмі. Функцію користувача оголошують так:
<тип функції> <назва функції> (<список формальних параметрів>);
де
тип функції - це тип даного, який функція повертає в основну програму. Тип функції можна не зазначати. За замовчуванням функція повертає у програму дане цілого типу int. Функцію, яка не повертає у програму жодного результату, оголошують з типом void. Для функції, яка не залежить від жодних параметрів, у круглих дужках записують службове слово void.
назву функції надає користувач за правилом створення ідентифікаторів.
у списку формальних параметрів через кому записують змінні, зазначаючи їхні типи. Тип необхідно зазначати для кожної змінної окремо. Імена змінних можна опускати. Якщо функція не набуває жодних значень, то список формальних параметрів може бути відсутній. Круглі дужки опускати не можна.
Приклад 1. Розглянемо сигнатури функцій
float Suma(int kil, float cina);
void drib (float, float);
kod(int k1, int k2); double loto(void);
У цьому випадку оголошена функція Suma типу float, яка залежить від двох змінних: перша змінна цілого типу int, друга - типу float.
Функція drib залежить від двох змінних дійсного типу float і не повертає у програму жодного значення.
Ціла функція kod залежить від двох змінних цілого типу, дійсна функція loto типу double не залежить від жодних параметрів.
Під час оголошення можна відразу ініціалізувати формальні параметри функції, тобто надавати їм певних значень. Такі значення називаються значеннями за замовчуванням. їх записують у кінці списку. Значення таких параметрів у програмі можна змінювати. Враховуючи це, розглянемо ще один спосіб оголошення функцій, наведених у прикладі 1.
float Suma(int kil, float cina = 2.5); void drib (float v = 1.2, float n = 3); kod(int k1, int k2 = 5);
3. Опис функцій користувача. Опис функції складається із заголовка без «;» і тіла функції, записаного у фігурних дужках, а саме:
<тип функції> <назва функції>(<список формальних параметрів>)
{
<тіло функції>;
return (<назва змінної 1>);
}
У тілі функції записують команди, які задають дію функції. Результат виконання функції повертається в основну програму (у точку виклику) за допомогою змінної 1 командою return. Тип змінної 1 має збігатися з типом функції. У тілі функцій типу void команду return не зазначають. У команді return круглі дужки можна не писати.
Зауваження 1. Функцію можна описувати і на початку програми. У такому випадку декларувати її не потрібно.
Приклад 2. Функції Suma і drib, оголошені у прикладі 1, у деякій програмі можна описати так:
float Suma(int kil, float cina) // Заголовок функції
{
float s = kil * cina;
return (s); // Значення, яке повертає функція в основну програму
}
//
void dilennya (float v, float n)
{
cout <<“\n dilennya = " << v / n;
}
Якщо потрібно проініціалізувати значення змінних, що входять у функцію, то це можна зробити у сигнатурі функції. Тоді в описі у заголовка функції значення за замовчуванням не задають.
Приклад 3. Сигнатуру функції, яка обчислює периметр k-кутної правильної фігури зі стороною r, можна оголосити так: float perymetr (int k = 4, float r = 2.5);
а описати власне функцію так: float perymetr (int k, float r)
{
float p;
p = k * r;
return (p);
}
Виклик функцій користувача. До функції користувача звертаються з розділу команд основної програми (функції main()) або з іншої функції. Виклик функцій можна виконати двояко: або командою виклику, або з виразів так:
<назва функції>(<список фактичних параметрів>)
Список фактичних параметрів може містити сталі, змінні, посилання, вказівники, вирази. Списки формальних і фактичних параметрів мають бути узгодженими за типами та кількістю елементів. Якщо у списку формальних параметрів є проініціалізовані змінні, то у списку фактичних параметрів ці змінні можуть бути відсутні, їм будуть надані значення за замовчуванням.
Приклад 4. Розглянемо сигнатуру з прикладу 3. float perymetr (int k = 4, float r = 2.5);
До цієї функції можна звернутись одним із способів:
perymetr (7, 2.8); perymetr (8); perymetr 0;
У першому випадку змінній k буде присвоєне значення 7, а змінній r - 2,8; у другому випадку k = 8, r = 2,5; в третьому k = 7, r = 2,5.
У списку фактичних параметрів не можна пропускати змінні з середини списку, тобто не можна функцію perymetr () викликати так: perymetr (1.65);, оскільки тут пропущено ініціалізацію першої змінної k.
Задача 1 (про товарний чек). Використовуючи функцію користувача, скласти програму для виведення на екран товарного чека для купівлі ті штук товару за ціною тп грнивень за одну штуку. Ціну та кількість купленого товару ввести самостійно у режимі діалогу.
#include <iostream> // Товарний чек
#include <conio.h>
using namespace std;
float Suma(int, float); // Оголошення функції Suma
int main() {
float m; int n;
cout << "Введіть ціну за 1 шт. \n"; cin >> m;
cout << "Введіть кількість купленого товару \n"; cin >> n;
cout<< "\t ТОВАРНИЙ ЧЕК \n";
cout <<"Ціна за 1 шт. -"<< m << " грн \n";
cout <<"За "<< n << " штук необхідно сплатити ";
cout<< Suma(n, m) << " грн\n"; // Виклик функції Suma
cout << "\t Дякуємо за покупку!";
getch();
}
float Suma(int kil, float cina) // Опис функції Suma
{
float s;
s = kil * cina;
return s;
}
5. Посилання. До даних можна звертатись за допомогою імен або посилань.
Посилання слугує для надання ще одного імені (псевдоніма, синоніма, аліасу) даному. Посилання утворюють так:
<тип даного> &<назва посилання> = <назва змінної>;
Наприклад, float &cina = suma;
У цьому випадку посилання cina і змінна suma вказуватимуть на одну і ту саму адресу в пам’яті комп’ютера. Для посилань не резервується додаткова оперативна пам’ять.
У C++ можна утворювати посилання на дані, але не на їхні типи. Значення посилання ініціалізуються відразу під час того оголошення, тобто на етапі компіляції. У нашому прикладі посилання cina проініціалізоване змінною suma. Отже, якщо suma = 11, то і значення посилання cina також буде 11.
Під час зміни значення посилання змінюється значення змінної, на яке це посилання вказує. Отже, якщо у програмі записати команду cina = 15.7, то змінна suma також набуде значення 15.7.
Змінювати (переадресовувати) посилання у програмі не можна. Посилання завжди вказує на одну і ту саму адресу в оперативній пам’яті. Це використовують під час створення та виклику функцій. Під час виклику функції копії усіх її фактичних параметрів заносяться у спеціально організовану область пам’яті. Потім виконуються відповідні команди функції і результат повертається у програму командою return. Оскільки всі дії відбуваються з копіями параметрів, а не із самими параметрами (копії та власне параметри розміщені у різних ділянках пам’яті), то значення фактичних параметрів в основній програмі не змінюються. Як параметри функції можна використовувати посилання або вказівники. Тоді значення фактичних параметрів у основній програмі змінюватимуться, оскільки функція буде повертати значення в основну програму не тільки через змінну з команди return, а й через відповідні посилання та вказівники, бо вони вказують на ту саму ділянку пам’яті, де розміщені фактичні параметри.
Щоб передати посилання чи вказівники у функцію як параметри і не змінити значення фактичних параметрів, треба в оголошенні функції до кожного параметра дописати ключове слово const.
Наприклад, int sort(const int *р, const int *g);
У C++ посиланням може бути не тільки змінна чи стала, а і функція
<тиn> & <назва функції>(<список формальних параметрів>)
Така функція повертає синонім імені комірки, у яку занесено результат (посилання на змінну певного типу). Функція-посилання має двояке призначення. По-перше, як і звичайна функція, вона може повертати значення в основну програму. По-друге, їй самій можна надавати значень, що є унікальним випадком у програмуванні.
Приклад 5. Оголосимо змінну та вказівник на дійсний тип float *prt, u; та опишемо функцію float <em(float* а, int і) {return *(а + і);}
Виділимо ділянку пам’яті для зберігання значень десяти дійсних чисел prt = new float[10]; Викликати цю функцію можна звичайно: u = ltem(prt, 3); Тоді змінній u буде надано значення четвертого елемента. Уведемо значення п’ятого числа так: ltem(prt, 4) = 10.
Функції ltem() надаємо значення, тобто у ділянку пам’яті буде занесено число 10.
Задача 2 (про гуртову покупку). Нехай знижки на гуртові залежать від суми, на яку зроблено замовлення, а саме: під час купівлі товару на суму до 200 грн. покупець має сплатити 100% від вартості товару, на суму від 200 до 500 грн. йому надається знижка 10%, а на суму понад 500 грн. - 20%. Ввести з клавіатури суму, на яку зроблено замовлення, і вивести суму, яку необхідно сплатити з урахування системи знижок. Використати функцію користувача, аргументами якої є посилання на змінні.
#include <iostream> // Гуртове замовлення
#include <cstdlib>
using namespace std;
void Suma(float &t); // Оголошення функції Suma
int main() {
float S; float &pS = S;
cout <<"Введіть суму замовлення \n"; cin>> S;
cout<< "\t Вам необхідно сплатити \n";
Suma(pS); // Виклик функції
cout << S << " грн.";
system("PAUSE");
return EXIT_SUCCESS;
}
// ---------------------------------------------------
void Suma(float &t) // Опис функції Suma
{ // Зміна значення посилання t
if (t >= 200.0 && t < 500) t *= 0.9;
if (t >= 500.0) t *= 0.8;
}
У цьому випадку функція Suma() повертає у програму значення через посилання pS.
6. Рекурсія. Рекурсією називається алгоритмічна конструкція, де підпрограма викликає сама себе. Рекурсія дає змогу записувати циклічний алгоритм, не застосовуючи команд циклу.
Рекурсивні методи часто використовують в сортуванні, а також в алгоритмах, пов'язаних зі штучним інтелектом. У звичайній практиці рекурсія використовується рідко.
Використання рекурсії збільшує час виконання програми і часто вимагає значного обсягу пам'яті для зберігання копій підпрограми на рекурсивном спуску. Тому на практиці заміняють рекурсивні алгоритми на ітеративні.
Рекурсія дозволяє створювати код з незмінними змінними, що
робить код більш читабельним,
захищає від помилок типу «дії виконані в невірному порядку», «використано не-ініціалізована змінна» і інших аналогічних,
полегшує організацію контролю коректності вхідних даних,
дозволяє читати код з будь-якого місця, не переглядаючи його весь, відстежуючи всі зміни змінної,
полегшує налагодження.
У деяких випадках, рекурсія дозволяє більш ясно сформулювати ідею алгоритму; наприклад, це відноситься до алгоритму швидкого сортування - quicksort - який рекурсівен за своєю природою.
Але, звичайно, використовувати рекурсію слід розумно. Потрібно враховувати те, що часто (не завжди) вона веде до великих витрат стека і деякого зниження продуктивності.
Крім того, вдаючись до рекурсії, треба розуміти, яку вигоду ви можете від неї отримати, і прагнути максимізувати вигоду і мінімізувати внесок негативних властивостей рекурсії.
У будь-якому випадку, існує безліч мов, в яких рекурсія - єдиний засіб, для виконання багатьох дій. До таких мов відносяться не тільки «екзотичні» функціональні мови, такі як Haskell, а й засоби більш широкого застосування: XSLT-процесори, макро-процесор m4 (основа системи autoconf і багатьох систем конфігурації), і інші засоби. Таке «тяжіння» до рекурсії - не наслідок обмеженості цих мов; навпаки, ці мови спеціально оптимізовані для використання рекурсії; вони активно використовують факт незмінності змінних і здатні виконати безліч оптимізацій, позбавляючи програміста від багатьох турбот.
Типовий приклад використання рекурсії - обчислення факторіала числа. Нагадаємо, що факторіал числа - це добуток цілих чисел від одиниці до певного заданого числа.
Отже, п! = n • (п - 1) • (n - 2) • ... •1. Рекурсивна властивість факторіала: n! = n• (n-1)!.
Приклад 4. Скласти функцію для обчислення n!, використовуючи рекурсію, можна так: long factorial (int n)
{long fact;
if (n > 1) fact = n * factorial(n -1);
else fact = 1; return fact;}
Зауваження 2. Оскільки навіть для невеликих чисел значення факторіала є досить великим, то у цьому прикладі для функції factorial задано тип long. Це дає змогу обчислити факторіали чисел від 1 до 16. Для визначення факторіалів чисел більших від 16 необхідно використати алгоритми „довгої арифметики”.
Обчислимо функцію factorial(5) = 5 • factorial(4) = 5 • 4 • factorial(3) = 5 •4• 3 factorial(2) = 5•4•3•2•factorial(l) = 5• 4•3•2•1 = 120. Переконайтеся, що factorial (13) = 1932053504.
Приклад 6. Рекурсивна функція обчислення суми цілих чисел від а до b має вигляд
int Suma (int a, int b){
int S;
if (a == b) S = a;
else S = b + Suma(a, b -1); return S;}
Зауваження 3. Застосовуючи рекурсію, потрібно правильно складати стоп-умови, які забезпечують закінчення циклічних обчислень.
Вправи
З презентації
Скласти програму для обчислення факторіала числа. Знайдіть факторіали 4, 7, 10.
Запишіть функцію для обчислення добутку цілих чисел з діапазону від а до b. Знайдіть добуток чисел, діапазон увести з клавіатури.
Обчислити суму перших n цілих додатних чисел.
Перевірте, чи є уведено число паліндромом. Наприклад, 12321, 2442 – паліндроми
Створити функцію для обчислення довжини відрізка, заданого координатами своїх вершин на площині. Використати цю функцію для обчислення периметра трикутника, заданого координатами своїх вершин
Задані два натуральних числа. Визначити в якому з них більше цифр, організувавши функцію для підрахунку кількості цифр в будь-якому натуральному числі.
Придумайте призначення, складіть і запишіть функцію kod(int k1, int k2), сигнатура якої оголошена у прикладі 1.
Придумайте призначення та опишіть дві - три функції різних типів.
Модифікуйте програму Товарний чек на випадок купівлі двох видів товару за різною ціною. Товарний чек виведіть у файл.
Модифікуйте програму Товарний чек на випадок купівлі h видів товару за різною ціною, якщо кількість товарів наперед відома.
Вказівка: використайте команду циклу for.
Модифікуйте програму Товарний чек на випадок купівлі k видів товару за різною ціною, якщо кількість товарів наперед невідома.
Вказівка. Використайте команду циклу while з параметром завершення циклу.
Виведіть у файл факторіали чисел від 1 до 10.
Модифікуйте програму Гуртове замовлення, використовуючи вказівники.
Модифікуйте програму Гуртове замовлення, використовуючи вказівники з ключовим словом const.
Розв’яжіть задачу № 7 вашого варіанта, використавши дві функції користувача для знаходження суми та добутку. Результати виведіть
а) на екран;
б) у файл.
Розв’яжіть задачу № 7 вашого варіанта, використавши дві функції користувача. Аргументами цих функцій мають бути посилання на дійсні змінні.
Розв’яжіть задачу № 7 вашого варіанта, використовуючи рекурсивні функції (тобто без використання команди циклу).
1.7
