Циклы в программировании. Цикл while
Циклы являются такой же важной частью структурного программирования, как условные операторы. С помощью циклов можно организовать повторение выполнения участков кода. Потребность в этом возникает довольно часто. Например, пользователь последовательно вводит числа, и каждое из них требуется добавлять к общей сумме. Или нужно вывести на экран квадраты ряда натуральных чисел и тому подобные задачи.
Цикл while
«While» переводится с английского как «пока». Но не в смысле «до свидания», а в смысле «пока имеем это, делаем то».
Можно сказать, while является универсальным циклом. Он присутствует во всех языках, поддерживающих структурное программирование, в том числе в Python. Его синтаксис обобщенно для всех языков можно выразить так:
while логическое_выражение
Это похоже на условный оператор if . Однако в случае циклических операторов их тела могут выполняться далеко не один раз. В случае if , если логическое выражение в заголовке возвращает истину, то тело выполняется единожды. После этого поток выполнения программы возвращается в основную ветку и выполняет следующие выражения, расположенные ниже всей конструкции условного оператора.
В случае while , после того как его тело выполнено, поток возвращается к заголовку цикла и снова проверяет условие. Если логическое выражение возвращает истину, то тело снова выполняется. Потом снова возвращаемся к заголовку и так далее.
Цикл завершает свою работу только тогда, когда логическое выражение в заголовке возвращает ложь, то есть условие выполнения цикла больше не соблюдается. После этого поток выполнения перемещается к выражениям, расположенным ниже всего цикла. Говорят, «происходит выход из цикла».
Рассмотрите блок-схему цикла while .

