Найти тему
ZDG

Когда нужен перебор. Часть 3: Условные переходы и маленькое поздравление.

В первых двух частях я рассказал, зачем нужны массивы и циклы. Но я описал цикл, из которого нет выхода, и значит он бесполезен. Должно быть что-то ещё, чтобы заставить цикл остановиться в нужный момент.

Представим, что каждый раз, когда цикл должен повториться, мы задаём вопрос – надо его повторять или нет? Если бы у нас была такая возможность, то мы могли бы закончить цикл тогда, когда захотим.

К счаcтью, такая возможность есть. Это ещё одна машинная инструкция, которая может сравнить одно значение с другим и получить результат: больше, меньше, равно. Поэтому мы можем просто считать, сколько раз выполнился цикл. Для этого можно завести переменную-счетчик, и при каждом повторении цикла увеличивать её на 1.

Сейчас я составлю простой цикл, в котором переменная будет увеличиваться на 1. Примечание: я делаю цикл с помощью метки и перехода goto на метку. Это очень примитивная и вредная с точки зрения языков программирования конструкция, настолько вредная, что некоторые языки даже полностью запрещают goto. Как в языках программирования делают нормальные циклы, и почему goto считается вредным, я объясню ниже. Но усвойте навсегда, что можно написать самый красивый цикл на самом красивом языке, а после трансляции в машинный код всё равно получится метка и goto. Просто вы этого не увидите. Сейчас я просто хочу нагляднее показать, как это работает. Поэтому буду использовать пример на языке C.

  1. Сначала я заведу целочисленную переменную-счетчик, назову её "a" и присвою ей 0. Это будет означать, что цикл пока что повторился 0 раз, то есть ни разу:
    int a = 0;
  2. Теперь я поставлю метку, с которой должен повторяться цикл. Это любое имя с двоеточием. Назову её label ("метка").
    label:
  3. Затем я напишу тело цикла – то, что должно повторяться. Сейчас в теле цикла я буду просто увеличивать счетчик на 1. Для этого служит операция ++.
    a++;
  4. И наконец, я напишу возврат на метку label, чтобы цикл замкнулся.
    goto label;

Всё вместе:

Я добился того, чтобы значение a увеличивалось на 1 в цикле. Теперь, если я хочу повторить цикл только 5 раз, мне нужно написать условие. Это условие будет сравнивать a с 5.

if (a < 5) goto label;

"if" значит "если". Такая инструкция используется почти во всех языках программирования. Видели одну – видели все. Написав такую инструкцию, мы получаем следующий результат человеческим языком:

если a < 5, перейди на метку label.

А если a = 5 или а > 5? Тогда условие не выполняется, перехода на метку не происходит, и программа работает дальше. Ура, мы вышли из цикла!

Мы только что ознакомились с понятием безусловного перехода (goto) и условного перехода (if ... goto). Условный переход выполняется только тогда, когда выполняется заданное условие.

Поздравляю!

Хакер из аниме "Ковбой Бибоп".
Хакер из аниме "Ковбой Бибоп".

Освоив условные и безусловные переходы, вы освоили буквально всё программирование. Хотя в языках программирования есть много модных фишек и плюшек, непосредственно в машинном коде всего этого нет. Есть только условия и переходы. С помощью только условий и переходов вы можете написать ВООБЩЕ ЛЮБУЮ программу.

Однако, посмотрим, как языки организуют циклы без goto. Напишу сразу код, а затем разберу его. Этот код также одинаков для очень большого количества языков, поэтому видели один – видели все.

Здесь появляется инструкция while, которая означает "пока". То есть,

пока a < 5, надо...

Надо что? Надо выполнять то, что написано между фигурными скобками "{ }". Такие скобки служат для объединения нескольких инструкций в один смысловой блок, который или выполняется, или не выполняется целиком. В данном случае в блоке есть только одна инструкция, но это неважно.

Таким образом, весь блок со всем своим содержимым связан с инструкцией while, и целиком зависит от нее.

Нетрудно заметить, что while одновременно заменяет if (так как проверяет условие) и goto (так как сама организует цикл). В данном случае невидимый goto как бы стоит там, где стоит закрывающая скобка "}", и перенаправляет выполнение программы снова на строку с while.

Для сравнения, то же самое можно записать с помощью метки и goto:

Если выполняется условие if, то, как и в предыдущем варианте, выполняется всё, что записано между скобками "{ }". Блок инструкций на этот раз связан с if. Как видим, он будет выполняться, только пока a < 5.

Также замечу на будущее, что расположение скобок не играет роли. Можно написать так:

или так:

Всё это одно и то же.

Кроме цикла while, есть еще циклы for, do, а также т.н. итераторы типа foreach для перебора т.н. коллекций. Все они ничем не отличаются от обычных циклов и служат только для облегчения написания и понимания кода. Поэтому я не буду здесь на них заостряться. Когда понадобятся – тогда и расскажу. Если вы нормально усвоили, что такое цикл, остальные варианты это уже пустяки.

Но почему в языках программирования не приветствуется или вовсе запрещается использовать переходы goto? Просто потому, что такие переходы, если их использовать в большом количестве и как попало, сильно замусоривают код и затрудняют его понимание. То есть путем запрета goto вас заставляют писать понятные и легко отлаживаемые программы. Других причин нет. Однако если вам доведётся писать на языке ассемблера, то у вас там не будет ничего кроме goto, или, по-тамошнему, jmp (jump – прыжок). И там вы сможете оторваться по полной.

Ну, а дальше мы наконец возьмем всех монстров и в цикле обработаем их, как положено. И кроме того, обсудим другие возможности программ.

Читайте дальше: