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

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


blackbox:manual:records

Различия

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

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

Предыдущая версия справа и слева Предыдущая версия
blackbox:manual:records [2018/11/30 01:13]
127.0.0.1 внешнее изменение
blackbox:manual:records [2019/01/02 17:55] (текущий)
иван_денисов
Строка 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.txt · Последние изменения: 2019/01/02 17:55 — иван_денисов