Циклы нам нужны для того, чтобы осуществить повторное выполнение действий. Сила операторов циклов в том, что мы можем задавать количество выполнений с помощью переменных, что означает, что программа может гибко адаптироваться к внешним условиям.
Понятие цикла близко к понятию рекурсивной функции. И вправду многие циклы мы можем выразительно представить через рекурсию и рекуррентные отношения. Но цикл сам по себе более императивная вещь, которая буквально пытается представить алгоритм.
В C# мы имеем несколько операторов для представления циклов:
- while, do-while – нужны для повторения некоторых действий без четкого понимания, сколько действий потребуется. Есть только условие продолжения;
- for – нужен для циклов у которого заранее известно сколько итераций (выполнений) нам нужно сделать;
- foreach – более высокоуровневый цикл, который является встроенным в C# оператором для работы с некой сущностью “итератор”. При работе с ним мы перебираем некое множество элементов. Его мы рассмотрим в разделе с массивами и интерфейсом IEnumerable. ;
while
Простейший цикл, внешне схож с оператором if, но имеет другую семантику.
У него также есть условие и тело. Только в отличие от оператора if мы немного по-другому управляем программой. В случае с оператором if мы имеем условие и тело, которое выполняется, если условие верное. Далее в любом случае выполняются операторы после оператора if. А с циклом while есть одно интересное дополнение. Если условие верно, то после выполнения тела, мы опять возвращаемся к условию, если условие все еще верно то всё повторяется.
Цикл мог бы быть бесполезным, но внутри его тела мы можем изменить обстоятельства таким образом, чтобы условие перестало быть верным и мы бы проследовали дальше. Чаще всего в условие мы используем переменную или вызов метода, состояние объекта которого может изменяться во время итераций.
Фрагмент 1.8
int secretNumber = 250;
int userInput = 0;
while(userInput != secretNumber)
{
Console.WriteLine("Введите секретное число:");
userInput = Convert.ToInt32(Console.ReadLine());
}
Console.WriteLine("Вы ввели правильное секретное число!!!");
Если заменить в этом примере while на if, то программа скомпилируется и будет работать. Только у пользователя будет одна попытка ввести секретное число. И в любом случае программа выведет, что число было правильным. ¯\_(ツ)_/¯
for
Любой цикл можно описать с помощью цикла while. Даже цикл foreach в процессе трансляции преобразуется в цикл while. Но как было и с оператором goto, нам недостаточно только возможности. Нам нужен ещё и удобный уровень абстракции и специализированные инструменты.
Одним из таких инструментов является цикл for. Он невероятно удобен при итерировании (переборе) массивов, а также выполнении операций, число которых можно описать.
Его синтаксис выражает три основных блока, которые присущи подобным циклам:
- Инициализация счётчика;
- Условие;
- Изменение состояния (обычно инкремент);
Эти блоки мы перечисляем внутри круглых скобок оператора for через точку с запятой. Мы также вполне можем оставить этот блок пустым. Выполняются они в таком порядке:
- Инициализация;
- Условие, если верное, идём на шаг 3, если не верное уходим от оператора for;
- Тело цикла;
- Изменение состояния ;
- Переход на шаг 2;
Фрагмент 1.9
int userAge = 0;
for(int i = 0; i < userAge; i++)
{
Console.WriteLine("Happy birthday!");
}
Данная программа поздравляет пользователя с днём рождения столько раз, сколько ему лет.
Вырожденные операторы
Бывают ситуации которые стоит избегать. Например когда тело оператора вырождается, это часто бывает с оператором while.
Бывает такой код некоторые пытаются уместить в одну строку.
int number = 2;
int delimeter = 2;
while(number % delimeter++ == 0) ;
Console.WriteLine(delimeter);
Данный алгоритм ищет ближайший делитель числа без остатка.
Записывать это в одну строку нет смысла только если вы не хотите запутать читателя или показать свой навык владения синтаксисом. Правильно будет так:
int number = 2;
int delimeter = 2;
while(number % delimeter == 0)
{
delimeter++;
}
Console.WriteLine(delimeter);
Отдельно условие, отдельно действие.