INC
и DEC
) — это прямые команды процессора. Можете объяснить: зачем было вводить такие языковые конструкции? Подробнее можно посмотреть в Википедии.Это старая версия документа!
Циклом называется повторяющееся действие или их набор. Как правило, повтор циклов производится более одного, а содержимое цикла даже может несколько изменяться, в зависимости от включенных в него условий рассмотренных в прошлой главе.
Такой цикл сочетает в себе и условие, и сам цикл. Поскольку условие находится на входе, называется этот цикл — цикл с условием на входе (и это, как можно догадаться один из нескольких видов циклов). Начало такого цикла описывается ключевым словом WHILE
. Поскольку этот цикл — частью условие, после окончания описания условий указывается ключевое слово DO
. Оно похоже на THEN
, с той лишь разницей, что после THEN
идёт однократное исполнение инструкций, а после DO
— пока не будет выполнено условие выхода из цикла (для этого и было введено два разных слова, чтобы показать разницу, хотя возможно в будущих вариантах КП останется только THEN
). В ранних версиях языков для окончания цикла WHILE
использовалось ключевое слово LOOP
. Но в Компонентном Паскале это слово посчитали лишним, и теперь этот цикл заканчивается по END;
. Вот простой пример использования цикла WHILE:
> WHILE p1 < 50 DO > INC(p1) > END;
В примере на входе для переменной р1
проверяется условие (должна быть меньше 50). И пока это условие выполняется производится наращивание р1
на единицу через ключевое слово INC
(инкремент)1). Также следует обратить внимание на то, что в цикле с условием на входе (как и в условиях) сложные выражения группируются в круглые скобки. Кроме того, шаг в таком цикле можно сделать любым. Например, 0.001. Или ещё меньше. В самом цикле переменные, от которых зависит выход из цикла — можно менять как угодно. Если из тела цикла в примере убрать инкремент переменой р1
— такой цикл не закончится никогда. Иногда такие используются в программах. Но в 99,999% случаев в несистемном программировании такое зацикливание будет ошибкой программирования, и КП такие ошибки не анализирует.
Это второй вид цикла, в котором условия выхода могут быть сформированы каким угодно способом. Как следует из названия, проверка условия производится на выходе из цикла. И здесь есть одно важное следствие: даже если и будет произведён выход из цикла — проход по телу цикла будет гарантирован, по крайней мере — один раз. Пример такого цикла приведён ниже:
> REPEAT > p1 := p1 - 10; > UNTIL p1 < - 100;
Цикл с условием на выходе начинается с ключевого слова REPEAT
(«повторить»). Выход из цикла предваряется ключевым словом UNTIL
(«пока не…») — пока не будет выполнено условие выхода. Обратите внимание ещё раз — пока не будет выполнено условие из выхода! Т. е. если цикл с условием на входе требует истинности условия (ПОВТОРЯТЬ ПОКА ЕСТЬ
), то цикл с условием на выходе требует отрицания на выходе (ПОВТОРЯТЬ ПОКА НЕ ЕСТЬ
)! Если забыть про эту тонкость — ваш цикл не завершится никогда2).
Этот цикл выделен в отдельную структуру, так как имеет реализацию в командах процессора. Поскольку, для описания параметров целочисленного цикла используются целочисленные значения, то его очень удобно применять для обработки массивов с заранее известным размером. Почему нельзя использовать дробные числа? Да потому что не может быть элемента массива с порядковым номером «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
. Об этом программисту беспокоиться не надо, и в целочисленном цикле: раньше или позже — но обязательно наступит завершение.
Этот цикл является расширением предыдущего и почти от него не отличается. Пример представлен ниже:
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
. С таким шагом всё нечётные ячейки массива будут пропущены, обратите внимание на вывод работы этой программы:
Так и есть! В нечётных ячейках находится непонятно что! В ходе выполнения цикла значения им не присваивались. Отсюда следует правило: перед использованием числовых массивов их очень желательно обнулять.
И этот цикл не зря называется так по экстремистски. Он действительно безусловный. Бывают такие программы, которые запускаются вместе с включением компьютера и завершают своё выполнение за одно мгновение до выключения4). В таких программах просто не нужен выход из цикла. А если всё-таки наступает условие, по которому надо бесконечный цикл прервать (и при этом нужно избежать тех инструкций, что идут далее) — происходит такой же безусловный выход, не терпящий возражений. Код ниже:
> LOOP > IF p1>100 THEN > EXIT > END; > IF GetCommand = 'Exit' THEN > EXIT > END; > INC(p1) > END;
Безусловный цикл объявляется ключевым словом LOOP
. Внутри него выполняются любые действия. Как только будет выполнено условие (р1 > 1000
), выход из цикла будет выполнен. Во втором условии выполняется вызов процедуры GetCommand
и если строка-команда будет иметь значение Exit
, произойдёт выход из безусловного цикла. Веток, предусматривающих выход из цикла может быть множество. Хотелось бы обратить внимание ещё раз, что получить завешивание
программы в таких конструкциях очень легко, и надо предусматривать возможность принудительного прерывания таких циклов (как во втором условии).
Итак, циклы бывают трёх видов:
И важное напоминание: неаккуратное обращение с циклами (кроме целочисленного) может обернуться «зависанием» программы.
INC
и DEC
) — это прямые команды процессора. Можете объяснить: зачем было вводить такие языковые конструкции? Подробнее можно посмотреть в Википедии.Next
(Visual Basic), отступы (python), или закрывающие фигурные скобки (Java). Использование Next
в Visual Basic наименее оправдано, так как в цикле FOR
итак используется несколько ключевых слов, зачем вводить новую сущность? Более того, если следовать логике, то NEXT
(ДАЛЬШЕ) — предполагает, что цикл далее продолжится, а на самом деле с точность наоборот – это его окончание. Отступы в python заставляют писать аккуратный и правильный код, но представьте себе, если вложенных условий или циклов будет 10 уровней? Какой величины будут отступы? (а отступ в python принят 4 пробела — 40 пробелов подряд!). Фигурные скобки в Java, состоящие только из одного символа не цепляют взгляд и легко теряются на фоне множества таких же скобок. В Компонентном Паскале, как ориентированном на надёжность, принято не гнаться за краткостью (в ущерб пониманию), и не вводить излишних сущностей, если существующих хватает для описания структурной единицы.