На ней ярко-голубыми прямоугольниками обозначена основная ветка программы, ромбом – заголовок цикла с логическим выражением, бирюзовым прямоугольником – тело цикла.
С циклом while возможны две исключительные ситуации:
- Если при первом заходе в цикл логическое выражение возвращает False , то тело цикла не выполняется ни разу. Эту ситуацию можно считать нормальной, так как при определенных условиях логика программы может предполагать отсутствие необходимости в выполнении выражений тела цикла.
- Если логическое выражение в заголовке while никогда не возвращает False , а всегда остается равным True , то цикл никогда не завершится, если только в его теле нет оператора принудительного выхода из цикла ( break ) или вызовов функций выхода из программы – quit() , exit() в случае Python. Если цикл повторяется и повторяется бесконечное количество раз, то в программе происходит зацикливание. В это время она зависает и самостоятельно завершиться не может.
Вспомним наш пример из урока про исключения. Пользователь должен ввести целое число. Поскольку функция input() возвращает строку, то программный код должен преобразовать введенное к целочисленному типу с помощью функции int() . Однако, если были введены символы, не являющиеся цифрами, то возникает исключение ValueError , которое обрабатывается веткой except . На этом программа завершается.
Другими словами, если бы программа предполагала дальнейшие действия с числом (например, проверку на четность), а она его не получила, то единственное, что программа могла сделать, это закончить свою работу досрочно.
Но ведь можно просить и просить пользователя корректно вести число, пока он его не введет. Вот как может выглядеть реализующий это код:
n = input("Введите целое число: ") while type(n) != int: try: n = int(n) except ValueError: print("Неправильно ввели!") n = input("Введите целое число: ") if n % 2 == 0: print("Четное") else: print("Нечетное")
Примечание 1. Не забываем, в языке программирования Python в конце заголовков сложных инструкций ставится двоеточие.
Примечание 2. В выражении type(n) != int с помощью функции type() проверяется тип переменной n . Если он не равен int , то есть значение n не является целым числом, а является в данном случае строкой, то выражение возвращает истину. Если же тип n равен int , то данное логическое выражение возвращает ложь.
Примечание 3. Оператор % в языке Python используется для нахождения остатка от деления. Так, если число четное, то оно без остатка делится на 2, то есть остаток будет равен нулю. Если число нечетное, то остаток будет равен единице.
Проследим алгоритм выполнения этого кода. Пользователь вводит данные, они имеют строковый тип и присваиваются переменной n . В заголовке while проверяется тип n . При первом входе в цикл тип n всегда строковый, то есть он не равен int . Следовательно, логическое выражение возвращает истину, что позволяет зайти в тело цикла.
Здесь в ветке try совершается попытка преобразования строки к целочисленному типу. Если она была удачной, то ветка except пропускается, и поток выполнения снова возвращается к заголовку while .
Теперь n связана с целым числом, следовательно, ее тип int , который не может быть не равен int . Он ему равен. Таким образом логическое выражение type(n) != int возвращает False , и весь цикл завершает свою работу. Далее поток выполнения переходит к оператору if-else, находящемуся в основной ветке программы. Здесь могло бы находиться что угодно, не обязательно условный оператор.
Вернемся назад. Если в теле try попытка преобразования к числу была неудачной, и было выброшено исключение ValueError , то поток выполнения программы отправляется в ветку except и выполняет находящиеся здесь выражения, последнее из которых просит пользователя снова ввести данные. Переменная n теперь имеет новое значение.
После завершения except снова проверяется логическое выражение в заголовке цикла. Оно даст True , так как значение n по-прежнему строка.
Выход из цикла возможен только тогда, когда значение n будет успешно конвертировано в число.
Рассмотрим следующий пример:
total = 100 i = 0 while i 5: n = int(input()) total = total - n i = i + 1 print("Осталось", total)
Сколько раз «прокрутится» цикл в этой программе, то есть сколько итераций он сделает? Ответ: 5.
- Сначала переменная i равна 0. В заголовке цикла проверяется условие i < 5 , и оно истинно. Тело цикла выполняется. В нем меняется значение i , путем добавления к нему единицы.
- Теперь переменная i равна 1. Это меньше пяти, и тело цикла выполняется второй раз. В нем i меняется, ее новое значение 2.
- Два меньше пяти. Тело цикла выполняется третий раз. Значение i становится равным трем.
- Три меньше пяти. На этой итерации i присваивается 4.
- Четыре по прежнему меньше пяти. К i добавляется единица, и теперь ее значение равно пяти.
«Смысловая нагрузка» данного цикла – это последовательное вычитание из переменной total вводимых чисел. Переменная i в данном случае играет только роль счетчика итераций цикла. В других языках программирования для таких случаев предусмотрен цикл for , который так и называется: «цикл со счетчиком». Его преимущество заключается в том, что в теле цикла не надо изменять переменную-счетчик, ее значение меняется автоматически в заголовке for .
В языке Python тоже есть цикл for . Но это не цикл со счетчиком. В Питоне он предназначен для перебора элементов последовательностей и других сложных объектов. Данный цикл и последовательности будут изучены в последующих уроках.
Для while наличие счетчика не обязательно. Представим, что надо вводить числа, пока переменная total больше нуля. Тогда код будет выглядеть так:
total = 100 while total > 0: n = int(input()) total = total - n print("Ресурс исчерпан")
Сколько раз здесь выполнится цикл? Неизвестно, все зависит от вводимых значений. Поэтому у цикла со счетчиком известно количество итераций, а у цикла без счетчика – нет.
Самое главное для цикла while – чтобы в его теле происходили изменения значений переменных, которые проверяются в его заголовке, и чтобы хоть когда-нибудь наступил случай, когда логическое выражение в заголовке возвращает False . Иначе произойдет зацикливание.
Примечание 1. Не обязательно в выражениях total = total — n и i = i + 1 повторять одну и ту же переменную. В Python допустим сокращенный способ записи подобных выражений: total -= n и i += 1 .
Примечание 2. При использовании счетчика он не обязательно должен увеличиваться на единицу, а может изменяться в любую сторону на любое значение. Например, если надо вывести числа кратные пяти от 100 до 0, то изменение счетчика будет таким i = i — 5 , или i -= 5 .
Примечание 3. Для счетчика не обязательно использовать переменную с идентификатором i . Можно назвать переменную-счетчик как угодно. Однако так принято в программировании, что счетчики обозначают именами i и j (иногда одновременно требуются два счетчика).
Практическая работа
- Измените последний код из урока так, чтобы переменная total не могла уйти в минус. Например, после предыдущих вычитаний ее значение стало равным 25. Пользователь вводит число 30. Однако программа не выполняет вычитание, а выводит сообщение о недопустимости операции, после чего осуществляет выход из цикла.
- Используя цикл while , выведите на экран для числа 2 его степени от 0 до 20. Возведение в степень в Python обозначается как ** . Фрагмент вывода:
. 32 64 128 256 512 1024 .
Примеры решения и дополнительные уроки в pdf-версии курса
X Скрыть Наверх
Python. Введение в программирование
Управляющие структуры
Простое выражение в C++ — это каждая из отдельных инструкций программы, таких как объявление переменной или одно из выражений, рассмотренных в предыдущих разделах. Они всегда завершаются точкой с запятой (;) и выполняются в том же порядке, в котором они представлены в программе.
Но программы не ограничиваются линейной последовательностью выражений. Во время выполнения программа может повторять сегменты кода или принимать решения, и разветвляться. Для этих целей C++ предоставляет выражения для управления потоком исполнения, которые служат для указания, что наша программа должна сделать, когда и при каких обстоятельствах.
Многие из выражений управления потоком, освещенных в этом разделе требуют определенных (под)выражений как части синтаксиса. Эти выражения могут быть простыми выражениями C++, такими как одиночная инструкция, отделенная точкой с запятой (;), или составными выражениями. Составное выражение это группа выражений (каждое их них отделяется точкой с запятой), сгруппированных вместе в блок, заключенный в фигурные скобки: <>:
Весь блок рассматривается как одно выражение (состоящее из множества подвыражений). Выражение, являющееся частью синтаксиса выражения управления потоком, может быть как простым, так и составным.
Операторы выбора: if и else
Ключевое слово if используется для выполнения оператора или блока, если и только если выполняется условие. Его синтаксис:
if (condition) statement;
Здесь condition является вычисляемым выражением. Если condition равно true, выполняется выражение statement. Если же оно равно false, то statement не выполняется (просто игнорируется), и программа продолжает выполнение сразу после условного оператора. Например, следующий фрагмент кода печатает сообщение (x is 100), только если значение, хранимое в переменной x, действительно 100:
if (x == 100) cout
Если x не равен точно 100, это выражение игнорируется, и ничего не печатается.
Если необходимо исполнить более одного выражения при выполнении условия, эти выражения должны быть заключены в фигурные скобки (<>), формируя блок:
if (x == 100)
Обычно отступы и переносы строки в коде не имеют никакого эффекта, так что этот код эквивалентен следующему:
if (x == 100)
Операторы выбора с if также могут указывать, что происходит, когда условие не выполняется, используя ключевое слово else для введения альтернативного выражения. Его синтаксис:
if (condition) statement1 else statement2;
где statement1 выполняется в случае, если условие имеет значение true, а в случае, если это не так, выполняется statement2.
if (x == 100) cout
Этот фрагмент напечатает x is 100, если x действительно имеет значение 100, но если это не так (и только в этом случае), этот фрагмент кода напечатает x is not 100. Несколько структур if + else могут быть объединены с целью проверки диапазона значений.
if (x > 0) cout
Этот фрагмент напечатает x положителен, отрицателен или равен 0 путем объединения двух структур if-else. Также возможно выполнить более одного выражения на каждый случай, группируя их в блоки, заключенные в фигурные скобки: <>.
Итерационные операторы (циклы)
Циклы повторяю выражение определенное количество раз, или до тех пор, пока не будет выполнено условие. Они представлены ключевыми словами while, do и for.
Цикл while
Простейшая разновидность циклов это цикл while. Его синтаксис:
while (expression) statement
Цикл while просто повторяет выражение statement до тех пор, пока выражение expression истинно. Если после какого-либо выполнения выражения statement выражение expression станет ложно, цикл завершится, и программа продожит исполнение непосредственно после цикла. Например, рассмотрим обратный отсчет с использованием цикла while:
// пользовательский обратный отсчет // с использованием while #include using namespace std; int main () < int n = 10; while (n>0) < cout cout
10, 9, 8, 7, 6, 5, 4, 3, 2, 1, liftoff!
Первое выражение в main устанавливает n в значение 10. Это первое число для счетчика. Затем начинается цикл while: если это значение удовлетворяет условию n>0 (т.е. n больше нуля), то блок, который следует за условием, выполняется, и повторяется, пока условие (n>0) остается истинно.
Весь процесс этой программы может быть интерпретирован, согласно следующему скрипту (начиная с main):
- Присваивается значение n
- Проверяется условие цикла while (n>0). В этом месте есть два пути:
- условие истинно: выражение исполняется (шаг 3)
- условие ложно: выражение игнорируется и выполнение продолжается после него (шаг 5)
- Выполнение выражения:
cout
При использовании цикла while следует учитывать, что цикл должен заканчиваться в некоторой точке, и поэтому выражение должно изменять каким-то образом значения, проверяемые в условии, чтобы сделать условие ложным в какой-то момент. Иначе, цикл будет продолжать повторяться бесконечно. В нашем случае, цикл содержит --n, что уменьшает значение переменной, которая проверяется в условии (n), на единицу, что в конечном счете делает условие (n>0) ложным, после определенного числа итераций цикла. Чтобы быть более конкретным, после 10 итераций, n будет иметь значение 0, что делает условие ложным и завершает цикл while.
Обратите внимание, что сложность этого цикла незначительна для компьютера, и поэтому весь обратный отсчет выполняется мгновенно, без какой-либо существенной задержки между итерациями цикла (если интересно, см. sleep_for: пример обратного отсчета с задержками).
Цикл do-while
Очень похожий цикл - цикл do-while, синтаксис которого:
do statement while (condition);
Он ведет себя как цикл while, за исключением того, что условие condition вычисляется после выполнения выражения statement, а не перед ним, гарантируя хотя бы однократное выполнение выражения statement, даже если условие condition никогда не выполнится. Например, следующая программа-пример повторяет любой текст, который вводит пользователь, пока пользователь не введет goodbye:
// echo machine #include #include using namespace std; int main () < string str; do < cout while (str != «goodbye»); >
Enter text: hello You entered: hello Enter text: who’s there? You entered: who’s there? Enter text: goodbye You entered: goodbye
Цикл do-while обычно предпочтительнее цикла while, когда выражение statement должно быть выполнено хотя бы один раз, например, когда условие, которое проверяется до конца цикла, определяется внутри самого оператора цикла. В предыдущем примере пользовательский ввод в блоке определяет, завершится ли цикл. И, таким образом, даже если пользователь хочет завершить цикл как можно скорее, введя goodbye, блок в цикле должен быть выполнен по крайней мере один раз, чтобы запросить ввод, и условие может быть определено только после выполнения блока.
Цикл for
Цикл for создан для повторения определенного количества раз. Его синтаксис:
for (initialization; condition; increase) statement;
Подобно циклу while, этот цикл повторяет выражение statement до тех пор, пока условие condition истинно. Но, в дополнение, цикл for предоставляет конкретные места для инициализации и прироста (increase) выражения, выполняемого перед тем, как цикл произведет первую итерацию, и после каждой итерации, соответственно. Поэтому особенно полезно использовать переменные счетчика в качестве условия condition.
Это работает следующим образом:
- выполняется инициализация. Обычно здесь объявляется переменная-счетчик, и ей задается какое-то начальное значение. Это выполняется единственный раз, в начале цикла.
- проверяется условие condition. Если оно истинно, цикл продолжается; иначе, цикл заканчивается, пропуская выражение statement и переходя к шагу 5.
- выполняется выражение statement. Как обычно, оно может быть как единичным оператором, так и блоком операторов, заключенных в фигурные скобки <>.
- выполняется прирост increase, и цикл возвращается к шагу 2.
- цикл заканчивается: выполнение программы продолжается с опреатора, следующего за циклом.
Вот пример обратного отсчета с использованием цикла for:
// обратный отсчет // с использованием // цикла for #include using namespace std; int main () < for (int n=10; n>0; n--) < cout cout
10, 9, 8, 7, 6, 5, 4, 3, 2, 1, liftoff!
Три поля в цикле for являются опциональныи. Они могут быть оставлены пустыми, но в любом случае требуются точки с запятой между ними. Например, for (;n<10;) - это цикл без инициализации или приращения (эквивалент цикла while); for (;n<10;++n) - это цикл с приращением, но без инициализации (возможно, потому что переменная уже была инициализирована перед циклом). Цикл без условия condition является эквивалентом цикла с true вместо условия (т.е. бесконечного цикла).
Поскольку каждое из полей выполняется в определенный момент исполнения цикла, может быть полезно выполнить более одного выражения на месте любого из полей initialization, condition, или statement. К сожалению, это не операторы, а простые выражения, и поэтому их нельзя заменить блоком. Однако в качестве выражений они могут использовать оператор запятая (,): этот оператор является разделителем выражений и может разделять несколько выражений, где обычно ожидается только одно. Например, используя его, цикл for мог бы обрабатывать две переменные счетчика, инициализируя и увеличивая обе:
for ( n=0, i=100 ; n!=i ; ++n, --i ) < // здесь что угодно. >
Этот цикл будет выполнен 50 раз, если ни n, ни i не будут изменены в цикле:

