"Десять негритят купались в Черном море..."
Детская считалочка.
Повторение - мать учения.
Мы создаем программы, чтобы они выполняли за нас какую-то работу. И естественно, чем больше автоматизации в них будет присутствовать, тем лучше для нас. В идеале - хорошо бы чтобы программы сами себя писали, компилировали и запускали на выполнение. А нам тогда останется только - хмм,.. пить пиво? Но это совсем другая история, имеющая мало отношения к человеку разумному (Homo Sapiens Sapiens), к которым мы с вами относимся.
Однако, автоматизация - это очень хорошо. Особенно, автоматизация однотипных, повторяющихся действий. Ведь одна из задач создания программ - иметь возможность просто запустить уже готовую программу, когда нам нужно что-то сделать. Сделать что-то, для чего эта программа предназначена. Здесь мы сразу замечаем, что абсолютно универсальных программ, которые могли бы делать вообще все или очень многое - просто не существует. В частности, потому что такая программа будет бесконечно большой и, как следствие, бесконечно медленной, а еще в ней было бы огромное количество ошибок... Поэтому гораздо рациональнее создавать небольшие специализированные программы, выполняющие конкретные задачи, но делающие это эффективно и быстро.
То есть, для того, чтобы решить какую-то конкретную задачу, для которой существует программа, мы просто её запустим. А если такая же задача встретится нам еще раз, мы снова запустим ту же самую программу. И так - при каждом возникновении такой задачи. Получается, что мы повторяем один и тот же алгоритм всегда, конда возникает необходимость. Давайте представим себе алгоритм с орехами из урока №2 "Алгоритмы и программы" и перенесем его на конвейер с орехами: у нас постоянно поступают орехи, которые нам необходимо колоть. Получается, для этого нам необходимо каждый раз повторять одну и ту же последовательность операций: сам алгоритм колки одного ореха.
Простейший цикл
Точно так же и в пределах одного алгоритма у нас может возникнуть необходимость повторять какое-то количество команд. И более того, такая необходимость возникает в программах постоянно. Веди в дискретном цифровом мире очень многое повторяется. И эти повторения надо как-то обрабатывать. Разумеется, самый простой способ обработки - это создание в языке программирования специальных конструкций, отвечающих за управляемое повторение блоков кода. Такие конструкции называются циклами или операторами (командами) циклов.
Самый простой цикл - бесконечный. В таком цикле блок кода будет выполняться всегда (или пока запущена программа, или пока включен компьютер). Сточки зрения программирования это - самая простая конструкция (из всех циклов), потому что она вообще не требует настройки: достаточно только указать начало и конец блока операторов, которые надо повторять.
Например, в языке Scratch для реализации такого цикла имеется специальный оператор
Вот пример его применения:
Обратите внимание, что внутри П-образной рыжей скобки, обозначающей оператор цикла, располагаются другие команды (синего цвета), которые и будут постоянно повторяться во время работы цикла при запуске программы. Эти команды называются телом цикла.
Блок-схема алгоритма программы с бесконечным циклом может выглядеть следующим образом:
Однако, в других языках специального оператора для бесконечного цикла обычно не существует. Но его можно легко организовать с помощью других операторов цикла.
Также, его можно легко реализовать с помощью известного нам оператора GoTo. Вот пример такой реализации на языке MS Small Basic:
Start: ' Метка начала цикла
TextWindow.WriteLine("Эта строка будет повторяться всегда!") ' Тело цикла
Goto Start ' Переход на начало цикла
А вот пример той же самой программы на языке С:
1 2 3 4 5 6 7 8 |
#include "stdio.h" int main(void) { start: // Метка начала цикла printf("Эта строка будет повторяться всегда!\n"); // Тело цикла a>>>b A&B A && B <> goto start; // Переход на начало цикла } |
Эти программы делают одно и то же: Бесконечно выводят на экран (в консоль) строку текста "Эта строка будет повторяться всегда!". Разумеется, толку от такой программы немного. Однако, мы сейчас написали программу, которая никогда не заканчивается, если не прервать её выполнение снаружи - из операционной системы (например, в Windows - через Диспетчер Задач).
Но, как правило, при работе программ нужны бывают не бесконечные циклы, а циклы, ограниченные числом повторений или каким-то условием.
Циклы со счетчиком
Самый простой цикл такого вида - это цикл типа повторять N раз. В языке Scratch для реализации такого цикла имеется специальный оператор
Однако, в большинстве других языков и такого оператора нет. Для всех подобных задач используется более стандартный и универсальный цикл со счетчиком типа For (что очень часто переводят как "Для" - что, к сожалению, никак не отражает сути работы данного оператора).
Стандартный формат оператора цикла For предполагает наличие трех параметров, управляющих работой этого цикла:
- Начальное значение переменной цикла
- Конечное значение переменной цикла
- Шаг изменения переменной цикла
Алгоритм работы такого цикла довольно прост и понятен
- При входе в цикл Счетчик цикла имеет Начальное значение;
- После каждого выполнения тела цикла Счетчик увеличивается на значение Шага;
- Это продолжается до тех пор, пока текущее значение Счетчика не превысит Конечное значение;
- После чего цикл завершается и программа выполняется дальше.
В некоторых языках программирования все три параметра в этом цикле могут быть опущены, что приводит нас к простому бесконечному циклу. Так как считать нечего - значит будем повторять всегда.
1 2 3 4 5 6 7 8 9 |
#include "stdio.h" int main(void) { for(;;) // здесь в цикле со счетчиком отсутствуют все параметры { printf("Эта строка будет повторяться всегда!\n"); // Тело цикла } } |
Однако, стоит нам добавить начальное и конечное значение переменной цикла, как мы сразу получим полноценный цикл со счетчиком. Вот пример на языке MS Smallbasic:
For i = 1 To 5 ' начальное значение = 1, конечное = 5, шаг - не указан, поэтому по умолчанию равен 1
TextWindow.WriteLine("Счетчик цикла = " + i) ' на каждом шаге мы выводим в консоль значение счетчика цикла
EndFor ' конец блока цикла
В некоторых языках, например, в C, C++ и т.п. для этого потребуется определить также и значение шага цикла.
1 2 3 4 5 6 7 8 9 10 11 12 |
#include "stdio.h" int main(void) { for(int i = 1; i <= 5; i = i + 1) // здесь в цикле со счетчиком (переменной i) указаны все параметры // i = 1 - задано начальное значение, равное 1 // i <= 5 - задано конечное значение, в данном случае - в виде условия: i не может быть больше 5 // i = i + 1 - задан шаг, в данном случае - в виде формулы изменения переменной цикла: при каждом проходе i будет увеличиваться на 1 { printf("Счетчик цикла = %d\n", i); // Тело цикла } } |
Заметим, что в показанных выше примерах никто не запрещает нам использовать дробные значения счетчика цикла:
For i = 0.5 To 1.5 Step 0.5 ' начальное значение = 0.5, конечное = 1.5, шаг = 0.5
TextWindow.WriteLine("Счетчик цикла = " + i) ' на каждом шаге мы выводим в консоль значение счетчика цикла
EndFor ' конец блока цикла
Точно так же мы можем заставить счетчик цикла изменяться в обратную сторону. Для этого достаточно просто сделать значение шага отрицательным.
1 2 3 4 5 6 7 8 9 10 |
#include "stdio.h" int main(void) { for(float i = 2.3; i >= -3; i = i - 0.2) // здесь задан цикл с дробным отрицательным шагом // переменная цикла все время уменьшается на 0.2 { printf("Счетчик цикла = %f\n", i); // Тело цикла } } |
А если шаг цикла задать равным 0, то мы получим все тот же бесконечный цикл.
Обратите внимание, что мы также можем записать параметры цикла таким образом, что цикл не выполнится ни разу. Например:
1 |
for(float i = 2.3; i >= 3; i = i - 0.2) |
Здесь условие нарушено изначально, потому что 2.3 не может быть больше 3. Следовательно, программа сразу перейдет к первому оператору после тела цикла.
Следует помнить, что в некоторых языках программирования подобная ситуация может привести к однократному выполнению цикла.
Во многих С-подобных языках программирования даже цикл со счетчиком содержит проверку условия. Собственно говоря, в командах процессора цикл всегда организуется с помощью проверки условия и оператора перехода.
Другие типы циклов
Почти во всех языках программирования кроме циклов со счетчиком существуют циклы, в которых только проверяется условие. Как правило, такие циклы с проверкой условия могут быть двух типов:
- С проверкой условия каждый раз перед началом выполнения тела цикла:
- С проверкой выполнения условия каждый раз после выполнения тела цикла:
С помощью этих циклов тоже можно создать бесконечный цикл, если сделать так, чтобы проверяемое условие всегда выполнялось. Для этого, например можно проверять, 1 = 1 ? Так как это условие всегда будет выполнено, то такой цикл с условием будет выполняться бесконечно.
Как я уже говорил, на самом деле на уровне кода процессора существует только цикл, основанный на операторе безусловного перехода, который обычно соединен с оператором проверки условия.
А все остальные, существующие в разных языках программирования, виды циклов - это просто различные скрытые от пользователя дополнения к описанной выше алгоритмической структуре, так называемый "синтаксический сахар" - средства для упрощения написания программ и облегчения труда программистов.
Сейчас в разных языках программирования существуют различные виды циклов, специально предназначенные для обработки каких-то специфических элементов. Например, для обработки различных упорядоченных списков переменных существует специальный цикл foreach, который последовательно проходит по списку, перебирая его элемент за элементом.
Итак:
- Для выполнения однотипных повторяющихся действий в программах существуют специальные структуры, называемые циклами.
- Циклы бывают несколькоисх основных типов: бесконечные, со счетчиком, с проверкой условий.
На следующем занятии мы приступим к изучению упорядоченных списков переменных, называемых массивами.
Поделиться: