Безумовно, найбільш використовуваним циклом в мові C++ є цикл for.
Цикл for
Цикл for в мові С++ ідеальний, коли наперед відома необхідна кількість ітерацій. Виглядає він наступним чином:
for (оголошення змінних; умова; інкремент/декремент лічильника)
тіло циклу;
Або, конвертуючи for в еквівалентний цикл while:
{ // зверніть увагу, що цикл знаходиться в блоці
оголошення змінних;
while (умова)
{
тіло циклу;
інкремент/декремент лічильника;
}
} // змінні, оголошені всередині циклу, виходять з області видимості тут
Змінні, визначені всередині циклу for, мають спеціальний тип області видимості: область видимості циклу. Такі змінні існують тільки всередині циклу і недоступні за його межами.
Виконання циклу for
Цикл for в мові C++ виконується в 3 кроки:
Крок №1: Оголошення змінних. Як правило, тут виконується визначення та ініціалізація лічильників циклу, а точніше — одного лічильника циклу. Ця частина виконується тільки один раз, коли цикл виконується вперше.
Крок №2: Умова. Якщо вона дорівнює false, то цикл негайно завершує своє виконання. Якщо ж умова дорівнює true, то виконується тіло циклу.
Крок №3: Інкремент/декремент лічильника циклу. Змінна збільшується або зменшується на одиницю. Після цього цикл повертається до кроку №2.
Розглянемо приклад циклу for і розберемося детально, як він працює:
1 2 3 4 5 6 7 8 9 |
#include <iostream> int main() { for (int count = 0; count < 10; ++count) std::cout << count << " "; return 0; } |
Спочатку ми оголошуємо змінну count
і присвоюємо їй значення 0
. Далі виконується умова count < 10
, а оскільки count
дорівнює 0
, то умова 0 < 10
має значення true. Отже, виконається тіло циклу, в якому ми виводимо в консоль змінну count
(тобто 0
).
Потім виконається вираз ++count
, тобто інкремент змінної. Потім цикл знову повертається до перевірки умови. Умова 1 < 10
має значення true, тому тіло циклу виконається знову. Виводиться 1
, а змінна count
збільшується вже до значення 2
. Умова 2 < 10
є істинною, тому виводиться 2
, а count
збільшується до 3
і так далі.
В кінці, count
збільшується до 10
, а умова 10 < 10
є хибною, і цикл завершується. Отже, результат виконання програми:
0 1 2 3 4 5 6 7 8 9
Цикли for можуть бути трохи важкими для початківців, однак досвідчені програмісти їх люблять, тому що ці цикли дуже компактні та зручні. Наприклад, давайте перетворимо вищенаведений цикл for в еквівалентний цикл while:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#include <iostream> int main() { { // зовнішні дужки потрібні для забезпечення області видимості циклу int count = 0; while (count < 10) { std::cout << count << " "; ++count; } } return 0; } |
Зверніть увагу, що зовнішні фігурні дужки тут необхідні, так як змінна count
виходить з області видимості при завершенні циклу.
Ще приклади циклів for
Давайте напишемо функцію обчислення значень в степені n
, використовуючи цикл for:
1 2 3 4 5 6 7 8 9 |
int pow(int base, int exponent) { int total = 1; for (int count=0; count < exponent; ++count) total *= base; return total; } |
Функція повертає значення base^exponent
(число в степені n
). base
— це число, яке потрібно піднести до степеню, а exponent
— це степінь, до якого потрібно піднести base
.
Якщо експонент дорівнює 0
, то цикл for виконується 0 разів, і функція повертає 1
.
Якщо експонент дорівнює 1
, то цикл for виконується 1 раз, і функція повертає 1 * base
.
Якщо експонент дорівнює 2
, то цикл for виконується 2 рази, і функція повертає 1 * base * base
.
Хоча в більшості циклів використовується інкремент лічильника, ми також можемо використовувати і декремент лічильника:
1 2 3 4 5 6 7 8 9 |
#include <iostream> int main() { for (int count = 8; count >= 0; --count) std::cout << count << " "; return 0; } |
Результат:
8 7 6 5 4 3 2 1 0
Також з кожною новою ітерацією ми можемо збільшувати або зменшувати значення лічильника більше, ніж на одиницю:
1 2 3 4 5 6 7 8 9 |
#include <iostream> int main() { for (int count = 9; count >= 0; count -= 2) std::cout << count << " "; return 0; } |
Результат:
Помилка неврахованої одиниці
Однією з найчастіших проблем з якою стикаються початківці в циклах for (а також і в інших типах циклів) є помилка неврахованої одиниці. Вона виникає, коли цикл повторюється на 1 раз більше або на 1 раз менше від потрібної кількості ітерацій. Це зазвичай відбувається через те, що в умові використовується некоректний оператор порівняння (наприклад, >
замість >=
або навпаки). Як правило, ці помилки важко відстежити, тому що компілятор не скаржитиметься на них і програма працюватиме нормально, але її результати будуть неправильні.
При написанні циклів for пам’ятайте, що цикл виконуватиметься до тих пір, поки умова є істинною. Рекомендується тестувати цикли, використовуючи різні значення для перевірки працездатності циклу. Хорошою практикою є перевірка циклів за допомогою вхідних даних (чисел, символів та іншого), які змушують цикл виконатися 0, 1 і 2 рази. Якщо цикл працює справно, значить все ОК.
Правило: Тестуйте свої цикли, використовуючи вхідні дані, які змушують цикл виконатися 0, 1 і 2 рази.
Пропущені вирази в циклі
Також в циклах можна пропускати один або відразу всі вирази. Наприклад:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#include <iostream> int main() { int count = 0; for (; count < 10; ) { std::cout << count << " "; ++count; } return 0; } |
Результат:
0 1 2 3 4 5 6 7 8 9
Ініціалізацію лічильника ми прописали поза тілом циклу, а інкремент лічильника — всередині тіла циклу. У самому операторі for ми вказали лише умову. Іноді бувають випадки, коли не потрібно оголошувати лічильник циклу (тому що у нас вже є один) або збільшувати його (так як ми збільшуємо його якимось іншим способом).
Хоча це і не часто можна спостерігати, але в операторі for можна взагалі нічого не вказувати. Варто зазначити, що подібне призведе до нескінченного циклу:
for (;;)
тіло циклу;
Вищенаведений приклад еквівалентний наступному:
Оголошення змінних в циклі for
Хоча в циклах for зазвичай використовується тільки один лічильник, іноді можуть виникати ситуації, коли потрібно працювати відразу з декількома змінними. Для цього використовується оператор Кома. Наприклад:
1 2 3 4 5 6 7 8 9 10 |
#include <iostream> int main() { int aaa, bbb; for (aaa = 0, bbb = 9; aaa < 10; ++aaa, --bbb) std::cout << aaa << " " << bbb << std::endl; return 0; } |
Цей цикл присвоює значення двом раніше оголошеним змінним: aaa = 0
і bbb = 9
. Тільки з кожною ітерацією змінна aaa
збільшується на одиницю, а змінна bbb
— зменшується на одиницю.
Результат виконання програми:
0 9
1 8
2 7
3 6
4 5
5 4
6 3
7 2
8 1
9 0
Примітка: Вищенаведений цикл можна переписати наступним чином:
1 2 3 4 5 6 7 8 9 |
#include <iostream> int main() { for (int aaa = 0, bbb = 9; aaa < 10; ++aaa, --bbb) std::cout << aaa << " " << bbb << std::endl; return 0; } |
В такому випадку кома в оголошенні змінних є частиною синтаксису, а не використанням оператора Кома. Але ефект ідентичний.
Використання циклів for в старих версіях С++
У старих версіях мови C++ змінні, оголошені в циклі for, не знищувалися при завершенні цього циклу. Тобто у вас могло вийти щось на кшталт такого:
1 2 3 4 5 6 7 |
for (int count=0; count < 10; ++count) std::cout << count << " "; // В старих версіях мови С++ змінна count тут не знищується std::cout << "\n"; std::cout << "I counted to: " << count << "\n"; // тому ми можемо використовувати count навіть тут |
Пізніше це було заборонено, але ви все ще можете побачити подібне в старому коді.
Вкладені цикли for
Подібно іншим типам циклів, одні цикли for можуть бути вкладені в інші цикли for, що ви і можете побачити в наступному прикладі:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#include <iostream> int main() { for (char c = 'a'; c <= 'e'; ++c) // зовнішній цикл по буквам { std::cout << c; // спочатку виводимо букву for (int i = 0; i < 3; ++i) // внутрішній цикл по числам std::cout << i; std::cout << '\n'; } return 0; } |
З однією ітерацією зовнішнього циклу виконується три ітерації внутрішнього циклу. Відповідно, результат виконання програми:
Висновки
Цикли for є найбільш часто використовуваними циклами в мові C++. Незважаючи на те, що їх синтаксис, як правило, трохи заплутує початківців, ви дуже скоро до нього звикнете і відчуєте всю міць і зручність цих циклів.
Тест
Завдання №1
Напишіть цикл for, який виводить кожне парне число в діапазоні від 0 до 20.
Відповідь №1
1 2 3 4 5 6 7 8 9 |
#include <iostream> int main() { for (int count = 0; count <= 20; count += 2) std::cout << count << std::endl; return 0; } |
Завдання №2
Напишіть функцію sumTo(), яка приймає цілочисельний параметр з ім’ям value
і повертає суму всіх чисел від 1 до значення value
.
Наприклад, якщо значенням value
є 5, то sumTo(5)
повинен повернути 15
, виходячи з 1 + 2 + 3 + 4 + 5
.
Підказка: Використовуйте змінну поза тілом циклу для зберігання суми чисел, як в прикладі з функцією pow() в підрозділі “Ще приклади циклів for”.
Відповідь №2
1 2 3 4 5 6 7 8 |
int sumTo(int value) { int total(0); for (int count=1; count <= value; ++count) total += count; return total; } |
Завдання №3
Що не так з наступним циклом?
1 2 3 |
// Виводимо всі числа від 8 до 0 for (unsigned int count=8; count >= 0; --count) cout << count << " "; |
Відповідь №3
Цей цикл for виконується до тих пір, поки count >= 0
. Іншими словами, він працює до тих пір, поки змінна count
не стане від’ємним числом. Однак, оскільки count
є типу unsigned, то ця змінна ніколи не зможе бути від’ємною. Отже, цей цикл нескінченний! Як правило, рекомендується уникати використання типів unsigned в циклі, якщо на це немає вагомих причин.