n начинается со значения 0, а i со 100, условие n ! = i (то есть, что n не равно i ). Поскольку n увеличивается на единицу, а i уменьшается на единицу в каждой итерации, условие цикла станет ложным после 50-й итерации, когда n и i станут равны 50.
Range-based for. Цикл на основе диапазона.
Цикл for имеет другой синтаксис, который используется исключительно с диапазонами значений:
for ( declaration : range ) statement;
Этот вид цикла for перебирает все элементы в диапазоне range, где declaration объявляет некоторую пременную, способную принимать значение элемента этого диапазона. Диапазоны — это последовательности элементов, включая массивы, контейнеры и любой другой тип, поддерживающий функции begin и end; большинство из этих типов еще не были представлены в этом руководстве, но мы уже знакомы по крайней мере с одним видом диапазона: строками, которые являются последовательностями символов.
Пример такого цикла с использованием строк:
// range-based for #include #include using namespace std; int main () < string str ; for (char c : str) < cout cout
[H][e][l][l][o][!]
Обратите внимание, что перед двоеточием (:) в цикле for находится объявление переменной типа char (элементы в строке имеют тип char). Затем мы используем эту переменную, c, в блоке операторов для представления значения каждого из элементов в диапазоне.
Этот цикл является автоматическим и не требует явного объявления какой-либо переменной-счетчика.
Циклы на основе диапазона обычно также используют выведение типов для типов элементов с auto. Как правило, вышеприведенный цикл на основе диапазона также может быть записан как:
for (auto c : str) cout
Здесь тип переменной c автоматически определяется как тип элементов, содержащихся в str.
Операторы перехода (jump)
Операторы перехода позволяют изменять течение программы, выполняя переходы в определенные места.
Оператор break
break завершает цикл, даже если условие его завершения не выполнено. Его можно использовать для завершения бесконечного цикла или для принудительного завершения цикла до его нормального завершения. Например, давайте остановим обратный отсчет до его нормального завершения:
// пример завершения цикла #include using namespace std; int main () < for (int n=10; n>0; n--) < cout > >
10, 9, 8, 7, 6, 5, 4, 3, countdown aborted!
Оператор continue
Оператор continue заставляет программу пропустить остаток цикла в текущей итерации, как будто достигнут конец блока операторов, перейдя к началу следующей итерации. Например, давайте пропустим номер 5 в нашем обратном отсчете:
Оператор goto
goto позволяет совершить абсолютный переход к другой точке программы. Этот безусловный переход игнорирует уровни вложенности и не вызывает автоматического раскручивания стека. Следовательно, это особенность, которую следует использовать с осторожностью, и предпочтительно в пределах одного блока операторов, особенно при наличии локальных переменных.
Точка назначения идентифицируется меткой (label), которая затем используется в качестве аргумента для оператора goto. Метка состоит из корректного идентификатора, за которым следует двоеточие (:).
goto, как правило, считается низкоуровневой операцией без каких-либо случаев использования в современных парадигмах программирования более высокого уровня, обычно используемых в C++. Но, в качестве примера, вот версия нашего цикла обратного отсчета с использованием goto:
// пример цикла // с оператором continue #include using namespace std; int main () < for (int n=10; n>0; n--) < if (n==5) continue; cout cout
10, 9, 8, 7, 6, 4, 3, 2, 1, liftoff!
Оператор выбора: switch
Синтаксис оператора switch немного своеобразен. Его целью является проверка значения среди ряда возможных константных выражений. Это похоже на объединение операторов if-else, но ограничено константными выражениями. Его наиболее типичный синтаксис:
switch (expression)
case constant1:
group-of-statements-1;
break;
case constant2:
group-of-statements-2;
break;
.
.
.
default:
default-group-of-statements
>
Это работает следующим образом: switch вычисляет выражение expression и проверяет, эквивалентно ли оно значению constant1; если это так, выполняет group-of-statements-1, пока не найдет оператор break. Когда он находит оператор break, программа переходит к концу всего оператора switch (закрывающая фигурная скобка).
Если выражение не равно constant1, тогда проверяется constant2. Если выражение равно constant2, выполняется group-of-statements-2, до тех пор, пока не будет найден оператор break, после чего будет совершен переход к концу оператора switch.
Наконец, если значение выражения не соответствует ни одной из ранее указанных констант (их может быть любое количество), программа выполняет операторы, включенные после метки default:, если она существует (так как она необязательна).
Оба следующих фрагмента кода имеют одинаковое поведение, демонстрируя эквивалентность операторов if-else и switch:
| switch example | if-else equivalent |
| switch (x) case 1: cout break; case 2: cout break; default: cout > |
if (x == 1) cout > else if (x == 2) cout > else cout > |
Оператор switch имеет несколько своеобразный синтаксис, унаследованный с ранних времен первых компиляторов Си, потому что он использует метки вместо блоков. В наиболее типичном использовании (показано выше), это означает, что операторы break необходимы после каждой группы операторов для определенной метки. Если break отсутствует, все операторы, следующие за case (включая те, которые находятся под любыми другими метками) также выполняются до тех пор, пока не будет достигнут конец блока switch или оператор перехода (такой как break).
Если в приведенном выше примере будет отсутствовать оператор break после первой группы для первого случая, программа не будет автоматически переходить к концу блока switch после того, как напечатает x is 1, а вместо этого начнет выполнять операторы для case 2 (т.е. напечатает также x is 2). Это будет продолжаться до тех пор, пока не встретится оператор break или конец блока switch. Это делает излишним заключать операторы для каждого случая в фигурные скобки <>, а также может быть полезно для выполнения одной и той же группы операторов для разных возможных значений. Например:
switch (x)
Обратите внимание, что оператор switch ограничен в сравнении оцениваемого выражения метками. являющимися константными выражениями. В качестве меток невозможно использовать переменные или диапазоны значений, потому что они не являются допустимыми константами C++.
Для проверки диапазонов или значений, не являющихся константами, лучше использовать группу операторов if и else if.
Информатика
Какое значение будет у переменной i после выполнения фрагмента программы?
i = 0 while i 10: i = i + 1 if i > 7: i = i + 2Ответ: 135 шагСколько итераций цикла будет выполнено в этом фрагменте программы?i = 0 while i 10: i = i + 1 if i > 7: i = i + 2Ответ: 99 шагСколько всего знаков * будет выведено после исполнения фрагмента программы:i = 0 while i < 5: print('*') if i % 2 == 0: print('**') if i > 2: print('***') i = i + 1Ответ: 17Сколько итераций цикла будет выполнено в этом фрагменте программы i 0 while i 10 i i 1 if i 7 i i 2
Скачай курс
в приложенииПерейти в приложение
Открыть мобильную версию сайта© 2013 — 2023. Stepik
Наши условия использования и конфиденциальности
Public user contributions licensed under cc-wiki license with attribution required



