Menu

Цикл while в C++: синтаксис, do-while и подводные камни

Цикл while в C++: while с проверкой условия в начале, do-while с выполнением хотя бы один раз, цикл до сигнального значения, break и continue, а также как избежать бесконечных циклов.

На этой странице есть исполняемые редакторы: меняйте, запускайте и сразу видите результат.

Когда у вас нет счётчика

Цикл for построен вокруг счётчика, который вы задаёте заранее. Но у множества циклов нет понятного счёта: продолжать читать числа, пока не закончится ввод, продолжать запрашивать пароль, пока он не окажется верным, продолжать делить значение пополам, пока оно не достигнет 1. Для таких случаев цикл while подходит естественным образом — он просто повторяется, пока условие остаётся истинным.

Цикл while проверяет условие перед каждым проходом, включая самый первый. Если условие ложно с самого начала, тело не выполнится вовсе.

Условие count > 0 проверяется первым; если оно истинно, тело выполняется, затем мы возвращаемся и проверяем снова. Строка count-- — это то, что в итоге делает условие ложным: уберите её, и цикл будет работать вечно.

Анатомия цикла while

Сравните его с трёхчастным циклом for, который вы уже знаете. Цикл while разделяет эти три задачи: инициализацию вы делаете перед циклом, условие помещается в скобки, а обновление живёт внутри тела.

int i = 0;          // инициализация - перед циклом
while (i < 5) {     // условие - проверяется на каждом проходе
    cout << i << "\n";
    i++;            // обновление - о нём нужно помнить самому
}

Именно эта последняя часть — главная ловушка. В цикле for обновление стоит прямо рядом с условием, так что его трудно забыть. В цикле while это просто ещё один оператор в теле — самая частая ошибка в том, чтобы его пропустить и подвесить программу.

Подводный камень C++, на котором спотыкаются новички: случайная точка с запятой сразу после условия превращает тело в пустой оператор.

int i = 0;
while (i < 5);   // <-- эта точка с запятой и есть всё тело цикла
{
    cout << i << "\n";
    i++;
}

Это вечно крутится, ничего не делая, потому что ; и есть тело, а i никогда не меняется. Блок в фигурных скобках затем выполняется ровно один раз. Компилятор вас не остановит — это совершенно корректный код, просто не то, что вы имели в виду.

do-while: выполнить тело хотя бы один раз

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

Вам нужно хотя бы раз запросить и прочитать ввод, прежде чем вы узнаете, корректен ли он, — а это как раз то, что даёт do-while. Обратите внимание на точку с запятой после while (...): в C++ она обязательна для do-while, и забыть её — частая ошибка компиляции.

Отличие от обычного while чётко проявляется, когда условие изначально ложно:

Выведется только do-while body. Цикл while полностью пропускает своё тело, потому что x < 5 было ложно ещё до первой проверки.

Цикл, пока cin не даст сбой

Классическое применение while — читать, пока не прекратится ввод: счётчика нет, вы просто продолжаете, пока поток не скажет завершить. В C++ cin >> value вычисляется в сам поток, который истинен, пока чтение успешно, и ложен, как только он достигает конца ввода или несовпадения типов. Это делает его аккуратным условием цикла:

Условие выполняет двойную работу: оно читает и проверяет за один шаг. Сравните это с сигнальным значением — скажем, остановкой на 0. Там нужно прочитать один раз до цикла и ещё раз в конце каждого прохода, чтобы условие всегда проверяло свежий ввод:

Если вы забудете второе чтение внутри тела, value никогда не изменится, и вы получите бесконечный цикл. Форма while (cin >> value) обходит это, вкладывая чтение прямо в условие.

break и continue в циклах while

break и continue работают здесь так же, как в цикле for. break немедленно выходит из цикла; continue сразу переходит к проверке условия, пропуская остаток текущего прохода:

Это выводит 1 3 5 7 9. while (true) намеренно никогда не останавливается сам по себе — break является единственным выходом. Будьте осторожны с continue в цикле while: поскольку обновление является частью тела, переход к началу через continue до того, как вы продвинули счётчик, — это тихий способ подвесить цикл. В примере выше n++ выполняется первым, поэтому всё безопасно.

Остерегайтесь бесконечных циклов

Условие должно в конце концов стать ложным, и это полностью зависит от того, что что-то внутри тела меняется. Двое обычных виновников — забыть обновление и обновлять так, что значение выхода перескакивается:

int i = 0;
while (i < 5) {
    cout << i << "\n";   // i никогда не меняется -> работает вечно
}
int i = 0;
while (i != 10) {
    i += 3;   // 0, 3, 6, 9, 12... перешагивает прямо через 10 -> работает вечно
}

Первый зависает, потому что i никогда не обновляется. Второй зависает, потому что счётчик перешагивает точное значение, которое ищет условие, — предпочитайте < или <= вместо !=, когда шаг может не попасть точно. while (true) приемлем, если у него есть гарантированный break; случайный — это просто баг. И помните о ловушке пустого тела while (...); из начала: неуместная точка с запятой создаёт бесконечный цикл, который на первый взгляд выглядит правильным.

Далее: цикл for на основе диапазона

Цикл while — правильный инструмент, когда вы повторяете до изменения условия и понятного счёта нет. Но когда вы просто хотите обойти каждый элемент контейнера — vector, массива, string — без индекса и условия, которым нужно управлять, в современном C++ есть кое-что чище: цикл for на основе диапазона (for (auto x : container)). Это тема следующей страницы.

Часто задаваемые вопросы

В чём разница между while и do-while в C++?

Цикл while проверяет условие перед первым проходом, поэтому тело может не выполниться ни разу. Цикл do-while сначала один раз выполняет тело, а затем проверяет условие в конце — поэтому он всегда выполняется как минимум один раз. Используйте do-while, когда работа должна произойти до того, как вы сможете решить, повторять ли её, например запросить ввод, а затем проверить его. Учтите, что do-while требует точку с запятой после закрывающего while (...).

Когда в C++ стоит использовать цикл while вместо for?

Используйте цикл while, когда у вас нет понятного счётчика и вы просто хотите повторять до тех пор, пока не изменится некое условие — читать ввод, пока cin не даст сбой, опрашивать, пока значение не будет готово, или обрабатывать очередь, пока она не опустеет. Прибегайте к циклу for, когда вы знаете число итераций или у вас есть очевидный индекс для подсчёта.

Как остановить бесконечный цикл while в C++?

Убедитесь, что что-то внутри тела в конце концов делает условие ложным (уменьшает счётчик, продвигает указатель, устанавливает флаг). Для намеренного цикла while (true) поместите внутрь break, защищённый if. Если цикл зависает, обычная причина — забыли обновить переменную, от которой зависит условие.

Coddy programming languages illustration

Учитесь программировать с Coddy

НАЧАТЬ