Циклы позволяют выполняет некоторый набор инструкций множество раз, пока соблюдается определенное условие. В языке C++ имеются следующие виды циклов:
for
while
do...while
Цикл while
выполняет некоторый код, пока его условие истинно, то есть возвращает true. Он имеет следующее формальное определение:
while(условие) { // выполняемые действия }
После ключевого слова while в скобках идет условное выражение, которое возвращает true или false. Затем в фигурных скобках идет набор инструкций, которые составляют тело цикла. И пока условие возвращает true, будут выполняться инструкции в теле цикла.
Например, выведем квадраты чисел от 1 до 9:
#include <iostream> int main() { int i {1}; while(i < 10) { std::cout << i << " * " << i << " = " << i * i << std::endl; i++; } }
Здесь пока условие i < 10
истинно, будет выполняться цикл while, в котором выводится на консоль
квадрат числа и инкрементируется переменная i. В какой-то момент переменная i увеличится до 10, условие i < 10
возвратит false, и цикл завершится.
Консольный вывод программы:
1 * 1 = 1 2 * 2 = 4 3 * 3 = 9 4 * 4 = 16 5 * 5 = 25 6 * 6 = 36 7 * 7 = 49 8 * 8 = 64 9 * 9 = 81
Каждый отдельный проход цикла называется итерацией. То есть в примере выше было 9 итераций.
Если цикл содержит одну инструкцию, то фигурные скобки можно опустить:
int i {}; while(++i < 10) std::cout << i << " * " << i << " = " << i * i << std::endl;
Цикл for имеет следующее формальное определение:
for (инициализатор; условие; итерация) { // тело цикла }
инициализатор выполняется один раз при начале выполнения цикла и представляет установку начальных условий, как правило, это инициализация счетчиков - специальных переменных, которые используются для контроля за циклом.
условие представляет условие, при соблюдении которого выполняется цикл. Как правило, в качестве условия используется операция сравнения, и если она
возвращает ненулевое значение (то есть условие истинно), то выполняется тело цикла, а затем выполняется итерация
.
итерация выполняется после каждого завершения блока цикла и задает изменение параметров цикла. Обычно здесь происходит увеличение счетчиков цикла.
Например, перепишем программу по выводу квадратов чисел с помощью цикла for:
#include <iostream> int main() { for(int i {1}; i < 10; i++) { std::cout << i << " * " << i << " = " << i * i << std::endl; } }
Первая часть объявления цикла - int i {1}
- создает и инициализирует счетчик i. Фактически это то же самое, что и
объявление и инициализация переменной. Счетчик необязательно должен представлять тип
int. Это может быть и другой числовой тип, например, float. И перед выполнением цикла его значение будет равно 1.
Вторая часть - условие, при котором будет выполняться цикл. В данном случае цикл будет выполняться, пока переменная i не станет равна 10.
И третья часть - приращение счетчика на единицу. Опять же нам необязательно увеличивать на единицу. Можно уменьшать: i--. Можно изменять на другое значение: i+=2.
В итоге блок цикла сработает 9 раз, пока переменная i не станет равна 10. И каждый раз это значение будет увеличиваться на 1. И по сути мы получим тот же самый результат, что и в случае с циклом while:
1 * 1 = 1 2 * 2 = 4 3 * 3 = 9 4 * 4 = 16 5 * 5 = 25 6 * 6 = 36 7 * 7 = 49 8 * 8 = 64 9 * 9 = 81
Необязательно указывать все три выражения в определении цикла, мы можем одно или даже все из них опустить:
int i {1}; for(; i < 10;) { std::cout << i << " * " << i << " = " << i * i << std::endl; i++; }
Формально определение цикла осталось тем же, только теперь первое и третье выражения в определении цикла отсутствуют:
for (; i < 10;)
. Переменная-счетчик определена и инициализирована вне цикла, а ее приращение происходит в самом цикле.
Также цикл не обязательно должен содержать тело. Например, вычислим с помощью цикла сумму чисел от 1 до 5:
#include <iostream> int main() { int sum {}; for (unsigned i {}; i < 6; sum += i++); std::cout << "Sum: " << sum << std::endl; // Sum: 15 }
Здесь для хранения суммы чисел определена переменная sum
, которая по умолчанию равна 0. В цикле определяем переменную-счетчик i и выполняем цикл, пока i не станет равна 6.
Обратите внимание на третью часть определения цикла - sum += i++
. Здесь мы прибавляем к переменной sum значение переменной i и потом увеличиваем значение i. Таким образом, мы
нашли сумму чисел, но при этом обошлись без тела цикла.
Выражение инициализации может определять больше одной переменной. Например, определим две переменных и выведем на консоль их произведение:
#include <iostream> int main() { int numbers[]{1, 2, 3, 4}; int sum {}; for (int i {1}, j {5}; i < 6 && j < 10; i++, j++) { std::cout << i << "*" << j << "="<< i * j << std::endl; // Sum: 15 } }
Здесь цикл отрабатывает, пока либо переменная i не станет равна 6, либо пока переменная j не станет равна 10. Консольный вывод:
1*5=5 2*6=12 3*7=21 4*8=32 5*9=45
Существует также особая форма цикла for, которая предназначена специально для работы с последовательностями значений. Эта форма имеет следующее формальное определение:
for(тип переменная : последовательность) { инструкции; }
Например:
#include <iostream> int main() { for (int n : {2, 3, 4, 5}) { std::cout << n << std::endl; } }
Здесь выражение {2, 3, 4, 5}
как раз представляет последовательность значений - чисел int. Цикл перебирает всю эту последовательность и помещает каждое значение в
переменную n
, значение которой выводится на консоль.
Другой пример. Строка фактически представляет собой последовательность символов, которую также можно перебрать с помощью данной вида циклов:
#include <iostream> int main() { for (char c : "Hello") { std::cout << c << std::endl; } }
Здесь каждый символ строки помещается в переменную c, значение которой затем выводится на консоль.
В дальнейшем мы рассмотрим различные виды последовательности, которые можно перебирать с помощью данного вида циклов.
В цикле do сначала выполняется код цикла, а потом происходит проверка условия в инструкции while. И пока это условие истинно, то есть не равно 0, то цикл повторяется. Формальное определение цикла:
do { инструкции } while(условие);
Например:
#include <iostream> int main() { int i {6}; do { std::cout << i << std::endl; i--; } while(i>0); }
Здесь код цикла сработает 6 раз, пока i не станет равным нулю.
Но важно отметить, что цикл do гарантирует хотя бы однократное выполнение действий, даже если условие в инструкции while не будет истинно. То есть мы можем написать:
int i {-1}; do { std::cout << i << std::endl; i--; } while(i>0); }
Хотя у нас переменная i меньше 0, цикл все равно один раз выполнится.
Рассмотрим еще пример. В ряде консольных программ также реализован подобный цикл, который срабатывает, пока пользователь не введет какой-либо символ. Допустим, пользователь вводит числа, и программа должна вычислить среднее арифметическое чисел. И пусть пользователь может ввести неопределенное количество чисел, а если он захочет завершить ввод чисел, пусть введет символ "y" или "Y":
#include <iostream> int main() { char reply {}; // ответ пользователя int count {}; // количество введенных чисел double number {}; // для ввода числа double total {}; // общая сумма чисел do { std::cout << "Enter a number: "; std::cin >> number; // Вводим число total += number; // прибавляем к совокупному числу ++count; // увеличиваем количество введенных чисел на 1 std::cout << "Finish? (y/n): "; std::cin >> reply; // считываем ответ пользователя } while (reply != 'y' && reply != 'Y'); // пока пользователь не введет символ y и Y std::cout << "The average value is " << total/count << std::endl; }
В данном случае считываем каждое число в переменную number, а затем прибавляем ее к переменной total, попутно увеличиваем счетчик чисел - count. После каждого ввода также ожидаем еще один ввод - если пользователь введет "y" или "Y", завершаем цикл и выводим среднее арифметическое чисел. Пример работы программы:
Enter a number: 6 Finish? (y/n): n Enter a number: 5 Finish? (y/n): y The average value is 5.5
Можно определять вложенные циклы. Например, выведем таблицу умножения с помощью вложенного цикла for
:
#include <iostream> int main() { for (int i {1}; i < 10; i++) { for(int j {1}; j < 10; j++) { std::cout << i * j << "\t"; } std::cout << std::endl; } }
1 2 3 4 5 6 7 8 9 2 4 6 8 10 12 14 16 18 3 6 9 12 15 18 21 24 27 4 8 12 16 20 24 28 32 36 5 10 15 20 25 30 35 40 45 6 12 18 24 30 36 42 48 54 7 14 21 28 35 42 49 56 63 8 16 24 32 40 48 56 64 72 9 18 27 36 45 54 63 72 81
Иногда возникает необходимость выйти из цикла до его завершения. В этом случае можно воспользоваться оператором break. Например, нам надо подсчитать сумму чисел от 1 до 9, пока она не станет больше 20:
#include <iostream> int main() { int result{}; for(int i{1}; i < 10; i++) { result += i; std::cout << result << std::endl; if(result > 20) break; } }
Здесь когда значение переменной result станет больше 20 (то есть когда i будет равно 6), осуществляется выход из цикла с помощью оператора break:
1 3 6 10 15 21
В отличие от оператора break
, оператор continue производит переход к следующей итерации. Например, нам надо посчитать сумму только нечетных чисел из некоторого диапазона:
#include <iostream> int main() { int result {}; for (int i {1}; i<10; i++) { if (i % 2 == 0) continue; result +=i; } std::cout << "result = " << result << std::endl; // result = 25 }
Чтобы узнать, четное ли число, мы получаем остаток от целочисленного деления на 2, и если он равен 0, то с помощью оператора continue переходим к следующей итерации цикла. А если число нечетное, то складываем его с остальными нечетными числами.
Иногда необходимо, чтобы цикл выполнялся бесконечно. Например, когда нам надо бесконечно отслеживать изменения каких-то значений или когда мы точно не знаем, сколько итераций циклу предстоит сделать. Бесконечные циклы находят широкое применение в различных областях, например, в графических программах, играх, сетевых программах и т.д. Для создания бесконечного цикла можно использовать любой вид циклов, но во всех случаях условие всегда истинно:
// бесконечный цикл for - условие завершения отсутствует for (;;) { } // бесконечный цикл while - условие всегда равно true while (true) { } // бесконечный цикл do-while - условие всегда равно true do { } while (true);
Однако в этих случаях в зависимости от ситуации все равно может быть какое-то условие, при котором цикл может завершить работу. В этом случае для выхода из цикла может применяться оператор break. Например, пусть пользователь бесконечно может вводить числа, а программа выводит ему квадрат числа. Но если пользователь ввел 0, то выполним выход из цикла:
#include <iostream> int main() { int n {}; // для ввода числа // бесконечный цикл while(true) { std::cout << "Enter a number: "; std::cin >> n; // Вводим число // если пользователь ввел 0, то выходим из цикла if(n == 0) break; // иначе выводим квадрат числа std::cout << n * n << std::endl; } }