Циклы while и repeat, вложенность и досрочный выход
Урок разбирает циклы while и repeat, которые повторяют действия по условию, вложенные циклы и способы досрочно выйти из цикла.
while повторяет тело, пока условие истинно; repeat...until повторяет тело, пока условие не станет истинным.
Когда число повторов заранее неизвестно
Цикл for хорош, когда мы точно знаем, сколько раз повторить. Но часто это неизвестно. «Повторяй, пока пользователь не введёт правильный пароль». «Дели число пополам, пока оно больше единицы». «Считай цифры числа, пока оно не обнулится». Здесь количество шагов зависит от данных. Для таких задач нужны циклы, управляемые условием, а не счётчиком: while и repeat.
Цикл while: проверка в начале
Цикл while («пока») проверяет условие перед каждым повторением. Пока условие истинно — тело выполняется; как только стало ложным — цикл завершается:
var
n: integer;
begin
n := 100;
while n > 1 do
begin
write(n, ' ');
n := n div 2; // уменьшаем n, иначе зациклимся
end;
writeln;
end.
Эта программа делит 100 пополам, пока число больше 1: 100, 50, 25, 12, 6, 3, 1. Ключевой момент — внутри тела мы обязательно меняем переменную n, от которой зависит условие. Если этого не делать, условие навсегда останется истинным, и программа зациклится — будет крутиться вечно. Это самая опасная ошибка с while. Запустите аналог:
n = 100
while n > 1:
print(n, end=' ')
n = n // 2
print()
Вывод:
100 50 25 12 6 3
Важная особенность while: если условие ложно с самого начала, тело не выполнится ни разу. Проверка стоит в начале — это цикл «с предусловием».
Цикл repeat: проверка в конце
Цикл repeat...until («повторять... пока не») устроен наоборот: тело выполняется сначала, а условие проверяется в конце. Поэтому тело гарантированно выполнится хотя бы один раз. И ещё отличие: repeat повторяется, пока условие ложно, и останавливается, когда оно становится истинным (until = «до тех пор, пока не»).
var
password: integer;
begin
repeat
write('Введите код (нужен 42): ');
readln(password);
until password = 42;
writeln('Доступ разрешён!');
end.
Этот цикл будет спрашивать код снова и снова, пока пользователь не введёт 42. Идеально для проверки ввода: спросить хотя бы раз, а повторять при ошибке. Приятный бонус: repeat...until сам по себе ограничивает блок команд, поэтому begin...end внутри не нужны.
| Признак | while | repeat |
| Где проверка условия | в начале | в конце |
| Повторяется, пока условие... | истинно | ложно |
| Минимум выполнений тела | 0 раз | 1 раз |
| Нужны begin/end | да (для нескольких команд) | нет |
Разбор числа на цифры
Классическая задача на while — посчитать сумму цифр числа, когда мы не знаем, сколько в нём цифр. Используем приёмы из урока про div и mod: mod 10 даёт последнюю цифру, div 10 убирает её. Повторяем, пока число не обнулится:
n = 4926
sum = 0
while n > 0:
sum = sum + n % 10 # прибавляем последнюю цифру
n = n // 10 # убираем последнюю цифру
print('Сумма цифр:', sum)
Вывод:
Сумма цифр: 21
Здесь for не подошёл бы — мы заранее не знаем число цифр. А while отлично справляется: крутится ровно столько раз, сколько цифр в числе.
Вложенные циклы
Цикл можно поместить внутрь другого цикла — получится вложенный цикл. Это нужно, когда у задачи два измерения: строки и столбцы, пары элементов, таблица. Внешний цикл делает один шаг — внутренний прокручивается полностью:
for i in range(1, 4):
for j in range(1, 4):
print(i, '*', j, '=', i * j, end=' ')
print() # перенос строки после каждой строки таблицы
Вывод:
1 * 1 = 1 1 * 2 = 2 1 * 3 = 3 2 * 1 = 2 2 * 2 = 4 2 * 3 = 6 3 * 1 = 3 3 * 2 = 6 3 * 3 = 9
На Паскале это выглядело бы так: внешний for i := 1 to 3, а внутри него — for j := 1 to 3 со своим телом. У каждого цикла своя переменная-счётчик (i и j). Вложенные циклы — основа работы с таблицами и матрицами, которые мы изучим в следующем разделе.
Досрочный выход: break и continue
Иногда нужно прервать цикл раньше, не дожидаясь его естественного конца. Например, ищем элемент и нашли — зачем продолжать? Для этого есть две команды:
break— немедленно выйти из цикла полностью.continue— пропустить остаток текущего шага и перейти к следующему повтору.
for i in range(1, 11):
if i == 5:
print('Нашли пятёрку, выходим')
break
print('Проверяю', i)
Вывод:
Проверяю 1 Проверяю 2 Проверяю 3 Проверяю 4 Нашли пятёрку, выходим
В Паскале эти команды называются так же: break и continue. Пользуйтесь ими аккуратно: они удобны, но избыток досрочных выходов делает логику цикла запутанной. Часто более ясно подобрать правильное условие в while.
Попробуй сам
Напишите программу, которая находит наименьший делитель числа (кроме 1). Перебирайте делители d от 2 и проверяйте n mod d = 0; как только нашли — выводите и выходите через break. Проверьте на Python для числа 91:
n = 91
d = 2
while d <= n:
if n % d == 0:
print('Наименьший делитель:', d)
break
d = d + 1
Вывод:
Наименьший делитель: 7
Частые ошибки
- Зацикливание. Если в
whileне менять переменную из условия, цикл крутится вечно. Всегда проверяйте, что тело приближает условие к завершению. - Перепутали смысл until.
repeatостанавливается, когда условие истинно, аwhile— когда ложно. Это противоположные логики. - Лишние begin/end в repeat. Внутри
repeat...untilсоставной оператор не нужен — конструкция сама ограничивает блок. - Одна переменная на два вложенных цикла. Внешнему и внутреннему циклу нужны разные счётчики (
iиj).
Итоги
while условие doпроверяет условие в начале и повторяет тело, пока оно истинно (может не выполниться ни разу).repeat ... until условиепроверяет условие в конце, тело выполняется минимум один раз и повторяется, пока условие ложно.- В цикле по условию обязательно меняйте переменную, влияющую на условие, иначе программа зациклится.
- Вложенные циклы (цикл внутри цикла) нужны для таблиц и матриц; у каждого свой счётчик.
breakдосрочно выходит из цикла,continueпропускает остаток шага и переходит к следующему.