На цьому уроці ми розглянемо оператори умовного розгалуження if/else та те, як їх можна використовувати.
Умовні розгалуження if/else
Найпростішими умовними розгалуженнями в мові С++ є стейтменти if/else. Вони виглядають наступним чином:
if (вираз)
стейтмент1
або
if (вираз)
стейтмент1
else
стейтмент2
вираз називається умовою (або “умовним виразом”). Якщо результатом виразу є true (будь-яке ненульове значення), то виконуватися буде стейтмент1. Якщо ж результатом виразу є false (0), то виконуватися буде стейтмент2. Наприклад:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#include <iostream> int main() { std::cout << "Enter a number: "; int a; std::cin >> a; if (a > 15) std::cout << a << " is greater than 15\n"; else std::cout << a << " is not greater than 15\n"; return 0; } |
Використання декількох операцій в розгалуженнях if/else
Оператор if виконує тільки одну операцію, якщо вираз є true, і також лише одну операцію else, якщо вираз є false. Щоб виконати декілька операцій поспіль, використовуйте блок стейтментів:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
#include <iostream> int main() { std::cout << "Enter a number: "; int a; std::cin >> a; if (a > 15) { // Обидві операції будуть виконані, якщо a > 15 std::cout << "You entered " << a << "\n"; std::cout << a << " is greater than 15\n"; } else { // Обидві операції будуть виконані, якщо a <= 15 std::cout << "You entered " << a << "\n"; std::cout << a << " is not greater than 15\n"; } return 0; } |
Неявне вказування блоків
Якщо програміст не вказав дужки для блоку стейтментів if/else, то компілятор неявно зробить це замість нього. Таким чином, наступне:
if (вираз)
стейтмент1
else
стейтмент2
Буде виконуватися як:
if (вираз)
{
стейтмент1
}
else
{
стейтмент2
}
По суті, це не має значення. Однак початківці іноді намагаються зробити щось на кшталт наступного:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#include <iostream> int main() { if (1) int a = 4; else int a = 5; std::cout << a; return 0; } |
Програма не скомпілюється, і в підсумку ми отримаємо помилку, що ідентифікатор a не визначений. А станеться це через те, що програма буде виконуватися в такий спосіб:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include <iostream> int main() { if (1) { int a = 4; } // змінна a знищується тут else { int a = 5; } // змінна a знищується тут std::cout << a; // змінна a тут не визначена return 0; } |
У цьому контексті стає зрозумілим, що змінна a має локальну область видимості і знищується в кінці блоку, в якому вона ініціалізована. Але поки ми дійдемо до рядка з std::cout, то змінна a вже перестане існувати.
Поєднання стейтментів if
Стейтменти if/else можна поєднувати:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include <iostream> int main() { std::cout << "Enter a number: "; int a; std::cin >> a; if (a > 15) std::cout << a << " is greater than 15\n"; else if (a < 15) std::cout << a << " is less than 15\n"; else std::cout << a << " is exactly 15\n"; return 0; } |
Вкладені розгалуження if/else
Одні стейтменти if можуть бути вкладені в інші стейтменти if:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#include <iostream> int main() { std::cout << "Enter a number: "; int a; std::cin >> a; if (a > 15) // зовнішній оператор if // Це поганий спосіб написання вкладених стейтментів if if (a < 25) // внутрішній оператор if std::cout << a << " is between 15 and 25\n"; // До якого if відноситься наступний else? else std::cout << a << " is greater than 25\n"; return 0; } |
Зверніть увагу, що у вищенаведеній програмі ми можемо спостерігати потенційну помилку двозначності оператора else. До якого if відноситься оператор else: до зовнішнього чи до внутрішнього?
Справа в тому, що оператор else завжди відноситься до останнього незакритого оператору if в блоці, в якому знаходиться сам else. Тобто у вищенаведеній програмі else відноситься до внутрішнього if.
Щоб уникнути таких ось неоднозначностей при вкладеності операторів умовного розгалуження, рекомендується використовувати блоки стейтментів (вказувати дужки). Наприклад, ось вищенаведена програма, але вже без двозначності:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#include <iostream> int main() { std::cout << "Enter a number: "; int a; std::cin >> a; if (a > 15) { if (a < 25) std::cout << a << " is between 15 and 25 (inclusive)\n"; else // відноситься до внутрішнього оператора if std::cout << a << " is greater than 25\n"; } return 0; } |
Тепер зрозуміло, що оператор else відноситься до внутрішнього оператора if. Використання дужок також дозволяє явно вказати прив’язку else до зовнішнього оператора if:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#include <iostream> int main() { std::cout << "Enter a number: "; int a; std::cin >> a; if (a > 15) { if (a < 25) std::cout << a << " is between 15 and 25 (inclusive)\n"; } else // відноситься до зовнішнього оператора if std::cout << a << " is less than 15\n"; return 0; } |
Використовуючи блоки стейтментів, ми уточнюємо, до якого if слід прикріплювати певний else. Без блоків оператор else буде прикріплюватися до найближчого незакритого оператора if.
Використання логічних операторів в розгалуженнях if/else
Також ви можете перевірити відразу декілька умов в розгалуженнях if/else, використовуючи логічні оператори:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#include <iostream> int main() { std::cout << "Enter an integer: "; int a; std::cin >> a; std::cout << "Enter another integer: "; int b; std::cin >> b; if (a > 0 && b > 0) // && - це логічне І. Перевіряємо, чи є дві умови істинними std::cout << "Both numbers are positive\n"; else if (a > 0 || b > 0) // || - це логічне АБО. Перевіряємо, чи є істинною хоч одна з умов std::cout << "One of the numbers is positive\n"; else std::cout << "Neither number is positive\n"; return 0; } |
Основні використання розгалужень if/else
Розгалуження if/else активно використовуються для перевірки помилок. Наприклад, щоб обчислити квадратний корінь значення, параметр, який передається в функцію для обчислення, обов’язково повинен бути додатним:
|
1 2 3 4 5 6 7 8 9 10 |
#include <iostream> #include <cmath> // для функції sqrt() void printSqrt(double value) { if (value >= 0.0) std::cout << "The square root of " << value << " is " << sqrt(value) << "\n"; else std::cout << "Error: " << value << " is negative\n"; } |
Також оператори if використовують для ранніх повернень, коли функція повертає управління назад у викликаючий об’єкт ще до завершення виконання самої функції. У програмі, наведеній нижче, якщо значенням параметра є від’ємне число, то функція відразу ж повертає у викликаючий об’єкт символьну константу або енумератор в якості коду помилки:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
#include <iostream> enum class ErrorCode { ERROR_SUCCESS = 0, ERROR_NEGATIVE_NUMBER = -1 }; ErrorCode doSomething(int value) { // Якщо параметром value є від'ємне число, if (value < 0) // то відразу ж повертаємо код помилки return ErrorCode::ERROR_NEGATIVE_NUMBER; // Що-небудь робимо return ErrorCode::ERROR_SUCCESS; } int main() { std::cout << "Enter a positive number: "; int a; std::cin >> a; if (doSomething(a) == ErrorCode::ERROR_NEGATIVE_NUMBER) { std::cout << "You entered a negative number!\n"; } else { std::cout << "It worked!\n"; } return 0; } |
Розгалуження if/else також зазвичай використовують для виконання простих математичних операцій. Наприклад, розглянемо функцію min(), яка повертає мінімальне з двох чисел:
|
1 2 3 4 5 6 7 |
int min(int a, int b) { if (a > b) return b; else return a; } |
Ця функція настільки проста, що її можна переписати, використовуючи умовний тернарний оператор:
|
1 2 3 4 |
int min(int a, int b) { return (a > b) ? b : a; } |
Нульові стейтменти
Також в мові C++ можна не вказувати основну частину оператора if. Такі стейтменти називаються нульовими стейтментами (або “null-стейтментами”). Оголосити їх можна, використовуючи крапку з комою замість виконуваної операції. З метою поліпшення читабельності коду, крапка з комою нульового стейтменту зазвичай пишеться з нового рядка. Таким чином, ми явно вказуємо, що хочемо використати null-стейтмент, зменшуючи ймовірність не помітити його використання:
|
1 2 |
if (a > 15) ; // це нульовий стейтмент |
Хоча нульові стейтменти рідко використовуються в поєднанні з оператором if, але, через необережність, це може призвести до проблем. Розглянемо наступний фрагмент коду:
|
1 2 |
if (a == 0); a = 1; |
У вищенаведеному прикладі ми випадково вказали крапку з комою в кінці оператора if. Ця необачність призведе до того, що код буде виконуватися наступним чином:
|
1 2 3 |
if (a == 0) ; // крапка з комою вказує на те, що це нульовий стейтмент a = 1; // і цей рядок виконається в будь-якому випадку! |
Попередження: Завжди перевіряйте, чи не “закрили” ви випадково оператор if крапкою з комою.
