Цикъл с предварително условие е

Последователност от инструкции, предназначени за многократно изпълнение, се наричатяло на цикъл. Единичното изпълнение на тялото на цикъла се наричаитерация. Израз, който определя дали итерацията ще бъде извършена отново или цикълът ще приключи, се наричаусловие за изходилиусловие за край на цикъл(илиусловие за продължаванев зависимост от това как се интерпретира истинността му - като знак за необходимостта от прекратяване или продължаване на цикъла). Променливата, която съхранява текущия номер на итерация, се наричаброяч на итерациина цикъла или простоброяч на цикли. Цикълът не съдържа непременно брояч, броячът не трябва да бъде един - условието за излизане от цикъла може да зависи от няколко променливи, променени в цикъла, или може да се определя от външни условия (например настъпването на определено време), във втория случай броячът може изобщо да не е необходим.

Изпълнението на всеки цикъл включва първоначалната инициализация на променливите на цикъла, проверка на условието за изход, изпълнение на тялото на цикъла и актуализиране на променливата на цикъла при всяка итерация. В допълнение, повечето езици за програмиране предоставят средства за ранно прекратяване на цикъл, тоест излизане от цикъл, независимо дали условието за изход е вярно.

Видове цикли

Безусловни цикли

Понякога програмите използват цикли, изходът от които не се осигурява от логиката на програмата. Такива цикли се наричат ​​безусловни или безкрайни. Поради тяхната нетипичност, езиците за програмиране не предоставят специални синтактични средства за създаване на безкрайни цикли, следователно такива цикли се създават с помощта на конструкции, предназначени за създаване на обикновени (илиусловни) цикли. За да се осигури безкрайно повторение, проверката на условието в такъв цикъл или отсъства(ако синтаксисът позволява, както например в цикълаLOOP…END LOOPна езика Ada), или се заменя с постоянна стойност (while true do …в Pascal).

Цикл с предварително условие

Цикъл с предварително условие е цикъл, който се изпълнява, докато някое условие, определено преди началото му, е вярно. Това условие се проверявапредиизпълнението на тялото на цикъла, така че тялото може да не бъде изпълнено дори веднъж (ако условието е невярно от самото начало). В повечето процедурни езици за програмиране той се реализира от оператораwhile, следователно второто му име е цикъл while.

Цикъл с постусловие

Цикъл с постусловие е цикъл, в който условието се проверяваследизпълнението на тялото на цикъла. От това следва, че тялотовинаги се изпълнявапоне веднъж. В Pascal този цикъл се изпълнява от оператора repeat..until; в C, направете...докато.

Има разлики в интерпретацията на условието за цикъл с постусловие в различните езици. В Pascal и езиците, произлезли от него, условието на такъв цикъл се третира катоусловие за изход(цикълът завършва, когато условието е вярно, в българската терминология такива цикли се наричат ​​още “цикъл до”), а в C и неговите наследници - катоусловие за продължение(цикълът завършва, когато условието е невярно, такива цикли понякога се наричат ​​“цикъл докато”)…..

Примка от средата

Средният изходен цикъл е най-често срещаната форма на условен цикъл. Синтактично такъв цикъл се формира с помощта на три конструкции: началото на цикъла, края на цикъла и командата за излизане от цикъла. Началната конструкция маркира точката в програмата, в която започва тялото на цикъла, крайната конструкция маркира точката, в която завършва тялото. Вътре в тялото трябва да има команда за излизане от цикъла, при изпълнението на която цикълът завършва и управлението се прехвърля на оператора след конструкцията за край на цикъла.Естествено, за да може цикълът да се изпълни повече от веднъж, командата за изход не трябва да се извиква безусловно, а само когато е изпълнено условието за излизане от цикъла.

Основната разлика между този тип цикъл и тези, обсъдени по-горе, е, че частта от тялото на цикъла, разположена след началото на цикъла и преди командата за изход, винаги се изпълнява (дори ако условието за изход от цикъла е вярно при първата итерация), а частта от тялото на цикъла, разположена след командата за изход, не се изпълнява при последната итерация.

Лесно е да се види, че със среден изходен цикъл можете лесно да моделирате както цикъл на предусловие (чрез поставяне на изходния оператор в началото на тялото на цикъла), така и постусловен цикъл (чрез поставяне на изходния оператор в края на тялото на цикъла).

