Технологии и методы программирования — на главную

Циклы. for, while, вложенные циклы

Цикл while и счётчик, поиск минимума и суммы последовательности, цифры числа, цикл for и do-while, вложенные циклы, break и continue, отладка и вечный цикл.

лекции 2 ч
лаб. 4 ч
СРС 6 ч

Ветвление позволило программе выбрать одно из продолжений. Цикл позволяет выполнить одни и те же действия много раз — и это первая конструкция, с которой программа может обработать данные, объём которых заранее неизвестен. Заодно появляется новая неприятность: цикл может не закончиться никогда.

Цикл while

«While» переводится как «пока» и в программировании означает «пока условие верно, нужно выполнять следующие действия». В жизни цикл «пока» встречается очень часто. Например, вам срочно понадобились фиолетовые кроссовки для вечеринки. Как описать ваши действия? «Пока не найдёшь фиолетовые кроссовки — ходи по магазинам. Как только найдёшь — покупай».

while очень похож на if, но если if выполняет действия один раз, то while будет делать их до тех пор, пока выполнено условие.

Рассмотрим цикл на примере. Есть число N; нужно вывести все числа по возрастанию от 1 до N. Заведём счётчик — переменную i, равную текущему числу. Вначале это единица. Пока значение счётчика не превысит N, выводим его текущее значение и каждый раз увеличиваем на единицу:

int i, n;
cin >> n;
i = 1;
while (i <= n) {
    cout << i << " ";
    i = i + 1;
}
cout << endl;

Когда выполнение доходит до закрывающей фигурной скобки, происходит возврат к строке с while и повторная проверка условия. Если оно верно, блок команд выполняется ещё раз; если нет — программа продолжается с команд после блока.

У любого цикла со счётчиком три обязательные части, и забыть можно любую:

  1. начальное значение счётчика — до цикла (i = 1);
  2. условие продолжения — в заголовке (i <= n);
  3. изменение счётчика — в теле (i = i + 1).

Попробуйте ввести 0 и объяснить результат: условие ложно с самого начала, и тело цикла не выполняется ни разу. Это нормальное и частое поведение while.

Поиск минимума последовательности

Компания друзей хочет купить пиццу. Чтобы не платить за доставку, нужно послать кого-нибудь в пиццерию. Кого? Самого младшего. Формально: среди последовательности чисел нужно найти и вывести минимальное. Последовательность состоит из положительных чисел и оканчивается нулём.

Как такую задачу будет решать человек? Каждый раз, когда ему называют число, он сравнивает его с тем минимумом, который встречался раньше, и, если новое число ещё меньше, запоминает его. Так продолжается, пока числа не закончатся. Вначале нужно запомнить самое первое названное число, в конце — назвать запомненное.

int min, now;
cin >> now;
min = now;
while (now != 0) {
    if (now < min) {
        min = now;
    }
    cin >> now;
}
cout << min << endl;

Разберите два места, в которых легко ошибиться. Первое: min = now до цикла. Начать с нуля нельзя — тогда ноль и окажется минимумом; начать с «очень большого числа» можно, но первый элемент для этого подходит лучше. Второе: чтение следующего числа — последняя команда тела. Если поставить его первым, первое число прочитается дважды.

Сумма последовательности

Те же друзья решили посчитать, хватит ли у них денег: каждый говорит, сколько у него есть. Последовательность из положительных чисел оканчивается нулём, нужно вывести сумму всех элементов.

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

int sum = 0, now;
cin >> now;
while (now != 0) {
    sum = sum + now;
    cin >> now;
}
cout << sum << endl;

Сравните с предыдущей задачей: структура цикла та же, различаются только начальное значение (0 против первого элемента) и действие в теле. Это общий шаблон «накопитель», и он же сработает для произведения, количества подходящих элементов или максимума.

Цифры числа

Задачи на подсчёт суммы, минимумов и максимумов встречаются очень часто. Например, задача о счастливом билетике: если сумма цифр в первой половине номера совпадает с суммой цифр во второй половине, билет считается счастливым (и его нужно съесть).

Мы уже знаем, как узнать последнюю цифру числа — остаток от деления на 10, — и как отбросить её: поделить число на 10 нацело. Значит, можно поочерёдно рассмотреть все цифры справа налево и остановиться, когда цифры закончатся (число станет равным нулю). Сумму считаем накопителем, и делаем это для каждой половины номера:

int part1, part2;
cin >> part1 >> part2;
int sum1 = 0, sum2 = 0;
while (part1 != 0) {
    sum1 = sum1 + part1 % 10;
    part1 = part1 / 10;
}
while (part2 != 0) {
    sum2 = sum2 + part2 % 10;
    part2 = part2 / 10;
}
if (sum1 == sum2) {
    cout << "Lucky ticket";
} else {
    cout << "unlucky :(";
}
cout << endl;

Обратите внимание: условие цикла здесь не счётчик, а сама обрабатываемая величина. Число уменьшается на каждом шаге и гарантированно дойдёт до нуля. Проверьте на 123 321 и на 123 124.

