← Повернутися до лекцій

Лекція 10: Функції (Основи)

1. Що таке функція і навіщо вона потрібна?

Функція — це пойменований блок коду, який виконує одну конкретну задачу. Ви можете викликати його скільки завгодно разів з різних місць програми.

Головні переваги:

  1. DRY (Don't Repeat Yourself): Не треба копіювати один і той самий код 10 разів. Написали функцію один раз — використовуєте всюди.
  2. Читабельність: Код calculateTax(salary) набагато зрозуміліший, ніж 20 рядків математичних формул посеред main.

2. Анатомія функції

Створення функції складається з чотирьох частин:

тип_результату ім'я_функції ( параметри ) { тіло_функції }
  1. Тип результату (Return type): Що функція поверне після роботи? (int, double, string). Якщо функція нічого не повертає (просто виводить текст), використовується тип void.
  2. Ім'я (Name): Дієслово, що описує дію (наприклад, printHello, sum, getMax).
  3. Параметри (Parameters): Дані, які ми передаємо функції для роботи (вхідні дані).
  4. Тіло (Body): Код у фігурних дужках.

Приклад простої функції:

// Функція, яка приймає два числа і повертає їх суму
int addNumbers (int a, int b) {
    int result = a + b;
    return result; // return повертає значення в місце виклику
}

3. Виклик функції

#include <iostream>
using namespace std;

// Оголошуємо функцію
int addNumbers(int a, int b) {
    return a + b;
}

int main() {
    // Викликаємо функцію
    int sum = addNumbers(5, 10);
    cout << "Сума: " << sum << endl; // Виведе 15
    
    // Можна використовувати результат одразу у виводі
    cout << "Ще сума: " << addNumbers(100, 200) << endl;
    
    return 0;
}

4. Прототипи функцій (Важливий нюанс С++)

Компілятор читає код зверху вниз. Якщо main написано вище ваших функцій, компілятор видасть помилку типу "Я не знаю, що таке addNumbers".

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

#include <iostream>
#include <string>
using namespace std;

// 1. Прототип (Оголошення)
void sayHello(string name);

int main() {
    sayHello("Andrii"); // Тепер це працює, хоча тіло функції внизу
    return 0;
}

// 2. Реалізація (Визначення)
void sayHello(string name) {
    cout << "Привіт, " << name << "!" << endl;
    // return не потрібен, бо тип void
}

5. Передача параметрів: За значенням vs За посиланням

Це критично важливий момент, який пов'язаний з нашою попередньою лекцією про пам'ять.

У С++ існує 4 основні способи передати дані у функцію. Вибір способу залежить від двох питань: "Чи треба змінювати оригінал?" та "Скільки пам'яті це займає?"

A. Передача за значенням (Pass by Value)

Це режим "Ксерокс". Функція створює повну копію змінної. Всі зміни відбуваються тільки з копією і зникають після завершення функції.

Синтаксис: void func(int x)

  • Плюси: Безпечно (оригінал не постраждає).
  • Мінуси: Повільно для великих даних (копіювання величезного тексту займає час і пам'ять).
  • Коли використовувати: Для простих типів (int, float, char, bool).
#include <iostream>
using namespace std;

void modifyValue(int x) {
    x = 999; // Зміниться тільки копія
}

int main() {
    int num = 5;
    modifyValue(num);
    cout << num; // Все ще 5!
    
    return 0;
}

B. Передача за посиланням (Pass by Reference)

Це режим "Спільний доступ". Ми передаємо не дані, а посилання (альтернативне ім'я) на оригінальну змінну. Копіювання не відбувається.

Синтаксис: void func(int &x) (додаємо &)

  • Плюси: Дуже швидко; дозволяє змінювати оригінал.
  • Мінуси: Небезпечно (можна випадково зламати дані в main).
  • Коли використовувати: Коли функція має змінити передану змінну (наприклад, swap, input).
#include <iostream>
using namespace std;

void modifyReference(int &x) {
    x = 999; // Оригінал у main теж стане 999
}

int main() {
    int num = 5;
    modifyReference(num);
    cout << num; // Тепер 999!
    
    return 0;
}

C. Передача за константним посиланням (Pass by Const Reference) — Золотий стандарт С++

Це режим "Тільки подивитися". Ми намагаємося поєднати швидкість посилання з безпекою значення. Передаємо посилання, але забороняємо зміну даних через const.

Синтаксис: void func(const string &str)

  • Плюси: Миттєва передача (немає копіювання) + Гарантія, що дані не зміняться.
  • Коли використовувати: Для всіх "важких" типів даних (string, вектори, масиви, структури), які ви не плануєте змінювати.
#include <iostream>
#include <string>
using namespace std;

// Ефективно і безпечно виводимо довгий текст
void printMessage(const string &text) {
    // text = "New"; // Помилка! Змінювати заборонено
    cout << text << endl;
}

int main() {
    string message = "Дуже довгий текст...";
    printMessage(message);
    
    return 0;
}

D. Передача за вказівником (Pass by Pointer)

Це "старий стиль", спадщина мови C. Працює схоже на посилання (передається адреса), але синтаксис складніший.

Синтаксис: void func(int *x)

  • Особливість: Вказівник може бути пустим (nullptr), а посилання — ні.
  • Коли використовувати: Якщо параметр необов'язковий (може бути пустим) або при роботі з динамічними масивами.
#include <iostream>
using namespace std;

void modifyPointer(int *x) {
    if (x != nullptr) { // Перевірка на безпеку
        *x = 999; // Розіменування для доступу
    }
}

int main() {
    int num = 5;
    modifyPointer(&num); // Передаємо адресу
    cout << num; // Тепер 999!
    
    return 0;
}

Зведена таблиця (Шпаргалка для студента)

Спосіб Синтаксис Копіювання даних? Може змінити оригінал? Для чого краще?
За значенням int x Так (Повільно) Ні Маленькі числа (int, double)
За посиланням int &x Ні (Швидко) Так Коли треба повернути змінені дані
Const посилання const string &x Ні (Швидко) Ні (Безпечно) Великі дані (string), тільки для читання
За вказівником int *x Ні (Швидко) Так С-сумісність, масиви

6. Локальні та глобальні змінні (Область видимості)

  • Локальні змінні: Змінні, створені всередині функції (включно з main), є локальними. Вони існують лише поки виконується ця функція. Інші функції їх "не бачать".
  • Глобальні змінні: Змінні, створені поза всіма функціями (на початку файлу), є глобальними. Всі їх бачать. (Не зловживайте ними!).