Някои езици за програмиране съдържат специални конструкции за организиране на цикъл с изход от средата. И така, в езика Ada конструкциятаLOOP…END LOOPи командата за изходEXITилиEXIT WHENсе използват за това:

Тук, вътре в цикъла, може да има произволен брой команди за изход от двата типа. Самите команди за изход не са фундаментално различни, обикновеноEXIT WHENсе използва, когато се проверява само условието за изход, но простоEXITсе използва, когато се излезе от цикъла в един от вариантите на сложна условна инструкция.

В езици, в които не са предоставени такива конструкции, цикълът за среден екран може да бъде моделиран с помощта на всеки условен цикъл и оператор за прекъсване на цикъл (катоbreakв C) или оператор за безусловно прескачанеgoto.

Цикъл с брояч

Цикъл с брояч е цикъл, в който някаква променлива променя стойността си от дадена първоначална стойност до крайна стойност с някаква стъпка и за всяка стойност на тази променлива тялото на цикъла се изпълнява веднъж. INповечето процедурни езици за програмиране се изпълняват от изразаfor, който определя брояча (така наречената "циклична променлива"), необходимия брой преминавания (или граничната стойност на брояча) и евентуално стъпката, в която броячът се променя. Например на езика Oberon-2 такъв цикъл изглежда така:

(тук v е броячът, b е началната стойност на брояча, e е граничната стойност на брояча, s е стъпката).

Въпросът за стойността на променлива в края на цикъл, в който тази променлива е била използвана като брояч, е двусмислен. Например, ако програма на Pascal срещне конструкция на формата:

възниква въпросът: каква стойност в крайна сметка ще бъде присвоена на променливатаk: 9, 10, 100, може би нещо друго? Ами ако цикълът приключи преждевременно? Отговорите зависят от това дали стойността на брояча се увеличава след последната итерация и дали транслаторът променя тази стойност допълнително. Още един въпрос: какво ще се случи, ако на брояча изрично се присвои нова стойност вътре в цикъла? Различните езици за програмиране се справят с тези проблеми по различни начини. При някои поведението на брояча е ясно регламентирано. В други, например в същия Pascal, езиковият стандарт не определя нито крайната стойност на брояча, нито последствията от неговата изрична промяна в цикъла, но не препоръчва изрично да се променя броячът и да се използва в края на цикъла без повторна инициализация. Програма на Pascal, която игнорира тази препоръка, може да доведе до различни резултати, когато се изпълнява на различни системи и използва различни транслатори.

Въпросът е радикално решен в езика Ada: смята се, че броячът е описан в заглавката на цикъла и просто не съществува извън него. Дори ако името на брояча вече се използва в програмата, отделна променлива се използва като брояч вътре в цикъла. Броячът е изрично забраненприсвоява произволна стойност, тя може да бъде променена само от вътрешния механизъм на оператора на цикъла. В резултат на това дизайнът

Външно подобен на горния Pascal цикъл, той се интерпретира недвусмислено: на променливатаkще бъде присвоена стойност 100, тъй като променливатаi, използвана извън този цикъл, няма нищо общо с броячаi, който се създава и модифицира вътре в цикъла. Смята се, че такова изолиране на брояча е най-удобното и безопасно: не изисква отделно описание за него и вероятността от случайни грешки, свързани със случайно унищожаване на променливи, външни за цикъла, е минимална. Ако програмистът трябва да включи цикъл с брояч в готовия код, тогава той може да не провери дали има променлива с името, което е избрал за брояч, той може да не добави описание на новия брояч към заглавната част на съответната процедура, той може да не опита да използва някой от наличните, но в момента "свободни" броячи. Той просто пише цикъл с променлива-брояч, чието име е удобно за него и може да бъде сигурен, че няма да възникне сблъсък на имена.

Цикъл с брояч винаги може да се запише като условен цикъл, преди началото на който на брояча се задава начална стойност, а условието за изход е броячът да достигне крайната стойност; в същото време към тялото на цикъла се добавя оператор за промяна на брояча на дадена стъпка. Въпреки това, специални оператори на цикъл с брояч могат да бъдат преведени по-ефективно, тъй като формализираната форма на такъв цикъл позволява използването на специални процесорни инструкции за организиране на цикли.

В някои езици, като C и други, произлизащи от него, цикълътfor, въпреки синтактичната форма на цикъл с брояч, всъщност е цикъл с предварително условие. Тоест вC цикъл конструкция:

