Это старая версия документа!
1.10 Введение в циклы
1. Понятие о цикле
Циклом называется повторяющееся действие или их набор. Как правило, повтор циклов производится более одного, а содержимое цикла даже может несколько изменяться, в зависимости от включенных в него условий рассмотренных в прошлой главе.
2. Цикл с условием на входе
Такой цикл сочетает в себе и условие, и сам цикл. Поскольку условие находится на входе, называется этот цикл — цикл с условием на входе (и это, как можно догадаться один из нескольких видов циклов). Начало такого цикла описывается ключевым словом WHILE
. Поскольку этот цикл — частью условие, после окончания описания условий указывается ключевое слово DO
. Оно похоже на THEN
, с той лишь разницей, что после THEN
идёт однократное исполнение инструкций, а после DO
— пока не будет выполнено условие выхода из цикла (для этого и было введено два разных слова, чтобы показать разницу, хотя возможно в будущих вариантах КП останется только THEN
). В ранних версиях языков для окончания цикла WHILE
использовалось ключевое слово LOOP
. Но в Компонентном Паскале это слово посчитали лишним, и теперь этот цикл заканчивается по END;
. Вот простой пример использования цикла WHILE:
WHILE цПерем1 < 50 DO
INC(цПерем1)
END;
В примере на входе для переменной цПерем1
проверяется условие (должна быть меньше 50). И пока это условие выполняется производится наращивание цПерем1
на единицу через ключевое слово INC
(инкремент)1). Также следует обратить внимание на то, что в цикле с условием на входе (как и в условиях) сложные выражения группируются в круглые скобки. Кроме того, шаг в таком цикле можно сделать любым. Например, 0.001. Или ещё меньше. В самом цикле переменные, от которых зависит выход из цикла — можно менять как угодно. Если из тела цикла в примере убрать инкремент переменой цПерем1
— такой цикл не закончится никогда. Иногда такие используются в программах. Но в 99,999% случаев в несистемном программировании такое зацикливание будет ошибкой программирования, и КП такие ошибки не анализирует.
3. Цикл с условием на выходе
Это второй вид цикла, в котором условия выхода могут быть сформированы каким угодно способом. Как следует из названия, проверка условия производится на выходе из цикла. И здесь есть одно важное следствие: даже если и будет произведён выход из цикла — проход по телу цикла будет гарантирован, по крайней мере — один раз. Пример такого цикла приведён ниже:
REPEAT
цПерем1 := цПерем1 - 10;
UNTIL цПерем1 < - 100;
Цикл с условием на выходе начинается с ключевого слова REPEAT
(«повторить»). Выход из цикла предваряется ключевым словом UNTIL
(«пока не…») — пока не будет выполнено условие выхода. Обратите внимание ещё раз — пока не будет выполнено условие из выхода! Т. е. если цикл с условием на входе требует истинности условия (ПОВТОРЯТЬ ПОКА ЕСТЬ
), то цикл с условием на выходе требует отрицания на выходе (ПОВТОРЯТЬ ПОКА НЕ ЕСТЬ
)! Если забыть про эту тонкость — ваш цикл не завершится никогда2).
4. Целочисленный цикл
Этот цикл выделен в отдельную структуру, так как имеет реализацию в командах процессора. Поскольку, для описания параметров целочисленного цикла используются целочисленные значения, то его очень удобно применять для обработки массивов с заранее известным размером. Почему нельзя использовать дробные числа? Да потому что не может быть элемента массива с порядковым номером «2,5». Либо «2», либо «3». Небольшой пример, показывающий использование целочисленного цикла:
Hello5.odc
MODULE TestHello05;
(* Этот пример показывает как использовать
целочисленный цикл с массивами *)
IMPORT Log, Math;
PROCEDURE Start*;
CONST
_num = 5;
VAR
a: ARRAY(_num) OF INTEGER;
i: INTEGER;
BEGIN
FOR i := 0 TO(_num - 1) DO
a[i] := i * 5
END;
FOR i := 0 TO(_num - 1) DO
Log.String('a['); Log.Int(i); Log.String(']='); Log.Int(a[i]);
Log.Ln
END;
Log.Ln
END Start;
BEGIN
END TestHello05.
(!)TestHello05.Start
В этом примере видно, что целочисленный цикл начинается с ключевого слова FOR
. В качестве начала целочисленного счётчика цикла используется переменная i
, соответствующего типа. Эта переменная определена в секции VAR
процедуры Start
(а это значит, что модуль TestHello05
понятия не имеет о её существовании). Верхняя граница цикла устанавливается после ключевого слова TO
в виде скорректированной константы _num
. Уменьшение этой константы на единицу меньше объяснимо тем, что индексация массива а
начинается с нуля, а не с 1
. Поэтому, последний номер элемента массива а
будет 4
, а не 5
, как это объявлено в секции VAR
с помощью константы _num
. Если такую корректировку верхней границы целочисленного цикла не провести, то в ходе исполнения программы будет преодолена верхняя граница массива, и программа «вылетит с ошибкой». Заканчивается целочисленный цикл FOR
традиционно — ключевым словом END;
3). Также необходимо обратить внимание на то, что константа начинается с символа подчёркивания (необязательно, зато наглядно).
Второй цикл FOR
по своему объявлению полностью повторяет первый. Но содержание отличается. Так в первом цикле происходит заполнение массива целочисленных ячеек целочисленными значениями переменной i
с шагом в 5
. Во втором же цикле происходит вывод значений ячеек массива без их изменения. Если всё сделано правильно, то можно убедиться в том, что у каждой ячейки своё значение:
компилируется "TestHello05" 140 0
старый модуль TestHello05 выгружен
a[ 0]= 0
a[ 1]= 5
a[ 2]= 10
a[ 3]= 15
a[ 4]= 20
Во втором цикле в строку скомбинирован вывод строк и целочисленных значений. При желании, можно выводить всё-что угодно и такой способ бывает удобен, чтобы оперативно посмотреть, какие значения принимают переменные в ходе выполнения программы. Остаётся один вопрос: переменная i
ни в первом цикле, ни во втором — не меняется. Каким образом происходит её изменение? Правильный ответ состоит в том, что центральный процессор сам наращивает значение i
. Об этом программисту беспокоиться не надо, и в целочисленном цикле: раньше или позже — но обязательно наступит завершение.
5. Целочисленный цикл с начальным произвольным шагом
Этот цикл является расширением предыдущего и почти от него не отличается. Пример представлен ниже:
Hello6.odc
MODULE TestHello06;
(* Этот пример показывает как использовать
целочисленный цикл с массивами c произвольным
шагом *)
IMPORT Log, Math;
PROCEDURE Start*;
CONST
Num = 5;
VAR
a: ARRAY(Num) OF INTEGER;
i: INTEGER;
BEGIN
FOR i := 0 TO(Num - 1) BY 2 DO
a[i] := i * 5
END;
FOR i := 0 TO(Num - 1) DO
Log.String('a['); Log.Int(i); Log.String(']='); Log.Int(a[i]); Log.Ln
END;
Log.Ln
END Start;
BEGIN
END TestHello06.
(!)TestHello06.Start
Чтобы задать шаг, необходимо после задания числа по окончанию цикла указать ключевое слово BY
. В случае примера выше — это 2
. С таким шагом всё нечётные ячейки массива будут пропущены, обратите внимание на вывод работы этой программы:
Так и есть! В нечётных ячейках находится непонятно что! В ходе выполнения цикла значения им не присваивались. Отсюда следует правило: перед использованием числовых массивов их очень желательно обнулять.
6. Безусловный цикл
И этот цикл не зря называется так по экстремистски. Он действительно безусловный. Бывают такие программы, которые запускаются вместе с включением компьютера и завершают своё выполнение за одно мгновение до выключения4). В таких программах просто не нужен выход из цикла. А если всё-таки наступает условие, по которому надо бесконечный цикл прервать (и при этом нужно избежать тех инструкций, что идут далее) — происходит такой же безусловный выход, не терпящий возражений. Код ниже:
> LOOP
> IF p1>100 THEN
> EXIT
> END;
> IF GetCommand = 'Exit' THEN
> EXIT
> END;
> INC(p1)
> END;
Безусловный цикл объявляется ключевым словом LOOP
. Внутри него выполняются любые действия. Как только будет выполнено условие (р1 > 1000
), выход из цикла будет выполнен. Во втором условии выполняется вызов процедуры GetCommand
и если строка-команда будет иметь значение Exit
, произойдёт выход из безусловного цикла. Веток, предусматривающих выход из цикла может быть множество. Хотелось бы обратить внимание ещё раз, что получить завешивание
программы в таких конструкциях очень легко, и надо предусматривать возможность принудительного прерывания таких циклов (как во втором условии).
7. Заключение
Итак, циклы бывают трёх видов:
С условием на входе, условием на выходе (универсальный)
Целочисленный и целочисленный с произвольным шагом (для обработки массивов, может быть быстрее чем, с условием на входе/выходе)
Безусловный цикл (для длительных процессов).
И важное напоминание: неаккуратное обращение с циклами (кроме целочисленного) может обернуться «зависанием» программы.