for, while и do-while
Чтобы напечатать числа от 1 до 5, можно написать пять строк с std::cout. Для тысячи чисел понадобилась бы тысяча строк. Вместо этого пишут цикл (loop) — конструкцию, которая повторяет действие, пока выполняется условие:
#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:
int n = 100;
int steps = 0;
while (n > 1) {
n = n / 2;
++steps;
}
std::cout << steps << '\n'; // 6Цикл do-while сначала выполняет тело и только потом проверяет условие. Поэтому его тело выполняется хотя бы один раз, даже если условие ложно с самого начала:
int n = 10;
while (n < 5) {
std::cout << n << '\n';
++n;
}
do {
std::cout << n << '\n'; // 10
++n;
} while (n < 5);Частая ошибка
Счётчик типа unsigned в цикле обратного отсчёта:
for (unsigned i = 3; i >= 0; --i) { // ✗
std::cout << i << '\n';
}Значение unsigned не бывает отрицательным, поэтому условие i >= 0 истинно всегда. После 0 вычитание единицы даёт наибольшее значение unsigned, и цикл печатает числа без конца. GCC с флагом -Wextra предупреждает, что сравнение всегда истинно, а Clang даже с -Wextra молчит. Для отсчёта до нуля объявите счётчик как int: после 0 он станет равен -1, и условие окажется ложным.