Циклы

Последнее обновление: 22.02.2023

Циклы позволяют выполняет некоторый набор инструкций множество раз, пока соблюдается определенное условие. В языке C++ имеются следующие виды циклов:

  • for

  • while

  • do...while

Цикл 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 (инициализатор; условие; итерация)
{
    // тело цикла
}
  • инициализатор выполняется один раз при начале выполнения цикла и представляет установку начальных условий, как правило, это инициализация счетчиков - специальных переменных, которые используются для контроля за циклом.

  • условие представляет условие, при соблюдении которого выполняется цикл. Как правило, в качестве условия используется операция сравнения, и если она возвращает ненулевое значение (то есть условие истинно), то выполняется тело цикла, а затем выполняется итерация.

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

Например, перепишем программу по выводу квадратов чисел с помощью цикла 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-each

Существует также особая форма цикла 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

В цикле 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

Можно определять вложенные циклы. Например, выведем таблицу умножения с помощью вложенного цикла 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

Операторы continue и break

Иногда возникает необходимость выйти из цикла до его завершения. В этом случае можно воспользоваться оператором 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;   
    }
}
Дополнительные материалы
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850