Цикл for

В цикле со счётчиком три части — начальное значение, условие и изменение — разбросаны по трём разным местам программы, и любую из них легко потерять. Цикл for собирает их в одну строку:

for (начальное значение; условие; изменение) {
    // тело цикла
}

Та же задача о выводе чисел от 1 до N:

int n;
cin >> n;
for (int i = 1; i <= n; i++) {
    cout << i << " ";
}
cout << endl;

Порядок работы: один раз выполняется начальное значение, затем проверяется условие, затем тело, затем изменение, затем снова условие — и так далее. for и while взаимозаменяемы: любой for переписывается в while и наоборот.

Когда что выбирать: for — когда число повторений известно («для каждого элемента», «десять раз»), while — когда неизвестно («пока не встретится ноль», «пока не найдём»). Технической разницы нет, но правильно выбранный цикл сам объясняет читателю, что происходит.

Ещё одно практическое отличие: int i объявлена внутри for, и после цикла её не существует. Это хорошо — счётчик не мешается дальше в программе, — но если значение счётчика нужно после цикла, переменную придётся объявить до него.

Цикл do…while

Третья форма: условие проверяется после тела, поэтому тело выполняется хотя бы один раз.

int n;
do {
    cin >> n;
    cout << "прочитано " << n << endl;
} while (n <= 0);
cout << "принято: " << n << endl;

Это типичное применение do…while: проверка введённого значения. Прочитать число надо до того, как его можно проверить, поэтому условие и оказывается внизу. Тот же алгоритм на while потребовал бы читать число дважды — до цикла и в конце тела, — и это ровно та дубликация, от которой избавляет do…while.

Обратите внимание на точку с запятой после while (n <= 0); — она обязательна.

Вложенные циклы

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

for (int i = 1; i <= 5; i++) {
    for (int j = 1; j <= 5; j++) {
        cout << setw(4) << i * j;
    }
    cout << endl;
}

Внешний цикл отвечает за строки, внутренний — за столбцы внутри строки, а cout << endl стоит между циклами: после каждой строки, но не после каждого числа. Манипулятор setw(4) из <iomanip> выравнивает столбцы, отводя каждому числу четыре позиции.

Число шагов у вложенных циклов перемножается: 5 × 5 — это 25 выполнений внутреннего тела. Поменяйте границы на 100 и 100 — будет уже десять тысяч, и это стоит помнить, когда внутри цикла происходит что-то тяжёлое.

Второй важный момент — у каждого цикла свой счётчик. Если внутренний цикл использует тот же i, что и внешний, программа сломается самым запутанным способом: внешний цикл получит изменённый счётчик.

Инструкции break и continue

Для управления поведением цикла есть две инструкции, которые позволяют досрочно прерывать выполнение цикла или начинать выполнение его тела сначала.

break прекращает работу цикла — как будто не было выполнено условие. Осмысленное использование break возможно только внутри if внутри цикла. Использование break — плохой тон, по возможности следует обходиться без него. Пример ниже — именно пример, так писать не нужно:

int i;
i = 1;
while (1) {
    cout << i;
    i = i + 1;
    if (i > 100)
        break;
}
cout << endl;

Условие while (1) — всегда истина, то есть цикл сам по себе бесконечный, и единственный выход из него — break. Сравните с обычной записью while (i <= 100): она делает то же самое, но условие окончания видно в заголовке, а не спрятано в середине тела. Именно поэтому break считают плохим тоном: он прячет условие выхода.

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

Дана последовательность чисел, оканчивающаяся нулём; нужно вывести все положительные числа из неё (при решении этой задачи можно и нужно обходиться без continue, но для примера):

int now;
now = -1;
while (now != 0) {
    cin >> now;
    if (now <= 0)
        continue;
    cout << now << " ";
}
cout << endl;

В этом решении есть интересный момент: перед циклом переменная инициализируется заведомо подходящим значением — иначе первая же проверка условия читала бы мусор. Команда вывода выполняется только в том случае, если не выполнится условие в if.

`continue` в цикле `for` и в цикле `while` ведут себя по-разному

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

Вечный цикл

С помощью while очень легко сделать вечный цикл: достаточно написать условие, которое никогда не будет нарушено. Возьмём задачу о выводе всех чисел от 1 до 100 и забудем об увеличении счётчика:

int i;
i = 1;
while (i <= 100) {
    cout << i << " ";
}

Эта программа будет работать вечно, потому что счётчик всегда будет равен единице. Этот фрагмент не сделан запускаемым намеренно — запустить его здесь нельзя: страница ждала бы результата, которого не будет.

Как прервать зациклившуюся программу

В среде разработки: в Visual Studio — Shift+F5, в Code::Blocks и VS Code — кнопка остановки в панели запуска. В терминале — Ctrl+C. Закрывать чёрное окно консоли крестиком не стоит: программа может остаться в памяти.

На этой странице всё проще: у запускаемых примеров есть ограничение по времени, и зациклившийся пример остановится сам с сообщением о превышении времени. Попробуйте: впишите бесконечный цикл в любой пример выше.

