1. Знайомство з циклом do-while
Іноді в програмі є дії, які треба виконати щонайменше один раз, навіть якщо «умова продовження» від початку може виявитися хибною. У коді таке трапляється, коли потрібно хоча б раз показати меню, хоча б раз попросити користувача ввести значення або хоча б раз виконати тіло циклу, щоб узагалі отримати дані для перевірки.
Уявімо типову задачу: «запитати в користувача число й повторювати запит, доки він не введе число, більше за нуль». Щоб перевірити умову «більше за нуль», спершу треба це число зчитати. Отже, щонайменше один прохід тут життєво необхідний: без нього ми просто не матимемо значення для перевірки. Саме тому do-while робить такий сценарій максимально простим.
Синтаксис do-while і обов’язкова ;
У do-while синтаксис простий, але має одну особливість: наприкінці обов’язково ставиться крапка з комою. Це один із небагатьох випадків у C++, коли конструкція виглядає трохи незвично. Тому варто запам’ятати весь шаблон цілком, а не складати його з окремих шматків уже перед «іспитом» у компілятора. Форма така: спочатку do, потім блок, далі while (умова) і обов’язкова ;.
Ось мінімальний приклад: «виконаємо один раз і вийдемо», бо умова хибна:
#include <iostream>
int main() {
int x = 0;
do {
std::cout << "Привіт!\n"; // Привіт!
} while (x > 0);
}
Ключова думка: умова перевіряється після тіла. Тому тіло гарантовано виконається хоча б один раз. Так, крапка з комою після while (...) обов’язкова — без неї буде помилка компіляції.
while і do-while: одна відмінність — різні наслідки
Різниця між while і do-while здається невеликою, але наслідки можуть бути дуже помітними. У while ми спочатку перевіряємо умову й лише потім виконуємо тіло. У do-while — навпаки: спочатку виконуємо тіло, а вже потім перевіряємо умову. Це впливає на те, чи виконається тіло хоча б один раз, і саме цього часто бракує.
Порівняймо обидва варіанти на одному й тому самому значенні x = 0:
#include <iostream>
int main() {
int x = 0;
while (x > 0) {
std::cout << "while\n";
}
do {
std::cout << "do-while\n"; // do-while
} while (x > 0);
}
Якщо сприймати це як невелику історію, то while каже: «поки правда — роблю». А do-while каже: «роблю, а потім вирішую, чи повторювати». Другий варіант логічний, коли перша дія важлива сама собою: показати меню, попросити користувача ввести значення, вивести підказку, зробити «першу спробу».
2. Коли do-while зручний у реальному коді
Введення й меню без зайвої акробатики
На практиці do-while найчастіше використовують у двох сценаріях. Перший — це «введення з повтором»: запитати в користувача значення, перевірити, чи воно підходить, і, якщо ні, запитати знову. Другий — «консольне меню»: показати список команд, дати користувачеві вибрати дію, виконати її й знову показати меню, доки не буде вибрано вихід.
Зауважте: обидві ситуації об’єднує спільна логіка — без першого проходу нічого не працює. Поки меню не показали, обирати нічого. Поки значення не зчитали, перевіряти нічого. Це як намагатися оцінити смак борщу, не скуштувавши його. Хоча дехто так і робить, але це вже окрема дисципліна.
Приклад: просимо число > 0
Почнімо з простого: зчитуємо n і повторюємо запит, доки користувач не введе n > 0. Це ідеальний випадок для do-while, бо нам потрібно щонайменше один раз виконати читання.
#include <iostream>
int main() {
int n = 0;
do {
std::cout << "Введіть n (> 0): ";
std::cin >> n;
} while (n <= 0);
std::cout << "n = " << n << '\n'; // наприклад: n = 5
}
Зверніть увагу: умова наприкінці читається майже як звичайний текст: «повторювати, доки n <= 0». Це хороший стиль для do-while: формулювати умову саме як умову продовження, а не виходу. Так ви менше плутатиметеся в ! і в самій логіці.
3. Приклад: консольне меню «скарбничка»
Почнімо створювати невеликий консольний застосунок, який розвиватимемо в темах про цикли. Сьогодні закладемо основу: «скарбничка» — умовний бюджет, до якого можна додавати гроші, переглядати баланс, обнуляти його й виходити. Жодних масивів, функцій чи складних структур — поки що все тримається на int, if/else і циклах.
Скелет меню на do-while
Спочатку зробимо скелет меню на do-while. Це зручно: меню має з’явитися щонайменше один раз.
#include <iostream>
int main() {
int balance = 0;
int cmd = -1;
do {
std::cout << "1 - Додати\n2 - Показати\n3 - Скинути\n0 - Вихід\n";
std::cin >> cmd;
if (cmd == 2) {
std::cout << "Баланс = " << balance << '\n'; // Баланс = 0
}
} while (cmd != 0);
}
Це ще не «застосунок мрії», але головне вже видно: do-while робить структуру «показати меню → зчитати команду → виконати дію → повторити» дуже прямою. З while це теж можна зробити, але тоді часто доводиться або дублювати виведення меню, або мудрувати з підготовчими кроками перед циклом.
Додавання та скидання балансу
Тепер додамо обробку команд 1 і 3. Ми, як і раніше, працюємо в межах уже вивченого: тільки if/else і базова арифметика. Водночас не варто перетворювати тіло циклу на «простирадло», у якому важко зрозуміти, що відбувається. Краще тримати логіку прямою: зчитали команду → обрали дію → виконали її.
#include <iostream>
int main() {
int balance = 0;
int cmd = -1;
do {
std::cout << "1 - Додати\n2 - Показати\n3 - Скинути\n0 - Вихід\n";
std::cin >> cmd;
if (cmd == 1) {
int add = 0;
std::cout << "Сума поповнення: ";
std::cin >> add;
balance = balance + add;
} else if (cmd == 2) {
std::cout << "Баланс = " << balance << '\n';
} else if (cmd == 3) {
balance = 0;
std::cout << "Баланс скинуто.\n"; // Баланс скинуто.
}
} while (cmd != 0);
}
Зауважте один важливий момент: змінна add існує лише всередині гілки cmd == 1. Це нормально й навіть корисно: менше шансів випадково використати її «пізніше», коли вона вже не потрібна.
Обробка невідомих команд
Якщо користувач введе 42, програма зараз мовчки це «проковтне» й просто знову покаже меню. Формально це не помилка, але UX виходить як в автомата з кавою, який просто ігнорує вас і робить вигляд, що нічого не сталося. І все одно просить гроші. Додаймо м’яку обробку невідомих команд.
#include <iostream>
int main() {
int balance = 0;
int cmd = -1;
do {
std::cout << "1 - Додати\n2 - Показати\n3 - Скинути\n0 - Вихід\n";
std::cin >> cmd;
if (cmd == 1) {
int add = 0;
std::cout << "Сума поповнення: ";
std::cin >> add;
balance = balance + add;
} else if (cmd == 2) {
std::cout << "Баланс = " << balance << '\n';
} else if (cmd == 3) {
balance = 0;
std::cout << "Баланс скинуто.\n";
} else if (cmd != 0) {
std::cout << "Невідома команда.\n"; // Невідома команда.
}
} while (cmd != 0);
}
Зверніть увагу, наскільки акуратно виглядає умова else if (cmd != 0): ми не сваримося на команду виходу, бо вона якраз правильна. Це дрібниця, але саме з таких дрібниць складається «відчуття, що програма жива».
4. Порядок виконання та часті пастки
Схема виконання do-while
Коли новачки плутаються в циклах, найчастіше проблема не в синтаксисі, а в порядку виконання. Тому корисно хоча б раз побачити блок-схему. Читайте її так: спочатку виконується тіло, потім перевіряється умова — і далі або повтор, або вихід.
flowchart TD
A[Вхід у do-while] --> B[Виконати тіло циклу]
B --> C{Умова істинна?}
C -->|так| B
C -->|ні| D[Вихід із циклу]
Якщо ви триматимете в голові цю схему, зникне більша частина помилок на кшталт «чому воно виконалося один раз, хоча умова хибна». Бо для do-while це не баг, а сама суть.
Цикл має рухатися до завершення
do-while не скасовує головного правила всіх циклів: має бути причина, через яку цикл колись закінчиться. Іноді причина — у зміні змінної, іноді — у введенні користувача, іноді — у зменшенні числа діленням, як ви вже бачили в інших прикладах. Але причина має бути.
У нашому меню причина завершення проста: користувач вводить 0, і умова cmd != 0 стає хибною. Якби ми забули зчитувати cmd усередині тіла або випадково перезаписали cmd не тим значенням, могли б отримати нескінченний цикл. Нескінченні цикли самі по собі не є «злом», але сьогодні ми зосереджуємося на коректних циклах, що завершуються. Тож ставтеся до цього як до договору: «кожна ітерація наближає нас до виходу».
Крапка з комою та порожнє тіло
У do-while є дві «класичні пастки», які трапляються так часто, що їх уже можна вважати програмістським фольклором. Перша — забута ; після while (...). Друга — зайва ; не там, де треба: через неї цикл перетворюється на дивну конструкцію, у якій вам здається, що всередині щось відбувається, а насправді — ні.
Правильний шаблон варто запам’ятати візуально:
do {
// тіло
} while (умова);
Якщо ви одного разу почнете сприймати } while (...) ; як одну «зв’язку», помилок стане помітно менше.
5. Типові помилки під час роботи з do-while
Помилка № 1: забули крапку з комою після while (умова).
Ця помилка особливо неприємна тим, що мозок кричить: «ну це ж майже як while!», а компілятор кричить у відповідь: «ні». Лікується просто: вивчайте do-while як готовий шаблон do { ... } while (...); і в навчальних проєктах завжди ставте фігурні дужки, навіть якщо всередині лише один рядок.
Помилка № 2: переплутали умову продовження й умову виходу.
Часто пишуть умову «як вийти», а потім ставлять її в while (...), унаслідок чого цикл працює навпаки. Хороша звичка — читати умову вголос саме як умову продовження: «повторювати, доки …». Якщо фраза звучить неприродно, найімовірніше, ви написали умову виходу, а не умову повторення.
Помилка № 3: тіло циклу не змінює ситуацію, і цикл стає нескінченним.
У меню це трапляється, якщо ви забули std::cin >> cmd;, або випадково зчитуєте не в cmd, або постійно присвоюєте cmd одне й те саме значення. У циклах введення таке буває, якщо змінна з умови взагалі ніде не змінюється. Перед запуском програми корисно запитати себе: «Що зміниться за одну ітерацію? Чому це наближає нас до завершення?».
Помилка № 4: забагато логіки в одному місці, і цикл стає нечитабельним.
do-while часто використовують для меню, а меню легко перетворюється на «комбайн»: десять команд, двадцять if, і ви вже боїтеся відкривати цей файл. Навіть без функцій, поки ми їх ще не проходили, можна тримати дисципліну: нехай тіло щоразу виконує той самий порядок дій — показати підказку → прочитати команду → виконати одну гілку → повернутися на початок.
Помилка № 5: випадково зробили порожній цикл через зайву ; не там.
Іноді ставлять do { ... }; while (cond); або утворюють інші комбінації, після яких програма компілюється, але поводиться «якось дивно». Коли поведінка здається магічною, майже завжди винна пунктуація: ; і {}. У C++ це не прикраси, а керувальні елементи мови. Ставтеся до них як до дротів у щитку: зайвий дріт може не просто «заважати», а й замкнути логіку.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