Глава 8. Циклические программы
Идею цикла я поясню на примере движения объектов по экрану. Возьмем игру в воздушный бой. Самолетик по экрану должен двигаться. Но в списках операторов большинства языков программирования, используемых профессиональными программистами для создания игр, нет команды движения. Здесь нужно задаться вопросом – а что такое движение? Рассмотрим иллюзию движения, возникающую на экране кинотеатра. Если вы держали в руках кинопленку фильма, изображающего, скажем, движение автомобиля, то должны были обратить внимание, что она состоит из множества неподвижных слайдов-кадров, на каждом следующем из которых автомобиль находится чуть-чуть в другом месте, чем на предыдущем. Показывая эти кадры один за другим с большой скоростью, мы создаем иллюзию движения автомобиля. Точно так же поступают с созданием иллюзии движения на экране компьютера. Запишем алгоритм движения самолетика по экрану слева направо:
1.Зададим в уме компьютера позицию самолетика в левой части экрана.
2.Нарисуем в задуманном месте самолетик.
3.Сотрем его.
4.Изменим в уме компьютера позицию самолетика на миллиметр правее.
5.Перейдем к команде 2.
Каждая из приведенных команд алгоритма легко программируется на большинстве языков. Любой компьютер, выполнив очередную команду, автоматически переходит к выполнению следующей. Так, выполнив команду 2, компьютер всегда перейдет к выполнению команды 3. Однако, если мы захотим, то можем заставить компьютер изменить этот порядок, что мы и сделали в команде 5. Из-за нее компьютер выполняет команды в таком порядке: 1-2-3-4-5-2-3-4-5-2-3-…. Напомню, что, выполнив команду 2, компьютер всегда перейдет к выполнению команды 3, независимо от того, какую команду он выполнял перед командой 2 – 1-ю или 5-ю. Таким образом, многократно выполняется последовательность команд 2-3-4-5. Такая многократно выполняемая последовательность называется циклом. Можно сказать, что цикл – это одно из средств заставить компьютер долго работать при помощи короткой программы.
В коротком промежутке времени после выполнения команды 2 самолетик будет появляться на экране и на команде 3 исчезать, но этого достаточно, чтобы человеческий глаз его заметил. Благодаря циклу самолетик будет мелькать каждый раз в новом месте, а поскольку смена «кадров» будет очень быстрой, нам будет казаться, что происходит плавное движение самолетика.
Не нужно думать, что циклы применяются лишь при движении. Они пронизывают все программирование. Ведь со 2-й по 5-ю команды мы можем писать команды любого назначения: и вычислительные, и по работе с текстом и так далее.
Оператор перехода GoTo. Цикл. Метки
Оператор GoTo является одним из самых низкоуровневых средств современных языков программирования и на практике им почти не пользуются. Но сам компьютер «думает» именно на низком уровне, и поэтому настоящий программист должен быть с GoTo «на ты».
Цикл с GoTo. Метки
Посмотрим, как осуществить цикл в VB. Предположим, мы хотим, чтобы компьютер бесконечно повторял выполнение следующего фрагмента:
Debug.Write("Это ")
Debug.Write("тело ")
Debug.WriteLine("цикла")
в результате чего в окне Output мы бы увидели:
Это тело цикла
Это тело цикла
Это тело цикла
Это тело цикла
. . . . . . . .
Если бы операторы VB можно было писать по-русски, то для достижения нашей цели было бы естественно воспользоваться такой конструкцией:
метка m1: Debug.Write( "Это ")
Debug.Write("тело ")
Debug.WriteLine("цикла")
Иди к оператору, помеченному меткой m1
Здесь мы видим новый для нас «оператор» ИДИ, который выполняется после оператора Debug.WriteLine("цикла") и единственная работа которого заключается в том, чтобы заставить компьютер перескочить к выполнению оператора Debug.Write( "Это "), помеченного меткой m1.
А вот как этот фрагмент выглядит реально на VB (не запускайте его пока):
m1: Debug.Write("Это ")
Debug.Write("тело ")
Debug.WriteLine("цикла")
GoTo m1
Здесь GoTom1 – оператор безусловного перехода, переводится «иди к», m1:– метка. Метка- это произвольное имя или произвольное не слишком большое целое положительное число. Метка перед оператором должна заканчиваться двоеточием.
Оператор GoTo можно писать в любых местах процедуры и метку можно ставить перед любым оператором процедуры, заставляя компьютер таким образом перескакивать внутри процедуры откуда угодно куда угодно. Правда, в сложных процедурах и внутри сложных операторов эта свобода перескакивания существенно ограничивается, так что я не советую вам врываться снаружи внутрь вложенных операторов, а вот изнутри наружу – пожалуйста. Между процедурами скакать нельзя.
А теперь запустите эту программу, но только в пошаговом режиме. Посмотрите, как заполняется окно Output. Чтобы оно заполнялось быстрее, нажмите клавишу F11 и не отпускайте.
Группа операторов, выполняющихся многократно, называется телом цикла. У нас это все 4 оператора.
Зацикливание
Теперь запустите эту программу обычным образом (не в пошаговом режиме). Через некоторое время перед вами должен встать жизненно важный вопрос – когда же она остановится? А никогда! Вы видите, что окно Output лихорадочно заполняется текстом, а белка в колесе и не думает уставать.
Вы обнаружите, что кнопки и другие элементы управления на форме не отзываются на нажатие мыши, и вообще, до программы «не докричишься». Любопытно, что так «глохнет» любая нормальная программа в процессе выполнения операторов кода. И все ваши прежние программы тоже так «глохли». Но вы этого не замечали по той простой причине, что весь код их процедур выполнялся очень быстро. Не успели вы нажать на кнопку, а все уже выполнилось и снова программа реагирует на ваши действия.
В нормальной программе, написанной без ошибок, исключены ситуации, когда код выполняется бесконечно или на протяжении слишком долгого времени. Если же вы допустили ошибку и в программе выполняется бесконечный цикл, то возникает как раз такая ситуация. Вы вечно будете смотреть на экран, по которому бесконечно бегут непонятные числа или слова или рисуются бесконечные вереницы графических фигур, а возможно и ничего не происходит – все зависит от характера программы. Говорят, что программа зациклилась.
Для прерывания работы программы, в том числе и зациклившейся, вы нажимаете кнопку Stop. Можно щелкнуть и по крестику на форме, но в этом случае VB подвергнет вас небольшому допросу.
Примеры
Все нижеприведенные примеры прогоните в обычном и в пошаговом режиме.
Пример 1. Определите без компьютера, что напечатает фрагмент:
Dim a = 100
GoTo 8
a = a + 40
Dim k = 7
Debug.Write(a)
8: a = a + 2
k = k + 10
Debug.Write(a)
Этот фрагмент напечатает 102. Операторы выполняются в такой последовательности:
Dim a = 100
GoTo 8
a = a + 2
k = k + 10
Debug.Write(a)
А операторы
a = a + 40
Dim k = 7
Debug.Write(a)
выполнены не будут вообще, несмотря на то, что написаны. Цикла здесь нет.
Пример 2. Печатать числа 0, 1, 2, 3 . . . и так без конца.
Вот программа:
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
Dim n As Long = 0
m1: Debug.Write(n & " ")
n = n + 1
GoTo m1
End Sub
Здесь в оператор Debug.Write(n & " ") вставлена печать пробела, чтобы как-то отделить друг от друга числа в одной строке.
Обратите внимание, что когда компьютер, скажем, в 24-й раз выполняет тело цикла, значение n как раз равно 24. Значит, зная в любой момент значение n, мы можем сказать, в какой раз выполняется тело цикла (еще говорят: какая итерацияцикла выполняется). Переменная, обладающая таким свойством, называется счетчиком циклов.
Пример 3. Выводить числа 0, 1, 2, 3 . . . , но не на печать, а в элемент управления Label (что весьма приятно наблюдать).
Вот программа:
Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click
Dim n As Long = 0
m1: Label1.Text = n
Label1.Refresh()
n = n + 1
GoTo m1
End Sub
Здесь новостью для нас является оператор Label1.Refresh(), который можно перевести так – «перерисовать, обновить, освежить Label1». Без него вы не увидели бы в Label1 никаких новых чисел, информация в ней просто не обновлялась бы. Метод Refresh подходит в некоторых случаях и к другим элементам управления.
Пример 4. Печатать числа 200, 205, 210, 215 . . . и так без конца.
Вот программа:
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
Dim n As Long = 200
m1: Debug.Write(n & " ")
n = n + 5
GoTo m1
End Sub
Задание 23.
Определить без компьютера, что будет печатать программа:
Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click
Dim n As Integer = 10
Dim k As Integer = 0
Debug.WriteLine("Считаем зайцев")
met5: Debug.Write(n)
n = n + k
GoTo m1
n = n + 1
m1: Debug.WriteLine(" зайцев")
k = k + 1
GoTo met5
Debug.Write("Посчитали зайцев")
End Sub
Если не можете определить – посмотрите в пошаговом режиме.