Отладка программ

Мы дошли до достаточно сложных программ, и находить в них ошибку методом пристального взгляда бывает непросто. Для облегчения поиска ошибок есть средства отладки.

Основной инструмент — точка остановки (breakpoint). Она ставится на строке, перед выполнением которой программу нужно остановить. Когда выполнение доходит до точки остановки, оно прерывается, и можно посмотреть текущие значения всех переменных: обычно достаточно навести курсор на имя переменной в коде.

Дальше есть два способа продолжить: до следующей точки остановки или пошагово, строка за строкой. Во второй режиме выполняется одна выделенная строка, и происходит переход к следующей команде. В Visual Studio это F5 и F10; в других средах клавиши свои, но режимы те же.

Чаще всего отладка состоит в том, чтобы поставить точку остановки в начале потенциально ошибочного кода, запустить программу, проверить, что всё считалось правильно, а затем выполнять программу пошагово, смотреть на значения переменных и ловить момент, когда что-то пойдёт не так.

На этой странице отладчика нет

Примеры на сайте запускаются целиком: есть код, ввод и вывод, точку остановки поставить некуда. Это ограничение браузерного запуска, и обходится оно единственным способом — выводом на печать: добавьте cout внутрь цикла и напечатайте значения переменных на каждом шаге.

Приём кажется примитивным, но работает везде, не требует настройки и остаётся основным инструментом отладки у очень многих. Попробуйте на примере с поиском минимума: напечатайте now и min в начале каждого шага и посмотрите, как минимум обновляется.

Задание к лабораторной

Рабочая программа не даёт отдельных вариантов по циклам, поэтому задания ниже составлены к этому уроку.

Вариант 1. Программа читает целое число n и печатает: сумму всех чисел от 1 до n, их произведение и количество чётных среди них. Все три величины считаются в одном цикле. В отчёте укажите, при каком n произведение перестаёт помещаться в int, и как это проявляется.

Вариант 2. Программа читает последовательность целых чисел, оканчивающуюся нулём, и печатает: количество чисел, их сумму, минимум, максимум и среднее арифметическое. Предусмотрите случай, когда первое же введённое число — ноль (последовательность пуста).

Вариант 3. Программа читает натуральное число и печатает: количество его цифр, сумму цифр, число, записанное теми же цифрами в обратном порядке, и является ли число палиндромом. Используйте только цикл и операции % и /, без строк и массивов.

Вариант 4. Программа печатает таблицу умножения от a до b (границы вводятся) вложенными циклами, с выравниванием столбцов и подписанной первой строкой. Проверьте случай a > b.

Вариант 5. Программа читает целое число и определяет, простое ли оно, перебором возможных делителей в цикле. Определите, до какого предела достаточно проверять делители, и обоснуйте это в отчёте.

Как оценивается лабораторная

Работа сдаётся преподавателю очно: сайт её не принимает и не оценивает. Шкала и показатели ниже — из рабочей программы дисциплины, раздел 7.

Показатели оценки

  1. степень соответствия выполненного задания поставленным целям, задачам и требованиям;
  2. оформление, структурирование и комментирование лабораторной работы;
  3. уникальность выполнения работы (отличие от работ коллег);
  4. успешные ответы на контрольные вопросы.

Баллы

  • 86–100
    отлично— оформление соответствует требованиям, критерии выдержаны, защита всего перечня контрольных вопросов.
  • 66–85
    хорошо— оформление соответствует требованиям, критерии выдержаны, защита только до 85 % контрольных вопросов.
  • 51–65
    удовлетворительно— оформление соответствует требованиям, критерии выдержаны, защита только до 51 % контрольных вопросов.
  • 0–50
    неудовлетворительно— оформление не соответствует требованиям, критерии не выдержаны, защита менее 51 % контрольных вопросов.

Проверьте себя

Викторина по теме

Вопрос 1 из 10
да или нет

Тело цикла while может не выполниться ни разу.

Ссылки на литературу

  1. Воробьев, Г. А. Основы программирования на C++ : учебно-методическое пособие. — Липецк : Липецкий ГПУ, 2022. — 89 с. — ISBN 978-5-907461-84-0. Лань : электронно-библиотечная система (дата обращения: 15.01.2026). Доступ: для авторизованных пользователей
  2. Калитвин, В. А. Введение в программирование на C++ : учебное пособие. — Липецк : Липецкий ГПУ, 2023. — 84 с. — ISBN 978-5-907655-86-7. Лань : электронно-библиотечная система (дата обращения: 15.01.2026). Доступ: для авторизованных пользователей
  3. Широбокова, С. Н., Кацупеев, А. А., Сулыз, А. В. Программирование на языке C++ для лабораторных занятий : учебное пособие. — Новочеркасск : ЮРГПУ, 2020. — 104 с. — ISBN 978-5-9997-0725-3. Лань : электронно-библиотечная система (дата обращения: 15.01.2026). Доступ: для авторизованных пользователей
Мой прогресс

Содержание