Инструменты пользователя

Инструменты сайта


bb:redbook:110

Различия

Показаны различия между двумя версиями страницы.

Ссылка на это сравнение

Предыдущая версия справа и слева Предыдущая версия
Следующая версия
Предыдущая версия
bb:redbook:110 [2016/04/15 16:57]
prospero78 [8. Примечания]
— (текущий)
Строка 1: Строка 1:
-===== 1.10 Введение в циклы ===== 
- 
-==== 1. Понятие о цикле ==== 
-//Циклом// называется //повторяющееся// действие или их набор. Как правило, повтор циклов производится более одного, а содержимое цикла даже может несколько изменяться, в зависимости от включенных в него условий рассмотренных в прошлой главе. 
-==== 2. Цикл с условием на входе ==== 
-Такой цикл сочетает в себе //и условие//, и //сам цикл//. Поскольку условие находится //на входе//, называется этот цикл — //цикл с условием на входе// (и это, как можно догадаться один из //нескольких// видов циклов). Начало такого цикла описывается ключевым словом ''WHILE''. Поскольку этот цикл — частью условие, после окончания описания условий указывается ключевое слово ''DO''. Оно похоже на ''THEN'', с той лишь разницей, что после ''THEN'' идёт однократное исполнение инструкций, а после ''DO'' — пока //не будет// выполнено условие выхода из цикла (для этого и было введено два разных слова, чтобы показать разницу, хотя возможно в будущих вариантах **КП** останется только ''THEN''). В ранних версиях языков для окончания цикла ''WHILE'' использовалось ключевое слово ''LOOP''. Но в **Компонентном Паскале** это слово посчитали лишним, и теперь этот цикл заканчивается по "END;". Вот простой пример использования цикла **WHILE**: 
- 
- > WHILE p1 < 50 DO 
- > INC(p1) 
- > END; 
- 
-В примере на входе для переменной ''р1'' проверяется условие (должна быть меньше 50). И пока это условие выполняется производится наращивание ''р1'' на единицу через ключевое слово ''INC''(инкремент)((В языке Си, (также в **Java**, **python** под влиянием **Си**) для этих целей используется оператор в форме "p1++" или "++p1". А ещё возможна вот такая конструкция: "—(р1++)++". Попробуйте угадать, что это означает, и какой будет результат? (Далеко не все компиляторы такие примочки обрабатывают одинаково). А операции инкремента и декремента (''INC'' и ''DEC'') — это прямые команды процессора. Можете объяснить: зачем было вводить такие языковые конструкции? Подробнее можно посмотреть в [[https://ru.wikipedia.org/wiki/%D0%98%D0%BD%D0%BA%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D1%82|Википедии]].)). Также следует обратить внимание на то, что в цикле с условием на входе (как и в условиях) сложные выражения группируются в круглые скобки. Кроме того, шаг в таком цикле можно сделать //любым//. Например, 0.001. Или ещё меньше. В самом цикле переменные, от которых зависит выход из цикла — можно менять как угодно. Если из тела цикла в примере убрать инкремент переменой ''р1'' — такой цикл не закончится никогда. Иногда такие используются в программах. Но в 99,999% случаев в несистемном программировании такое зацикливание будет //ошибкой программирования//, и **КП** такие ошибки не анализирует. 
-==== 3. Цикл с условием на выходе ==== 
-Это второй вид цикла, в котором условия выхода могут быть сформированы //каким угодно// способом. Как следует из названия, проверка условия производится //на выходе// из цикла. И здесь есть одно важное следствие: даже если и будет произведён выход из цикла — проход по телу цикла //будет гарантирован//, по крайней мере — //один раз//. Пример такого цикла приведён ниже: 
- 
- > REPEAT 
- > p1 := p1 - 10; 
- > UNTIL p1 < - 100; 
- 
-Цикл с условием на выходе начинается с ключевого слова ''REPEAT'' ("повторить"). Выход из цикла предваряется ключевым словом ''UNTIL''("пока не...") — пока //не будет// выполнено условие выхода. Обратите внимание ещё раз — //пока не будет// выполнено условие из выхода! Т. е. если цикл с условием на входе требует //истинности// условия (''ПОВТОРЯТЬ ПОКА ЕСТЬ''), то цикл с условием на выходе требует //отрицания на выходе// (''ПОВТОРЯТЬ ПОКА НЕ ЕСТЬ'')! Если забыть про эту тонкость — ваш цикл //не завершится никогда//((Если всё-таки вы с циклом попали в просак, и ваша программа не останавливается всё-таки ещё есть возможность остановить программу: необходимо одновременно нажать комбинацию клавиш **<Ctrl+Break>**. Это стандартная комбинация для остановки (или прерывания) программ и работает во многих приложениях. В **BlackBox** в том числе.)). 
-==== 4. Целочисленный цикл ==== 
-Этот цикл выделен в отдельную структуру, так как имеет реализацию в командах процессора. Поскольку, для описания параметров целочисленного цикла используются целочисленные значения, то его очень удобно применять для обработки массивов с заранее известным размером. Почему нельзя использовать дробные числа? Да потому что не может быть элемента массива с порядковым номером "2,5". Либо "2", либо "3". Небольшой пример, показывающий использование целочисленного цикла: 
- 
-Hello5.odc 
-<code oberon2> 
-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 
-</code> 
-В этом примере видно, что целочисленный цикл начинается с ключевого слова ''FOR''. В качестве начала целочисленного счётчика цикла используется переменная ''i'', соответствующего типа. Эта переменная определена в секции ''VAR'' процедуры ''Start'' (а это значит, что модуль ''TestHello05'' понятия не имеет о её существовании). Верхняя граница цикла устанавливается после ключевого слова ''TO'' в виде скорректированной константы ''_num''. Уменьшение этой константы на единицу меньше объяснимо тем, что индексация массива ''а'' //начинается с нуля//, а не с ''1''. Поэтому, последний номер элемента массива ''а'' будет ''4'', а не ''5'', как это объявлено в секции ''VAR'' с помощью константы '' _num''. Если такую корректировку верхней границы целочисленного цикла не провести, то в ходе исполнения программы будет //преодолена верхняя граница массива//, и программа "вылетит с ошибкой". Заканчивается целочисленный цикл ''FOR'' традиционно — ключевым словом ''END;''((В других языках часто используются ключевое слово ''Next'' (**Visual Basic**), отступы (**python**), или закрывающие фигурные скобки (**Java**). Использование ''Next'' в **Visual Basic** наименее оправдано, так как в цикле ''FOR'' итак используется несколько ключевых слов, зачем вводить новую сущность? Более того, если следовать логике, то ''NEXT''(ДАЛЬШЕ) --- предполагает, что цикл далее продолжится, а на самом деле с точность наоборот -- это его окончание. Отступы в **python** заставляют писать аккуратный и правильный код, но представьте себе, если вложенных условий или циклов будет //10 уровней//? Какой величины будут отступы? (а отступ в **python** принят 4 пробела — 40 пробелов подряд!). Фигурные скобки в **Java**, состоящие только из одного символа //не цепляют// взгляд и легко теряются на фоне множества таких же скобок. В **Компонентном Паскале**, как ориентированном на надёжность, принято не гнаться за краткостью (в ущерб пониманию), и не вводить излишних сущностей, если существующих хватает для описания структурной единицы.)). Также необходимо обратить внимание на то, что константа начинается с символа подчёркивания (//необязательно//, зато наглядно). 
- 
-Второй цикл ''FOR'' по своему объявлению полностью повторяет первый. Но содержание отличается. Так в первом цикле происходит заполнение массива целочисленных ячеек целочисленными значениями переменной ''i'' с шагом в ''5''. Во втором же цикле происходит вывод значений ячеек массива без их изменения. Если всё сделано правильно, то можно убедиться в том, что у каждой ячейки своё значение: 
- 
-<code> 
-компилируется "TestHello05"   140   0 
-старый модуль TestHello05 выгружен 
- 
-a[ 0]= 0 
-a[ 1]= 5 
-a[ 2]= 10 
-a[ 3]= 15 
-a[ 4]= 20 
-</code> 
- 
-Во втором цикле в строку скомбинирован вывод строк и целочисленных значений. При желании, можно выводить всё-что угодно и такой способ бывает удобен, чтобы оперативно посмотреть, какие значения принимают переменные в ходе выполнения программы. Остаётся один вопрос: переменная ''i'' ни в первом цикле, ни во втором — не меняется. Каким образом происходит её изменение? Правильный ответ состоит в том, что центральный процессор //сам// наращивает значение ''i''. Об этом программисту беспокоиться не надо, и в целочисленном цикле: раньше или позже — но обязательно наступит завершение. 
-==== 5. Целочисленный цикл с начальным произвольным шагом ==== 
-Этот цикл является расширением предыдущего и почти от него не отличается. Пример представлен ниже: 
- 
-Hello6.odc 
- 
-<code oberon2> 
-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 
-</code>   
-Чтобы задать шаг, необходимо после задания числа по окончанию цикла указать ключевое слово ''BY''. В случае примера выше — это ''2''. С таким шагом всё нечётные ячейки массива будут пропущены, обратите внимание на вывод работы этой программы: 
- 
- 
-Так и есть! В нечётных ячейках находится //непонятно что//! В ходе выполнения цикла значения им //не присваивались//. Отсюда следует правило: перед использованием числовых массивов их //очень желательно// обнулять.  
-==== 6. Безусловный цикл ==== 
-И этот цикл не зря называется так //по экстремистски//. Он действительно //безусловный//. Бывают такие программы, которые запускаются вместе с включением компьютера и завершают своё выполнение за одно мгновение до выключения((«Завершить работу за мгновение до выключения» это //вовсе не метафора//. Например, в песне из фильма «Семнадцать мгновений весны» есть строка: «они летят как пули у виска». Т. е. длительность мгновения определяется скоростью полёта пули. Современная пуля летит с такой скоростью, что для съёмки её полёта требуется «всего» 500 тыс. кадров в секунду. Для видеокамеры это //очень много//, но если переводить в частоту центрального процессора — то это будет всего 500 кГц. Чтобы понять на сколько это //мало// для компьютера, достаточно вспомнить, что современные центральные процессоры способны работать на частоте 5000000 кГц. Если учесть, что в **ЦП** может быть до 8 ядер, а конвеер **ЦП** может одновременно выполнять до 16 команд, то становится понятно, что за то время, что длится мгновение компьютер может успеть выполнить 960 тыс. операций. Согласитесь, это //очень много//. Кроме того, когда **Нео** в первой части фильма «Матрица» уклоняется от пуль, становится понятно, что либо **Нео** — читер, который воспользовался кодами, которые и замедлили работу Матрицы, либо все остальные в Зеоне были безграмотны и не умели использовать прерывания программы ).)). В таких программах просто //не нужен// выход из цикла. А если всё-таки наступает условие, по которому надо бесконечный цикл прервать (и при этом нужно избежать тех инструкций, что идут далее) — происходит такой же безусловный выход, не терпящий возражений. Код ниже: 
- 
- > LOOP 
- > IF p1>100 THEN 
- > EXIT 
- > END; 
- > IF GetCommand = 'Exit' THEN 
- > EXIT 
- > END; 
- > INC(p1) 
- > END; 
- 
-Безусловный цикл объявляется ключевым словом ''LOOP''. Внутри него выполняются любые действия. Как только будет выполнено условие (''р1 > 1000''), выход из цикла будет выполнен. Во втором условии выполняется вызов процедуры ''GetCommand'' и если строка-команда будет иметь значение ''Exit'', произойдёт выход из безусловного цикла. Веток, предусматривающих выход из цикла может быть множество. Хотелось бы обратить внимание ещё раз, что получить ''завешивание'' программы в таких конструкциях //очень легко//, и надо предусматривать возможность принудительного прерывания таких циклов (как во втором условии). 
-==== 7. Заключение ==== 
-Итак, циклы бывают трёх видов: 
-  - С условием на входе, условием на выходе (универсальный) 
-  - Целочисленный и целочисленный с произвольным шагом (для обработки массивов, может быть быстрее чем, с условием на входе/выходе) 
-  - Безусловный цикл (для длительных процессов). 
- 
-И важное напоминание: неаккуратное обращение с циклами (кроме целочисленного) может обернуться "зависанием" программы. 
  
bb/redbook/110.1460728652.txt.gz · Последнее изменение: 2020/10/29 07:08 (внешнее изменение)