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

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


blackbox:manual:records

Различия

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

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

Следующая версия
Предыдущая версия
blackbox:manual:records [2017/12/26 07:53]
иван_денисов создано
blackbox:manual:records [2020/10/29 07:08] (текущий)
Строка 1: Строка 1:
-===== 1.10 Введение в циклы =====+===== 1.11 Введение в записи =====
  
-==== 1. Понятие о цикле ==== +==== 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Цикл с условием на выходе ==== +==== 2Пример записи ==== 
-Это второй вид циклав котором условия выхода могут быть сформированы //каким угодно// способом. Как следует из названия, проверка условия производится //на выходе// из цикла. И здесь есть одно важное следствие: даже если и будет произведён выход из цикла — проход по телу цикла //будет гарантирован//, по крайней мере — //один раз//. Пример такого цикла приведён ниже:+В тексте модуля, который приведён ниже, представлено объявление одной записи с несколькими полями:
  
- REPEAT +  Привет7.odc 
-     цПерем1 := цПерем1 - 10; +
- UNTIL цПерем1 < - 100; +
- +
-Цикл с условием на выходе начинается с ключевого слова ''REPEAT'' ("повторить"). Выход из цикла предваряется ключевым словом ''UNTIL''("пока не...") — пока //не будет// выполнено условие выхода. Обратите внимание ещё раз — //пока не будет// выполнено условие из выхода! Т. е. если цикл с условием на входе требует //истинности// условия (''ПОВТОРЯТЬ ПОКА ЕСТЬ''), то цикл с условием на выходе требует //отрицания на выходе// (''ПОВТОРЯТЬ ПОКА НЕ ЕСТЬ'')! Если забыть про эту тонкость — ваш цикл //не завершится никогда//((Если всё-таки вы с циклом попали в просак, и ваша программа не останавливается всё-таки ещё есть возможность остановить программу: необходимо одновременно нажать комбинацию клавиш **<Ctrl+Break>**. Это стандартная комбинация для остановки (или прерывания) программ и работает во многих приложениях. В **BlackBox** в том числе.)). +
-==== 4. Целочисленный цикл ==== +
-Этот цикл выделен в отдельную структуру, так как имеет реализацию в командах процессора. Поскольку, для описания параметров целочисленного цикла используются целочисленные значения, то его очень удобно применять для обработки массивов с заранее известным размером. Почему нельзя использовать дробные числа? Да потому что не может быть элемента массива с порядковым номером "2,5". Либо "2", либо "3". Небольшой пример, показывающий использование целочисленного цикла: +
- +
-  Привет5.odc +
-  +
 <code oberon2> <code oberon2>
-MODULE КнигаПривет5+MODULE КнигаПривет7
- (* Этот пример показывает как использовать + (* Этот пример показывает как объявлять записи *)
- целочисленный цикл с массивами *)+
  
- IMPORT мЛог := Log, Math;+ IMPORT Log, Math
 +  
 +VAR 
 + зТочка: RECORD 
 + цКоорд_х, цКоорд_у: INTEGER; 
 + бВключ: BOOLEAN; 
 + мцЦвет: ARRAY 3 OF INTEGER; 
 + END;
  
  PROCEDURE Старт*;  PROCEDURE Старт*;
- 
- CONST 
- _разм = 5; 
- 
  VAR  VAR
- лмцИзмер: ARRAY(_разм) OF INTEGER; 
- лцИтер: INTEGER; 
- 
  BEGIN  BEGIN
- FOR лцИтер := 0 TO(_разм - 1) DO 
- лмцИзмер[лцИтер] := лцИтер * 5 
- END; 
- FOR лцИтер := 0 TO(_разм - 1) DO 
- мЛог.String('лмцИзмер['); мЛог.Int(лцИтер); 
- мЛог.String(']='); мЛог.Int(лмцИзмер[лцИтер]); 
- мЛог.Ln 
- END; 
- мЛог.Ln 
  END Старт;  END Старт;
  
 BEGIN BEGIN
-END КнигаПривет5.+END КнигаПривет7. 
 +</code>
  
-(!)КнигаПривет5.Старт +В секции ''VAR'' модуля объявлена переменная ''зТочка'' с ключевым словом ''RECORD''. Это //не тип данных//, это переменная, которая является точкой входа для записи. В самой записи могут быть //любые// поля любого типа, в неограниченном количестве (конечно, учитывая размер свободной памяти и разумность попытки разместить всё под одним объявление ''RECORD'')Более того, в запись может быть включена другая запись, в которую может быть включена другая запись, в которую...
-</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**, состоящие только из одного символа //не цепляют// взгляд и легко теряются на фоне множества таких же скобок. В **Компонентном Паскале**, как ориентированном на надёжность, принято не гнаться за краткостью (в ущерб пониманию), и не вводить излишних сущностей, если существующих хватает для описания структурной единицы.)). Также необходимо обратить внимание на то, что константа начинается с символа подчёркивания (//необязательно//, зато наглядно).+Описание полей в записи разделяются точкой с запятойа само объявление записи ограничивается ключевым словом ''END;''
 +==== 3. Обращение к полям записи ==== 
 +  
 +Обращение к полям записи происходит точно также, как и к простой переменной. Обращение к элементу массива в записив сущности, ничем не отличается от обращения к элементу простого масва. Единственное отличие, перед полем записи должно быть указано имя соответствующей переменной с типом RECORD и подряд символ "." ("точка"). Пример такого обращения к записи:
  