всъщност представлява друга форма на конструктивната нотация:

Тоест, в конструкциятаforпърво се записва произволно изречение за инициализация на цикъл, след това условие за продължение и накрая някаква операция, изпълнявана след всяко тяло на цикъл (това не трябва да е промяна на брояча; може да бъде редактиране на указател или някаква напълно външна операция). За езици от този вид проблемът, описан по-горе, се решава много просто: променливата на брояча се държи напълно предвидимо и в края на цикъла запазва последната си стойност.

Вложени цикли

Възможно е да се организира цикъл вътре в тялото на друг цикъл. Такъв цикъл ще се наричавложен цикъл. Вложен цикъл по отношение на цикъла, в чието тяло е вложен, ще се наричавътрешен цикъл, и обратното, цикъл, в тялото на който има вложен цикъл, ще се наричавъншенпо отношение на вложения. Вътре във вложения цикъл друг цикъл може да бъде вложен на свой ред, образувайки следващотониво на влаганеи т.н. Броят на нивата на влагане обикновено не е ограничен.

Общият брой изпълнения на тялото на вътрешния цикъл не надвишава произведението на броя повторения на вътрешния и всички външни цикли. Например, като вземем три вложени цикъла, всеки с 10 итерации, получаваме 10 изпълнения на тялото за външния цикъл, 100 за цикъла от второ ниво и 1000 в най-вътрешния цикъл.

Един от проблемите, свързани с вложените цикли, е организирането на ранно излизане от тях. Много езици за програмиране имат оператор за прекъсване на цикъл (breakв C,exitв Turbo Pascal,lastв Perl и т.н.), но той обикновено излиза само от цикъл на нивоот където се нарича. Извикването му от вложен цикъл ще прекрати само този вътрешен цикъл, докато обхващащият цикъл ще продължи да работи. Проблемът може да изглежда пресилен, но понякога възниква при програмиране на сложна обработка на данни, когато алгоритъмът изисква незабавно прекъсване при определени условия, наличието на които може да бъде проверено само в дълбоко вложен цикъл.

Има няколко решения на проблема с излизането от вложени цикли.

  • Най-простият е да използвате оператора за безусловно прескачанеgoto, за да прескочите до точката в програмата непосредствено след вложения цикъл. Този вариант е критикуван от структурирани програмисти, както и всички конструкции, които изискват използването наgoto. Някои езици за програмиране, като Modula-2, просто нямат безусловен оператор за разклоняване и такава конструкция не е възможна в тях.
  • Алтернатива е да използвате обикновените инструменти за прекъсване на цикъла, ако е необходимо, като зададете специални флагове, които изискват незабавно завършване на обработката. Недостатъкът е сложността на кода, влошаване на производителността без никаква полза освен теоретичната "коректност" поради елиминирането наgoto.
  • Поставяне на вложен цикъл в процедура. Идеята е всички действия, които може да се наложи да бъдат прекъснати преди време, да бъдат представени като отделна процедура, а за предсрочно прекратяване да използвате командата за изход от процедурата (ако има такава в езика за програмиране). В C, например, можете да изградите функция с вложен цикъл и да организирате изхода от нея с помощта на оператораreturn. Недостатъкът е, че изборът на кодов фрагмент в процедура не винаги е логически обоснован и не всички езици имат редовни средства за ранно завършване на процедурите.
  • Възползвайте се от механизма за генериране и обработка на изключения (извънредни ситуации), който вече е наличен в повечето Java езици. В този случай, в необичайна ситуация, кодът във вложения цикъл предизвиква изключение и блокът за обработка на изключения, в който е поставен целият вложен цикъл, го улавя и обработва. Недостатъкът е, че реализацията на механизма за обработка на изключения в повечето случаи е такава, че скоростта на програмата се намалява. Вярно е, че в съвременните условия това не е особено важно: на практика загубата на производителност е толкова малка, че има значение само за много малко приложения.
  • И накрая, има специални езикови средства за излизане от вложени цикли. И така, в езика Ada, програмистът може да маркира цикъл (най-високото ниво на вложен цикъл) с етикет и да посочи този етикет в командата за ранно прекратяване на цикъла. Изходът няма да се случи от текущия цикъл, а от всички вложени цикли до маркирания включително.

Ставен цикъл