1. Синтаксис розгалужень: if, else, else if
Коли ви лише починаєте програмувати, може здаватися, що програма — це просто калькулятор: ввели числа, отримали відповідь. Але доволі швидко зʼясовується: реальна програма майже завжди розгалужується. Якщо користувач увів одне — робимо так, якщо інше — інакше. Навіть у стандарті C++ окремо виділяють поняття condition («умова») як важливу частину керувальних конструкцій на кшталт if.
Головна думка проста: if — це роздоріжжя. Умова — це запитання, на яке програма відповідає true або false, а потім обирає одну з гілок.
Перш ніж писати «розумні» умови, важливо добре зрозуміти основу: if — це не магія, а дуже строга конструкція. У дужках після if має бути вираз типу bool або те, що до нього зводиться. Далі йде команда або блок команд. Саме тут новачки вперше по-справжньому стикаються із синтаксисом: де потрібні круглі дужки, де — фігурні, і чому одна зайва крапка з комою ; повністю змінює зміст.
Базовий if: «якщо (…) то …»
Мінімальний шаблон має такий вигляд:
if (condition) {
// дії, якщо condition == true
}
if
Приклад: «повнолітній чи ні»
Почнімо з найпростішого: зчитаємо вік і виведемо статус.
#include <iostream>
int main() {
int age = 0;
std::cin >> age;
if (age >= 18) {
std::cout << "adult\n"; // наприклад, при введенні 18 -> adult
}
}
Тут важливо зрозуміти: age >= 18 — це вираз, який обчислюється до true або false. Якщо результат — true, виконується блок.
else: «інакше робимо ось що»
Якщо if — це «якщо правда», то else — це «якщо неправда». Він завжди належить до найближчого if, у якого немає власного else. Це важливий момент: відступи й {} справді рятують нерви.
Базова форма:
if (condition) {
// true-гілка
} else {
// false-гілка
}
if / else
Це вже повноцінне розгалуження: «ліворуч» або «праворуч».
else if: «інакше якщо … інакше якщо … інакше …»
Тепер переходимо до ситуації, коли треба вибрати одну гілку з кількох. Таке трапляється дуже часто: число може бути додатним, відʼємним або нулем; команда може бути "add", "remove" чи "exit"; оцінка може бути «відмінно», «добре», «задовільно» або «погано».
Ланцюжок має такий вигляд:
if (cond1) {
...
} else if (cond2) {
...
} else if (cond3) {
...
} else {
...
}
Ключове правило: у такому ланцюжку виконується рівно одна гілка — перша, чия умова спрацювала, якщо рухатися згори донизу.
Приклад: знак числа
#include <iostream>
int main() {
int x = 0;
std::cin >> x;
if (x > 0) {
std::cout << "positive\n"; // 5 -> positive
} else if (x < 0) {
std::cout << "negative\n"; // -3 -> negative
} else {
std::cout << "zero\n"; // 0 -> zero
}
}
Чому порядок важливий? Тому що перевірки виконуються згори донизу. Якби ми помилково написали x >= 0 першою умовою, усе, що не є відʼємним, уже «поглинула» б перша перевірка.
2. Читабельність розгалужень: {}, смислові рівні та назви перевірок
Є два типи новачків: ті, хто завжди ставить {}, і ті, хто одного разу втратив дві години через пропущені {}, — а потім теж почав ставити їх завжди.
Формально C++ дозволяє писати так:
if (condition)
std::cout << "Hello\n";
Але для початківця це як їздити на велосипеді без рук: дехто вміє, та ми ж поки вчимося їздити, а не вражати перехожих.
Чому «один рядок без {}» небезпечний
Проблема зʼявляється, коли ви спершу написали один рядок, а потім додали другий і забули про дужки. Код компілюється, але поводиться дивно.
Порівняйте:
// ПОГАНО: легко зламати при додаванні рядків
if (age >= 18)
std::cout << "adult\n";
std::cout << "welcome!\n"; // виконується ЗАВЖДИ
і
// ДОБРЕ: структура завжди очевидна
if (age >= 18) {
std::cout << "adult\n";
std::cout << "welcome!\n";
}
Друга версія своїм виглядом буквально підказує: «ці два рядки — одна дія в межах цієї гілки».
else if і вкладений if: це різні смисли
Дуже поширене запитання: «А можна я просто вкладу if усередину if?» Можна. Але зміст буде іншим. А якщо зміст інший, краще писати так, щоб читач — зокрема й ви самі за тиждень — побачив це відразу.
else if — це «вибір однієї гілки з набору взаємовиключних варіантів».
Вкладений if — це «ми вже вибрали гілку і всередині неї щось уточнюємо».
Приклад: де потрібен вкладений if
Припустімо, спочатку ми перевіряємо, чи вік узагалі коректний, тобто чи не є він відʼємним. І лише потім вирішуємо: adult чи minor.
#include <iostream>
int main() {
int age = 0;
std::cin >> age;
if (age < 0) {
std::cout << "invalid\n"; // -5 -> invalid
} else {
if (age >= 18) {
std::cout << "adult\n"; // 20 -> adult
} else {
std::cout << "minor\n"; // 7 -> minor
}
}
}
Зміст тут такий: якщо вік некоректний — одразу invalid. Інакше визначаємо, чи людина повнолітня.
Якщо спробувати вмістити це в один ланцюжок else if, теж можна отримати робочий варіант. Але новачкові такий запис зазвичай важче читати, бо в ньому змішуються різні смислові рівні: спочатку перевірка коректності даних, а потім їх класифікація.
Робіть умови читабельними: називайте перевірки
У цій лекції ми говоримо не лише про те, як працює if, а й про те, як зробити так, щоб ваш код не скидався на шифр. Один із найпростіших прийомів — винести частину перевірки в змінну типу bool зі зрозумілою назвою.
Це не «зайві змінні», а радше підписи на дротах. Без підпису теж можна підʼєднати, але потім ремонтувати значно болючіше.
#include <iostream>
int main() {
int age = 0;
std::cin >> age;
bool is_adult = (age >= 18);
if (is_adult) {
std::cout << "adult\n";
} else {
std::cout << "minor\n";
}
}
Перевага такого підходу в тому, що умова if (is_adult) читається майже як англійське речення. Недолік лише один: треба дібрати вдалу назву. Але це складно тільки спочатку — згодом мозок робить так майже автоматично.
3. Практичний мініприклад: «обробник команди» без циклів
Зараз ми зберемо невелику заготовку застосунку, яка далі розвиватиметься протягом курсу. Поки що — без циклів, бо їх ми ще не проходили. Тому програма обробить одну команду й завершиться. Але навіть у такому вигляді вона вже схожа на реальний консольний інтерфейс: користувач вводить команду, а програма вирішує, що робити далі.
Ідея проста: зчитуємо рядок cmd і виконуємо різні дії.
Версія 1: три команди
#include <iostream>
#include <string>
int main() {
std::string cmd;
std::cin >> cmd;
if (cmd == "hello") {
std::cout << "Hello!\n"; // hello -> Hello!
} else if (cmd == "help") {
std::cout << "Commands: hello, help, exit\n";
} else if (cmd == "exit") {
std::cout << "Bye!\n"; // exit -> Bye!
} else {
std::cout << "Unknown command\n"; // qwerty -> Unknown command
}
}
Зауважте, як легко це читається: згори донизу — майже як список правил. Саме тому ланцюжок else if такий популярний на ранніх етапах навчання.
Версія 2: команда з числом
Нехай командою буде "age", а після неї користувач введе число. Поки що не додаємо складних перевірок введення — до цього ще повернемося. Зате тут добре видно, як гілка if може містити власний невеликий сценарій.
#include <iostream>
#include <string>
int main() {
std::string cmd;
std::cin >> cmd;
if (cmd == "age") {
int age = 0;
std::cin >> age;
if (age >= 18) {
std::cout << "adult\n"; // age 20 -> adult
} else {
std::cout << "minor\n"; // age 7 -> minor
}
} else {
std::cout << "Try command: age\n";
}
}
Зверніть увагу: усередині гілки cmd == "age" ми робимо ще одне розгалуження. Це цілком життєва ситуація: спочатку обираємо режим, а вже в ньому — конкретну дію.
Невелика схема: як виконується if / else if / else
Іноді корисно побачити else if не як «магічні слова», а як простий алгоритм: перевірили перше — якщо так, виконали й вийшли; якщо ні — пішли далі.
flowchart TD
A[Початок] --> B{cond1?}
B -->|так| C[гілка 1]
B -->|ні| D{cond2?}
D -->|так| E[гілка 2]
D -->|ні| F{cond3?}
F -->|так| G[гілка 3]
F -->|ні| H[гілка else]
C --> Z[Кінець]
E --> Z
G --> Z
H --> Z
Ця схема корисна тим, що наочно показує головний факт: виконується лише одна гілка, а перевірки йдуть згори донизу.
4. Типові помилки під час роботи з if/else
Помилка № 1: крапка з комою після if.
Новачки інколи пишуть if (cond); — і це виглядає майже правильно, але зміст ламається повністю. Крапка з комою тут означає «порожню команду»: умову перевірили, а далі нічого не зробили. Блок після цього виконується вже як звичайний блок, тобто майже завжди. Якщо бачите дивну поведінку на кшталт «гілка виконується завжди», насамперед шукайте зайвий ;.
Помилка № 2: гілки без {} і «рядок, що втік».
Спочатку все працює: у гілці лише один рядок. Потім ви додаєте другий, але забуваєте про фігурні дужки, і цей другий рядок починає виконуватися завжди або не тоді, коли треба. Це одна з найприкріших помилок: компілятор не свариться, а логіка вже інша. Звичка «завжди ставити {}» майже повністю від цього захищає.
Помилка № 3: переплутали зміст else if і вкладеного if.
Якщо вам потрібно вибрати «один варіант із багатьох», використовуйте ланцюжок else if. Якщо ж потрібно «спочатку перевірити одне, а всередині вже уточнити інше», використовуйте вкладений if. Коли ці два смислові рівні змішуються, код стає важким для читання: наче працює, але не дуже зрозуміло, що саме автор хотів сказати.
Помилка № 4: невдалий порядок перевірок у ланцюжку else if.
Проблема зʼявляється, коли перша перевірка надто широка й перехоплює випадки, які мали б потрапити в нижні гілки. Наприклад, if (x >= 0) перед else if (x == 0) — і гілка x == 0 ніколи не виконається. Виправлення просте: спочатку ставимо специфічніші випадки, потім — загальніші. Або спершу проговорюємо словами «драбину» перевірок, а вже потім записуємо її в код.
Помилка № 5: довгі гілки та «втрата змісту».
Іноді початківець пише в кожній гілці по 40 рядків. Формально це нормально, але читати такий код важко: поки дійдете до кінця, уже легко забути, яка саме умова привела вас у цю гілку. На цьому етапі курсу ми ще не розбираємо функції, тому рецепт простий: тримайте гілки короткими, виводьте зрозумілі повідомлення, а умови формулюйте максимально ясно. Коли дійдемо до функцій, навчимося розвантажувати main. А поки що тренуймо охайний стиль просто тут.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