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

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


blackbox:manual:records

Различия

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

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

blackbox:manual:records [2018/11/30 01:13]
127.0.0.1 внешнее изменение
blackbox:manual:records [2020/10/29 07:08]
Строка 1: Строка 1:
-===== 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''(инкремент)((В языке Си, (также в **Java**, **python** под влиянием **Си**) для этих целей используется оператор в форме ''цПерем1++'' или ''++цПерем1''. А ещё возможна вот такая конструкция: ''—(цПерем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 
-     цПерем1 := цПерем1 - 10; 
- UNTIL цПерем1 < - 100; 
- 
-Цикл с условием на выходе начинается с ключевого слова ''REPEAT'' ("повторить"). Выход из цикла предваряется ключевым словом ''UNTIL''("пока не...") — пока //не будет// выполнено условие выхода. Обратите внимание ещё раз — //пока не будет// выполнено условие из выхода! Т. е. если цикл с условием на входе требует //истинности// условия (''ПОВТОРЯТЬ ПОКА ЕСТЬ''), то цикл с условием на выходе требует //отрицания на выходе// (''ПОВТОРЯТЬ ПОКА НЕ ЕСТЬ'')! Если забыть про эту тонкость — ваш цикл //не завершится никогда//((Если всё-таки вы с циклом попали в просак, и ваша программа не останавливается всё-таки ещё есть возможность остановить программу: необходимо одновременно нажать комбинацию клавиш **<Ctrl+Break>**. Это стандартная комбинация для остановки (или прерывания) программ и работает во многих приложениях. В **BlackBox** в том числе.)). 
-==== 4. Целочисленный цикл ==== 
-Этот цикл выделен в отдельную структуру, так как имеет реализацию в командах процессора. Поскольку, для описания параметров целочисленного цикла используются целочисленные значения, то его очень удобно применять для обработки массивов с заранее известным размером. Почему нельзя использовать дробные числа? Да потому что не может быть элемента массива с порядковым номером "2,5". Либо "2", либо "3". Небольшой пример, показывающий использование целочисленного цикла: 
- 
-  Привет5.odc 
-   
-<code oberon2> 
-MODULE КнигаПривет5; 
- (* Этот пример показывает как использовать 
- целочисленный цикл с массивами *) 
- 
- IMPORT мЛог := Log, Math; 
- 
- PROCEDURE Старт*; 
- 
- CONST 
- _разм = 5; 
- 
- VAR 
- лмцИзмер: ARRAY(_разм) OF INTEGER; 
- лцИтер: INTEGER; 
- 
- BEGIN 
- FOR лцИтер := 0 TO(_разм - 1) DO 
- лмцИзмер[лцИтер] := лцИтер * 5 
- END; 
- FOR лцИтер := 0 TO(_разм - 1) DO 
- мЛог.String('лмцИзмер['); мЛог.Int(лцИтер); 
- мЛог.String(']='); мЛог.Int(лмцИзмер[лцИтер]); 
- мЛог.Ln 
- END; 
- мЛог.Ln 
- END Старт; 
- 
-BEGIN 
-END КнигаПривет5. 
- 
-(!)КнигаПривет5.Старт 
-</code> 
- 
-В этом примере видно, что целочисленный цикл начинается с ключевого слова ''FOR''. В качестве начала целочисленного счётчика цикла используется переменная ''лцИтер''(локальное целое "итератор"), соответствующего типа. Эта переменная определена в секции ''VAR'' процедуры ''Старт'' (а это значит, что модуль ''КнигаПривет5'' понятия не имеет о её существовании). Верхняя граница цикла устанавливается после ключевого слова ''TO'' в виде скорректированной константы ''_разм''. Уменьшение этой константы на единицу меньше объяснимо тем, что индексация массива ''лмцИзмер'' //начинается с нуля//, а не с ''1''. Поэтому, последний номер элемента массива ''лмцИзмер'' будет ''4'', а не ''5'', как это объявлено в секции ''VAR'' с помощью константы '' _разм''. Если такую корректировку верхней границы целочисленного цикла не провести, то в ходе исполнения программы будет //преодолена верхняя граница массива//, и программа "вылетит с ошибкой". Заканчивается целочисленный цикл ''FOR'' традиционно — ключевым словом ''END;''((В других языках часто используются ключевое слово ''Next'' (**Visual Basic**), отступы (**python**), или закрывающие фигурные скобки (**Java**). Использование ''Next'' в **Visual Basic** наименее оправдано, так как в цикле ''FOR'' итак используется несколько ключевых слов, зачем вводить новую сущность? Более того, если следовать логике, то ''NEXT''(ДАЛЬШЕ) --- предполагает, что цикл далее продолжится, а на самом деле с точность наоборот -- это его окончание. Отступы в **python** заставляют писать аккуратный и правильный код, но представьте себе, если вложенных условий или циклов будет //10 уровней//? Какой величины будут отступы? (а отступ в **python** принят 4 пробела — 40 пробелов подряд!). Фигурные скобки в **Java**, состоящие только из одного символа //не цепляют// взгляд и легко теряются на фоне множества таких же скобок. В **Компонентном Паскале**, как ориентированном на надёжность, принято не гнаться за краткостью (в ущерб пониманию), и не вводить излишних сущностей, если существующих хватает для описания структурной единицы.)). Также необходимо обратить внимание на то, что константа начинается с символа подчёркивания (//необязательно//, зато наглядно). 
- 
-Второй цикл ''FOR'' по своему объявлению полностью повторяет первый. Но содержание отличается. Так в первом цикле происходит заполнение массива целочисленных ячеек целочисленными значениями переменной ''лцИтер'' с шагом в ''5''. Во втором же цикле происходит вывод значений ячеек массива без их изменения. Если всё сделано правильно, то можно убедиться в том, что у каждой ячейки своё значение: 
- 
-  компилируется "КнигаПривет5"   140   0 
-  лмцИзмер[ 0]= 0 
-  лмцИзмер[ 1]= 5 
-  лмцИзмер[ 2]= 10 
-  лмцИзмер[ 3]= 15 
-  лмцИзмер[ 4]= 20 
- 
-Во втором цикле в строку скомбинирован вывод строк и целочисленных значений. При желании, можно выводить всё-что угодно и такой способ бывает удобен, чтобы оперативно посмотреть, какие значения принимают переменные в ходе выполнения программы. Остаётся один вопрос: переменная ''лцИтер'' ни в первом цикле, ни во втором — не меняется. Каким образом происходит её изменение? Правильный ответ состоит в том, что центральный процессор //сам// наращивает значение ''лцИтер''. Об этом программисту беспокоиться не надо, и в целочисленном цикле: раньше или позже — но обязательно наступит завершение. 
-==== 5. Целочисленный цикл с начальным произвольным шагом ==== 
-Этот цикл является расширением предыдущего и почти от него не отличается. Пример представлен ниже: 
- 
-  Привет6.odc 
- 
-<code oberon2> 
-MODULE КнигаПривет6; 
- (* Этот пример показывает как использовать 
- целочисленный цикл с массивами c произвольным 
- шагом *) 
- 
- IMPORT мЛог := Log, Math; 
- 
- PROCEDURE Старт*; 
-  
- CONST 
- _разм = 5; 
-  
- VAR 
- лмцИзм: ARRAY(_разм) OF INTEGER; 
- лцИтер: INTEGER; 
-  
- BEGIN 
- FOR лцИтер := 0 TO(_разм - 1) BY 2 DO 
- лмцИзм[лцИтер] := лцИтер * 5 
- END; 
- FOR лцИтер := 0 TO(_разм - 1) DO 
- мЛог.String('лмцИзм['); мЛог.Int(лцИтер); мЛог.String(']='); 
- мЛог.Int(лмцИзм[лцИтер]); мЛог.Ln 
- END; 
- мЛог.Ln 
- END Старт; 
-  
-BEGIN 
-END КнигаПривет6. 
- 
-(!)КнигаПривет6.Старт 
- 
-</code>   
-Чтобы задать шаг, необходимо после задания числа по окончанию цикла указать ключевое слово ''BY''. В случае примера выше — это ''2''. С таким шагом всё нечётные ячейки массива будут пропущены, обратите внимание на вывод работы этой программы: 
- 
-  компилируется "КнигаПривет6"   140   0 
-  лмцИзм[ 0]= 0 
-  лмцИзм[ 1]= 1693148453 
-  лмцИзм[ 2]= 10 
-  лмцИзм[ 3]= 35749088 
-  лмцИзм[ 4]= 20 
- 
-Так и есть! В нечётных ячейках находится //непонятно что//! В ходе выполнения цикла значения им //не присваивались//. Отсюда следует правило: перед использованием числовых массивов их //очень желательно// обнулять.  
-==== 6. Безусловный цикл ==== 
-И этот цикл не зря называется так //по экстремистски//. Он действительно //безусловный//. Бывают такие программы, которые запускаются вместе с включением компьютера и завершают своё выполнение за одно мгновение до выключения((«Завершить работу за мгновение до выключения» это //вовсе не метафора//. Например, в песне из фильма «Семнадцать мгновений весны» есть строка: «они летят как пули у виска». Т. е. длительность мгновения определяется скоростью полёта пули. Современная пуля летит с такой скоростью, что для съёмки её полёта требуется «всего» 500 тыс. кадров в секунду. Для видеокамеры это //очень много//, но если переводить в частоту центрального процессора — то это будет всего 500 кГц. Чтобы понять на сколько это //мало// для компьютера, достаточно вспомнить, что современные центральные процессоры способны работать на частоте 5000000 кГц. Если учесть, что в **ЦП** может быть до 8 ядер, а конвеер **ЦП** может одновременно выполнять до 16 команд, то становится понятно, что за то время, что длится мгновение компьютер может успеть выполнить 960 тыс. операций. Согласитесь, это //очень много//. Кроме того, когда **Нео** в первой части фильма «Матрица» уклоняется от пуль, становится понятно, что либо **Нео** — читер, который воспользовался кодами, которые и замедлили работу Матрицы, либо все остальные в Зеоне были безграмотны и не умели использовать прерывания программы ).)). В таких программах просто //не нужен// выход из цикла. А если всё-таки наступает условие, по которому надо бесконечный цикл прервать (и при этом нужно избежать тех инструкций, что идут далее) — происходит такой же безусловный выход, не терпящий возражений. Код ниже: 
- 
- LOOP 
-     IF цПерем1 > 100 THEN 
-         EXIT 
-     END; 
-     IF цКоманда = _выход THEN 
-         EXIT 
-     END; 
-     INC(цПерем1) 
- END; 
- 
-Безусловный цикл объявляется ключевым словом ''LOOP''. Внутри него выполняются любые действия. Как только будет выполнено условие (''цПерем1 > 1000''), выход из цикла будет выполнен. Во втором условии выполняется сравнение целочисленной переменной ''цКоманда'' и если целое-команда будет иметь значение ''_выход'', произойдёт выход из безусловного цикла. Веток, предусматривающих выход из цикла может быть множество. Хотелось бы обратить внимание ещё раз, что получить ''завешивание'' программы в таких конструкциях //очень легко//, и надо предусматривать возможность принудительного прерывания таких циклов (как во втором условии). 
-==== 7. Заключение ==== 
-Итак, циклы бывают трёх видов: 
-  - С условием на входе, условием на выходе (универсальный) 
-  - Целочисленный и целочисленный с произвольным шагом (для обработки массивов, может быть быстрее чем, с условием на входе/выходе) 
-  - Безусловный цикл (для длительных процессов). 
- 
-И важное напоминание: неаккуратное обращение с циклами (кроме целочисленного) может обернуться "зависанием" программы. 
  
blackbox/manual/records.txt · Последнее изменение: 2020/10/29 07:08 (внешнее изменение)