-Второй цикл ''FOR'' по своему объявлению полностью повторяет первыйНо содержание отличается. Так в первом цикле происходит заполнение массива целочисленных ячеек целочисленными значениями переменной ''лцИтер'' с шагом в ''5''. Во втором же цикле происходит вывод значений ячеек массива без их изменения. Если всё сделано правильно, то можно убедиться в том, что у каждой ячейки своё значение:+  Привет7.odc
  
-  компилируется "КнигаПривет5"   140   0 +<code oberon2> 
-  лмцИзмер[ 0]= 0 +MODULE КнигаПривет7; 
-  лмцИзмер[ 1]= 5 + (* Этот пример показывает как объявлять записи *)
-  лмцИзмер[ 2]= 10 +
-  лмцИзмер[ 3]= 15 +
-  лмцИзмер[ 4]= 20+
  
-Во втором цикле в строку скомбинирован вывод строк и целочисленных значений. При желанииможно выводить всё-что угодно и такой способ бывает удобен, чтобы оперативно посмотреть, какие значения принимают переменные в ходе выполнения программы. Остаётся один вопрос: переменная ''лцИтер'' ни в первом цикле, ни во втором — не меняется. Каким образом происходит её изменение? Правильный ответ состоит в том, что центральный процессор //сам// наращивает значение ''лцИтер''. Об этом программисту беспокоиться не надо, и в целочисленном цикле: раньше или позже — но обязательно наступит завершение. + IMPORT LogMath;
-==== 5. Целочисленный цикл с начальным произвольным шагом ==== +
-Этот цикл является расширением предыдущего и почти от него не отличается. Пример представлен ниже:+
  
-  Привет6.odc + VAR 
- + зТочка: RECORD 
-<code oberon2> + цКоорд_х, цКоорд_у: INTEGER; 
-MODULE КнигаПривет6; + бВключ: BOOLEAN; 
- (* Этот пример показывает как использовать + мцЦвет: ARRAY 3 OF INTEGER; 
- целочисленный цикл с массивами c произвольным + END;
- шагом *) +
- +
- IMPORT мЛог := Log, Math;+
  
  PROCEDURE Старт*;  PROCEDURE Старт*;
-  
- CONST 
- _разм = 5; 
-  
  VAR  VAR
- лмцИзм: ARRAY(_разм) OF INTEGER; 
  лцИтер: INTEGER;  лцИтер: INTEGER;
-  
  BEGIN  BEGIN
- FOR лцИтер := 0 TO(_разм - 1BY 2 DO + зТочка.цКоорд_х := 5; 
- лмцИзм[лцИтер:= лцИтер * 5+ зТочка.цКоорд_у := 4; 
 + Log.Int(зТочка.цКоорд_х); Log.String(', '); 
 + Log.Int(зТочка.цКоорд_у); Log.Ln; 
 + зТочка.мцЦвет[0] := 4; 
 + зТочка.мцЦвет[2] :=  - 10; 
 + FOR лцИтер := 0 TO 2 DO 
 + Log.Int(зТочка.мцЦвет[лцИтер]); Log.String(', ')
  END;  END;
- FOR лцИтер := 0 TO(_разм - 1) DO + Log.Ln
- мЛог.String('лмцИзм['); мЛог.Int(лцИтер); мЛог.String(']='); +
- мЛог.Int(лмцИзм[лцИтер]); мЛог.Ln +
- END; +
- мЛог.Ln+
  END Старт;  END Старт;
- +
 BEGIN BEGIN
-END КнигаПривет6.+END КнигаПривет7.
  
-(!)КнигаПривет6.Старт+(!)КнигаПривет7.Старт 
 +</code> 
 +  
  
-</code>   +В этом примере присваиваются значения полям ''цКоорд_Х'' и ''цКоорд_У''. В массиве ''мцЦвет'' элементам с номерами 0 и 2 также присваиваются значенияОбратите внимание, на именование полей — все они с //маленькой// буквы. В записях //могут быть// ссылки на процедуры, а процедуры //должны// именоваться с //большой// буквы (а иначе отличить одно от другого без чтения документации, либо исходных кодов — будет тяжело). Если всё сделано правильното будет получен такой вывод:
-Чтобы задать шаг, необходимо после задания числа по окончанию цикла указать ключевое слово ''BY''. В случае примера выше — это ''2''С таким шагом всё нечётные ячейки массива будут пропущеныобратите внимание на вывод работы этой программы:+
  
-  компилируется "КнигаПривет6  140   0 +  компилируется "КнигаПривет7  156   24 
-  лмцИзм[ 0]= 0 +  старый модуль КнигаПриветвыгружен 
-  лмцИзм[ 1]= 1693148453 +  5 4 
-  лмцИзм[ 2]= 10 +  4,  0,  -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. Заключение ==== +
-Итакциклы бывают трёх видов: +
-  - С условием на входеусловием на выходе (универсальный) +
-  - Целочисленный и целочисленный с произвольным шагом (для обработки массивовможет быть быстрее чем, с условием на входе/выходе) +
-  Безусловный цикл (для длительных процессов). +
- +
-И важное напоминание: неаккуратное обращение с циклами (кроме целочисленного) может обернуться "зависанием" программы.+
  
 +из которого можно сделать вывод, что //действительно// поля записи меняют свои значения.
 +==== 4. Заключение ====
 +
 +Это коротенькое введение очень важно. Так как **Компонентный Паскаль** очень сильно приспособлен под использование записей в связи с его подходом к построению программ. Пользоваться записями впереди предстоит часто.
blackbox/manual/records.1514264039.txt.gz · Последнее изменение: 2020/10/29 07:08 (внешнее изменение)