Краткое содержание
Урок От задачи к алгоритму выделил три способа составлять шаги: следование, ветвление и повторение. У первых двух уже есть своя запись в C++; этот урок даёт её третьему. Он изучает три формы цикла: while, который вычисляет своё условие перед каждой итерацией и может ни разу не выполнить тело; do, который вычисляет его после и выполняет тело хотя бы один раз; и for, который собирает в одной строке инициализацию, условие и приращение переменной, управляющей повторением. Урок показывает, что все три выражают один и тот же механизм, так что каждая форма преобразуется в другие, и учит выбирать самую ясную; знакомит с break и continue, которые меняют ход итерации; и завершается вложенными циклами, внутреннее тело которых выполняется столько раз, сколько даёт некоторая сумма. Инструмент, сопровождающий весь урок, есть таблица трассировки: выполнить цикл вручную, итерация за итерацией, значит предсказать, сколько раз выполнится его тело и что он оставит после выхода.
Цели обучения
- Писать цикл
while,doилиforдля заданного повторения, выбирая самую ясную форму. - Выполнять цикл вручную с таблицей трассировки и предсказывать, сколько раз выполнится тело.
- Преобразовывать цикл из одной формы в другую, сохраняя его смысл.
- Писать вложенные циклы и вычислять, сколько раз выполняется внутреннее тело.
while
Форма цикла while
Цикл while записывается так:
while (условие) { тело}Его смысл формулируется в три шага: вычисляется условие; если оно ложно, цикл завершается и выполнение продолжается после закрывающей его фигурной скобки; если истинно, выполняется тело и происходит возврат к первому шагу. Каждое выполнение тела называется итерацией (или проходом). Условие есть логическое выражение вроде тех, что рассматривал урок Отношения и логика, а тело есть блок; правило фигурных скобок, установленное уроком Ветвления, действует и здесь: тело цикла всегда заключается в фигурные скобки, даже если в нём одна инструкция.
Из определения следуют два вывода. Первый: условие вычисляется перед каждой итерацией, так что если оно ложно с самого начала, тело не выполняется ни разу. Второй: чтобы цикл завершился, тело должно менять что-то из того, что читает условие; если ничего не меняется, условие, однажды оказавшееся истинным, будет истинным всегда. Однако менять недостаточно: урок От задачи к алгоритму показал, что нужна натуральная величина, убывающая на каждой итерации, вариант цикла, а урок Проектирование правильных циклов превратит её в метод.
Деление последовательными вычитаниями
Первым алгоритмом с повторением в этом курсе было деление последовательными вычитаниями: пока остаток не меньше делителя, из него вычитается делитель, а к частному прибавляется единица. На C++ этот алгоритм переносится почти слово в слово.
#include <iostream>#include <print>int main(){ int a{}; int b{}; std::cin >> a >> b; int q{0}; int r{a}; while (r >= b) { r -= b; ++q; } std::println("{} = {} · {} + {}", a, b, q, r);}23 723 = 7 · 3 + 2Строки 9 и 10 дают переменным начальные значения: ещё ничего не вычтено, поэтому частное равно 0, а остаток равен всему делимому. Строка 11 есть условие шага 2 алгоритма; строки 12 и 13 образуют тело. Программа предполагает, как и алгоритм, что и : при строка 12 не меняла бы r и цикл не завершился бы.
Таблица трассировки
Выполнить цикл вручную значит заполнить таблицу: одна строка на итерацию, один столбец на переменную и ещё один для условия, вычисленного в начале итерации. Строка 0 фиксирует состояние перед первым вычислением условия; последняя строка фиксирует вычисление, которое оказывается ложным и завершает цикл.
Доказательство
Перед циклом выполняются строки 9 и 10: и . Это строка 0 таблицы; условие ещё не вычислялось.
Первая итерация. Условие истинно, поэтому выполняется тело: становится равным 16, а равным 1. Затем выполнение возвращается к строке 11.
Вторая итерация. Условие истинно: становится равным 9, а равным 2.
Третья итерация. Условие истинно: становится равным 2, а равным 3.
Четвёртое вычисление, , даёт ложь: тело не выполняется, цикл завершается, и строка 15 выводит .
Трассировка учит считать. Тело выполнилось три раза, столько же, сколько составляет частное, а условие вычислялось четыре раза: по одному на итерацию и ещё одно, неудачное. Это соотношение верно для любого while, завершающегося по своему условию: если тело выполняется раз, условие вычисляется раз. И крайний случай это подтверждает: при входных данных 5 7 первое вычисление, , уже ложно, тело выполняется ноль раз, и программа выводит , что верно. Правильно написанный while без дополнительного кода справляется со случаем, когда повторять нечего.
Загрузка содержимого…