Цикл do-while с постусловием. Вложенные циклы

Практический курс по C/C++: https://stepik.org/course/193691

На этом занятии рассмотрим последний такой оператор – цикл с постусловием do-while, который имеет следующий синтаксис:

do {
    [оператор (один или несколько)]
} while(<условие>);

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

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

Давайте рассмотрим пример, где использование такого типа цикла оправдано. Предположим, пользователь должен ввести кодовое число, чтобы получить доступ к чему-либо. Для этого вначале нужно попросить его ввести числовое значение и только после этого проверить, совпадает ли ввод с кодовым числом. Если совпадает, то предоставить доступ, а иначе попросить ввести код еще раз. Эту логику проще всего реализовать с помощью оператора цикла do-while следующим образом:

#include <stdio.h>
 
int main(void)
{
         int pass_code = 13;
         int enter_code;
 
         do {
                   printf("Please enter the secret code: ");
                   scanf("%d", &enter_code);
         } while(enter_code != pass_code);
 
         printf("Access is allowed\n");
 
         return 0;
}

Сначала будет выполнена итерация цикла, то есть, операторы, записанные в теле цикла. В результате пользователь получает возможность ввести кодовое значение. А затем, в цикле выполняется обратная проверка на неравенство значений. Почему так? Потому что мы здесь прописываем условие продолжения цикла. И цикл должен продолжаться, пока пользователь не введет верное кодовое число. В этом случае условие становится ложным и управление передается следующему оператору printf(), записанному после цикла do-while.

Как видите, цикл с постусловием полезен, когда нам в программе нужно вначале выполнить некоторые повторяющиеся действия и только после этого решить, продолжать цикл или завершить. В действительности, это не частая ситуация и по этой причине оператор цикла do-whileна практике применяется реже двух остальных: while и for, о которых мы с вами уже говорили на предыдущих занятиях.

Также обратите внимание, как записан в тексте программы этот оператор цикла. Ключевое слово whileстоитв одной строчке с закрывающейся фигурной скобкой.Так принято делать, чтобы визуально подчеркнуть, что while здесь – это завершение конструкции, которая начинается с ключевого слова do. И чтобы не спутать этот whileс другим таким же оператором уже цикла с предусловием. Например, давайте усовершенствуем нашу программу, и будем очищать буфер входного потока stdinпосле каждого ввода:

#include <stdio.h>
 
int main(void)
{
         int pass_code = 13;
         int enter_code;
         int c;
 
         do {
                   printf("Please enter the secret code: ");
                   scanf("%d", &enter_code);
 
                   while ((c = getchar()) != '\n' && c != EOF) { }
         } while(enter_code != pass_code);
 
         printf("Access is allowed\n");
 
         return 0;
}

Я здесь использую цикл whileс вызовом функции getchar(), которая читает один байт из потока stdin. Цикл останавливается, если прочитан символ переноса строки (\n) или конца файла (EOF). Это простейший вариант очистки буфера входного потока. И, смотрите, в тексте программы идут друг за другом два слова while. Но, тем не менее, они легко различаются, так как имеются отступы у операторов тела цикла.

Или может быть ситуация, когда после цикла do-whileидет цикл while:

#include <stdio.h>
 
int main(void)
{
         int pass_code = 13;
         int enter_code;
         int c;
 
         do {
                   printf("Please enter the secret code: ");
                   scanf("%d", &enter_code);
 
                   while ((c = getchar()) != '\n' && c != EOF) { }
         } while(enter_code != pass_code);
 
         while ((c = getchar()) != '\n' && c != EOF) { }
 
         printf("Access is allowed\n");
 
         return 0;
}

При нашем способе оформления текста программы все три цикла хорошо различимы и не возникает никакой путаницы. Именно поэтому рекомендуется оператор do-whileзаписывать в таком виде.

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

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

Чаще всего вложенные циклы можно увидеть с операторами for. Поэтому в нашем примере будут фигурировать именно они. А сам пример будет следующим. Представим, что нам нужно выполнить полный перебор документов (файлов), лежащих в нескольких ящиках (box). В каждом ящике одинаковое число файлов, а всего ящиков пусть будет три.

Для решения этой задачи воспользуемся вложенными циклами for следующим образом:

#include <stdio.h>
 
int main(void)
{
         int total_boxs = 3;
         int total_files = 6;
         
         for(int i = 0;i <total_boxs; ++i)
                   for(int j = 0; j <total_files; ++j)
                            printf("Box %d, file %d\n", i+1, j+1);
 
         return 0;
}

Смотрите, сначала срабатывает первый (внешний) цикл со счетчиком (переменной) i, который содержит номер текущего просматриваемого ящика. Затем, запускается итерация этого внешнего цикла (выполняются операторы, записанные в теле цикла). В результате запускается второй (внутренний) цикл, который перебирает документы текущего ящика. Для каждого документа выводится информация в формате:

Box<номер ящика>, file<номер документа>

В результате, после просмотра всех документов первого ящика на экране появятся строчки:

Box 1, file 1
Box 1, file 2
Box 1, file 3
Box 1, file 4
Box 1, file 5
Box 1, file 6

После этого работа внутреннего цикла завершается и управление передается внешнему циклу. В нем происходит увеличение счетчика i на единицу и проверяется условие цикла. Так как оно истинно, то запускается вторая итерация и снова срабатывает внутренний цикл, но уже для перебора документов второго ящика. И так для всех трех ящиков.

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

Мало того, при необходимости, мы можем увеличивать число вложений операторов циклов и осуществлять перебор элементов не только в плоскости, но и в объеме и вообще в Nмерном пространстве. Хотя, на практике слишком увлекаться этим не стоит, т.к. сложность понимания и восприятия программы растет с числом этих вложений. Обычно, ограничиваются двумя, тремя уровнями. При правильной организации логики программы этого оказывается вполне достаточно.

Чтобы закрепить этот материал предлагаю самостоятельно написать программу для вычисления следующей суммы:

Если все правильно сделаете, то должны получить ответ 2750.

Практический курс по C/C++: https://stepik.org/course/193691

Видео по теме