Перейти к содержимому
Теория · Циклы · урок 1 из 8

for, while и do-while

Чтобы напечатать числа от 1 до 5, можно написать пять строк с std::cout. Для тысячи чисел понадобилась бы тысяча строк. Вместо этого пишут цикл (loop) — конструкцию, которая повторяет действие, пока выполняется условие:

C++
#include <iostream>

int main() {
    for (int i = 1; i <= 5; ++i) {
        std::cout << i << ' ';  // 1 2 3 4 5
    }
    std::cout << '\n';
}

Как работает цикл for

В заголовке for три части через точку с запятой: инициализация, условие и шаг. Инициализация int i = 1 выполняется один раз, до начала цикла. Перед каждым проходом проверяется условие i <= 5: если оно истинно, выполняется тело, а за ним шаг ++i. Один проход тела называют итерацией (iteration).

Когда i становится равной 6, условие ложно, и цикл заканчивается. Переменная i объявлена в заголовке, поэтому видна только внутри цикла. После закрывающей скобки имени i уже нет.

Сколько итераций

Цикл выполняется столько раз, сколько значений принимает счётчик i. В for (int i = 0; i < 5; ++i) это значения от 0 до 4, то есть пять итераций. Знак < не пускает i к самой границе.

Если заменить < на <=, i дойдёт и до 5, и итераций станет шесть. Цикл, который выполняется на один раз больше или меньше нужного, содержит ошибку на единицу (off-by-one error).

while и do-while

Цикл while проверяет условие перед каждой итерацией, как for, но инициализации и шага в нём нет. Переменную объявляют до цикла, а меняют в теле. Так можно посчитать, сколько раз 100 нужно разделить нацело на 2, чтобы осталась 1:

C++
int n = 100;
int steps = 0;
while (n > 1) {
    n = n / 2;
    ++steps;
}
std::cout << steps << '\n';  // 6

Цикл do-while сначала выполняет тело и только потом проверяет условие. Поэтому его тело выполняется хотя бы один раз, даже если условие ложно с самого начала:

C++
int n = 10;
while (n < 5) {
    std::cout << n << '\n';
    ++n;
}
do {
    std::cout << n << '\n';  // 10
    ++n;
} while (n < 5);

Частая ошибка

Счётчик типа unsigned в цикле обратного отсчёта:

C++
for (unsigned i = 3; i >= 0; --i) {  // ✗
    std::cout << i << '\n';
}

Значение unsigned не бывает отрицательным, поэтому условие i >= 0 истинно всегда. После 0 вычитание единицы даёт наибольшее значение unsigned, и цикл печатает числа без конца. GCC с флагом -Wextra предупреждает, что сравнение всегда истинно, а Clang даже с -Wextra молчит. Для отсчёта до нуля объявите счётчик как int: после 0 он станет равен -1, и условие окажется ложным.