Хоча ви вже бачили оператор break в зв’язці з оператором switch, все ж він заслуговує більшої уваги, оскільки може використовуватися і з циклами. Оператор break призводить до завершення виконання циклів do, for та while.
break і switch
В контексті оператора switch оператор break зазвичай використовується в кінці кожного кейсу для його завершення (запобігаючи виконанню fall-through):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
switch (op) { case '+': doAddition(a, b); break; case '-': doSubtraction(a, b); break; case '*': doMultiplication(a, b); break; case '/': doDivision(a, b); break; } |
break і цикли
В контексті циклів оператор break використовується для передчасного завершення роботи циклу:
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 |
#include <iostream> int main() { int sum = 0; // Дозволяємо користувачеві ввести до 10 чисел for (int count=0; count < 10; ++count) { std::cout << "Enter a number to add, or 0 to exit: "; int val; std::cin >> val; // Виходимо з циклу, якщо користувач ввів 0 if (val == 0) break; // В протилежному випадку, додаємо число до загальної суми sum += val; } std::cout << "The sum of all the numbers you entered is " << sum << "\n"; return 0; } |
Ця програма дозволяє користувачеві ввести до 10 чисел і в кінці підраховує їх суму. Якщо користувач ввів 0
, то виконається break і цикл завершиться (не важливо, скільки чисел в цей момент встиг ввести користувач).
Зверніть увагу, що оператор break може використовуватися і для виходу з нескінченного циклу:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#include <iostream> int main() { while (true) // нескінченний цикл { std::cout << "Enter 0 to exit or anything else to continue: "; int val; std::cin >> val; // Виходимо з циклу, якщо користувач ввів 0 if (val == 0) break; } std::cout << "We're out!\n"; return 0; } |
break і return
Початківці часто плутають або не розуміють різниці між операторами break і return. Оператор break завершує роботу switch або циклу, а виконання коду продовжується зі стейтменту, який знаходиться відразу ж після цього switch або циклу. Оператор return завершує виконання всієї функції, в якій знаходиться цикл, а виконання продовжується в точці після виклику функції:
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 |
#include <iostream> int breakOrReturn() { while (true) // нескінченний цикл { std::cout << "Enter 'b' to break or 'r' to return: "; char sm; std::cin >> sm; if (sm == 'b') break; // виконання коду продовжиться з першого стейтменту після циклу if (sm == 'r') return 1; // виконання оператора return призведе до того, що точка виконання відразу повернеться у викликаючий об'єкт (в даному випадку, в функцію main()) } // Використання оператора break призведе до того, що виконання циклу продовжиться тут std::cout << "We broke out of the loop\n"; return 0; } int main() { int returnValue = breakOrReturn(); std::cout << "Function breakOrContinue returned " << returnValue << '\n'; return 0; } |
Оператор continue
Оператор continue дозволяє відразу перейти в кінець тіла циклу, пропускаючи весь код, який знаходиться під ним. Це корисно в тих випадках, коли ми передчасно хочемо завершити поточну ітерацію. Наприклад:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#include <iostream> int main() { for (int count = 0; count < 20; ++count) { // Якщо число ділиться націло на 4, то пропускаємо весь код в даній ітерації після continue if ((count % 4) == 0) continue; // пропускаємо все і переходимо в кінець тіла циклу // Якщо число не ділиться націло на 4, то виконання коду продовжується std::cout << count << std::endl; // Точка виконання після оператора continue переміщується сюди } return 0; } |
Ця програма виведе всі числа від 0 до 19, які не діляться націло на 4.
У випадку з циклом for частина інкременту/декременту лічильника як і раніше виконується навіть після виконання continue (так як інкремент/декремент відбувається поза тілом циклу).
Будьте обережні при використанні оператора continue з циклами while або do while. Оскільки в цих циклах інкремент лічильників виконується безпосередньо в тілі циклу, то використання continue може призвести до того, що цикл стане нескінченним! Наприклад:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include <iostream> int main() { int count(0); while (count < 10) { if (count == 5) continue; // переходимо в кінець тіла циклу std::cout << count << " "; ++count; // Точка виконання після оператора continue переміщується сюди } return 0; } |
Мається на увазі, що програма виведе всі числа від 0 до 9, за винятком 5. Але насправді:
0 1 2 3 4
А потім цикл стане нескінченним. Коли значенням count
стає 5
, то умова оператора if стане true, потім виконається continue і ми, минаючи вивід числа і інкремент лічильника, перейдемо до наступної ітерації. Змінна count
так і не збільшиться. Як результат, в наступній ітерації змінна count
як і раніше залишиться зі значенням 5
, а оператор if, як і раніше, залишиться true, і цикл стане нескінченним.
А ось правильне рішення, але з використанням циклу do while:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#include <iostream> int main() { int count(0); do { if (count == 5) continue; // переходимо в кінець тіла циклу std::cout << count << " "; // Точка виконання після оператора continue переміщується сюди } while (++count < 10); // цей код виконується, тому що знаходиться поза тілом циклу return 0; } |
Результат виконання програми:
break і continue
Багато підручників по програмуванню попереджають не використовувати оператори break та continue, оскільки вони призводять до безпідставного переміщення точки виконання програми по всьому коду, що ускладнює розуміння і слідування логіки виконання такого коду.
Проте розумне використання операторів break і continue може поліпшити читабельність циклів в програмі, зменшивши при цьому кількість вкладених блоків і необхідність наявності складної логіки виконання циклів. Наприклад, розглянемо наступну програму:
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() { int count(0); // рахуємо кількість ітерацій циклу bool exitLoop(false); // контролюємо завершення виконання циклу while (!exitLoop) { std::cout << "Enter 'e' to exit this loop or any other key to continue: "; char sm; std::cin >> sm; if (sm == 'e') exitLoop = true; else { ++count; std::cout << "We've iterated " << count << " times\n"; } } return 0; } |
Ця програма використовує змінну логічного типу даних для виходу з циклу, а також вкладений блок, який працюватиме тільки в тому випадку, якщо користувач не використовує символ виходу.
А ось читабельніша версія, але з використанням оператора break:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#include <iostream> int main() { int count(0); // рахуємо кількість ітерацій циклу while (true) // виконання циклу продовжується, якщо його не завершить користувач { std::cout << "Enter 'e' to exit this loop or any other key to continue: "; char sm; std::cin >> sm; if (sm == 'e') break; ++count; std::cout << "We've iterated " << count << " times\n"; } return 0; } |
Тут (з одним оператором break) ми уникли використання як логічної змінної (а також розуміння того, навіщо вона і де використовується), так і оператора else з вкладеним блоком.
Зменшення кількості використовуваних змінних і вкладених блоків покращують читабельність і розуміння коду набагато краще, ніж оператори break або continue можуть завдати шкоди. З цієї причини вважається прийнятним їх розумне використання.