Что такое оператор перехода
Операторы перехода
Язык C# предлагает несколько операторов, позволяющих немедленно перейти на другую строку программы. Давайте их рассмотрим.
Оператор goto
Имеющийся в C# оператор goto представляет собой оператор безусловного перехода. Когда в программе встречается оператор goto, ее выполнение переходит непосредственно к тому месту, на которое указывает этот оператор. Он уже давно «вышел из употребления» в программировании, поскольку способствует созданию «макаронного» кода. Хотя в некоторых случаях он оказывается удобным и дает определенные преимущества, если используется благоразумно. Главный недостаток оператора goto с точки зрения программирования заключается в том, что он вносит в программу беспорядок и делает ее практически неудобочитаемой. Но иногда применение оператора goto может, скорее, прояснить, чем запутать ход выполнения программы.
Для выполнения оператора goto требуется метка — действительный в C# идентификатор с двоеточием. Метка должна находиться в том же методе, где и оператор goto, а также в пределах той же самой области действия.
Пример использования оператора goto:
Репутация оператора goto такова, что в большинстве случаев его применение категорически осуждается. Вообще говоря, он, конечно, не вписывается в рамки хорошей практики объектно-ориентированного программирования.
Оператор break
С помощью оператора break можно специально организовать немедленный выход из цикла в обход любого кода, оставшегося в теле цикла, а также минуя проверку условия цикла. Когда в теле цикла встречается оператор break, цикл завершается, а выполнение программы возобновляется с оператора, следующего после этого цикла. Оператор break можно применять в любом цикле, предусмотренном в C#.
Обратите внимание если оператор break применяется в целом ряде вложенных циклов, то он прерывает выполнение только самого внутреннего цикла.
В отношении оператора break необходимо также иметь в виду следующее. Во-первых, в теле цикла может присутствовать несколько операторов break, но применять их следует очень аккуратно, поскольку чрезмерное количество операторов break обычно приводит к нарушению нормальной структуры кода. И во-вторых, оператор break, выполняющий выход из оператора switch, оказывает воздействие только на этот оператор, но не на объемлющие его циклы.
Оператор continue
С помощью оператора continue можно организовать преждевременное завершение шага итерации цикла в обход обычной структуры управления циклом. Оператор continue осуществляет принудительный переход к следующему шагу цикла, пропуская любой код, оставшийся невыполненным. Таким образом, оператор continue служит своего рода дополнением оператора break.
В циклах while и do-while оператор continue вызывает передачу управления непосредственно условному выражению, после чего продолжается процесс выполнения цикла. А в цикле for сначала вычисляется итерационное выражение, затем условное выражение, после чего цикл продолжается:
Оператор continue редко находит удачное применение, в частности, потому, что в C# предоставляется богатый набор операторов цикла, удовлетворяющих большую часть прикладных потребностей. Но в тех особых случаях, когда требуется преждевременное прерывание шага итерации цикла, оператор continue предоставляет структурированный способ осуществления такого прерывания.
Оператор return
Оператор return организует возврат из метода. Его можно также использовать для возврата значения. Имеются две формы оператора return: одна — для методов типа void, т.е. тех методов, которые не возвращают значения, а другая — для методов, возвращающих конкретные значения.
Для немедленного завершения метода типа void достаточно воспользоваться следующей формой оператора return:
Когда выполняется этот оператор, управление возвращается вызывающей части программы, а оставшийся в методе код пропускается.
Для возврата значения из метода в вызывающую часть программы служит следующая форма оператора return:
Давайте рассмотрим применение оператора return на конкретном примере:
Оператор перехода
Оператор return
Оператор return используется для выхода из функции. Отнесение его к категории операторов перехода обусловлено тем, что он заставляет программу перейти в точку вызова функции. Оператор return может иметь ассоциированное с ним значение, тогда при выполнении данного оператора это значение возвращается в качестве значения функции. В функциях типа void используется оператор return без значения.
Общая форма оператора return следующая:
Выражение присутствует только в том случае, если функция возвращает значение. Это значение выражения становится возвращаемым значением функции.
Оператор goto
Оператор break
Оператор break применяется в двух случаях. Во-первых, в операторе switch с его помощью прерывается выполнение последовательности case (см. раздел «Оператор выбора — switch» ранее в этой главе). В этом случае оператор break не передает управление за пределы блока. Во-вторых, оператор break используется для немедленного прекращения выполнения цикла без проверки его условия, в этом случае оператор break передает управление оператору, следующему после оператора цикла.
Оператор break часто используется в циклах, в которых некоторое событие должно вызвать немедленное прекращение выполнения цикла. В следующем примере нажатие клавиши прекращает выполнение функции look_up() :
Библиотечная функция kbhit() возвращает 0, если клавиша не нажата (то есть, буфер клавиатуры пуст), в противном случае она возвращает ненулевое значение. В стандарте С функция kbhit() не определена, однако практически она поставляется почти с каждым компилятором (возможно, под несколько другим именем).
Оператор break вызывает выход только из внутреннего цикла. Например, программа
Функция exit()
Общая форма функции exit() следующая:
Функция exit() часто используется, когда обязательное условие работы программы не выполняется. Рассмотрим, например, компьютерную игру в виртуальной реальности, использующую специальный графический адаптер. Главная функция main() этой игры выглядит так:
Здесь virtual_graphics() возвращает значение ИСТИНА, если присутствует нужный графический адаптер. Если требуемого адаптера нет, вызов функции exit(1) прекращает работу программы.
В следующем примере в новой версии ранее рассмотренной функции menu() вызов exit() используется для выхода из программы и возврата в операционную систему:
Оператор continue
Каждый символ строки сравнивается с пробелом. Если сравниваемый символ не является пробелом, оператор continue передает управление в конец цикла for и выполняется следующая итерация. Если символ является пробелом, значение переменной space увеличивается на 1.
В следующем примере оператор continue применяется для выхода из цикла while путем передачи управления на условие цикла:
[1] Уже одно это (чрезмерная вложенность и неожиданный выход сразу из нескольких циклов) может свидетельствовать о плохой структуре программы.
Оператор перехода
Оператор return
Оператор return используется для выхода из функции. Отнесение его к категории операторов перехода обусловлено тем, что он заставляет программу перейти в точку вызова функции. Оператор return может иметь ассоциированное с ним значение, тогда при выполнении данного оператора это значение возвращается в качестве значения функции. В функциях типа void используется оператор return без значения.
Общая форма оператора return следующая:
Выражение присутствует только в том случае, если функция возвращает значение. Это значение выражения становится возвращаемым значением функции.
Оператор goto
Оператор break
Оператор break применяется в двух случаях. Во-первых, в операторе switch с его помощью прерывается выполнение последовательности case (см. раздел «Оператор выбора — switch» ранее в этой главе). В этом случае оператор break не передает управление за пределы блока. Во-вторых, оператор break используется для немедленного прекращения выполнения цикла без проверки его условия, в этом случае оператор break передает управление оператору, следующему после оператора цикла.
Оператор break часто используется в циклах, в которых некоторое событие должно вызвать немедленное прекращение выполнения цикла. В следующем примере нажатие клавиши прекращает выполнение функции look_up() :
Библиотечная функция kbhit() возвращает 0, если клавиша не нажата (то есть, буфер клавиатуры пуст), в противном случае она возвращает ненулевое значение. В стандарте С функция kbhit() не определена, однако практически она поставляется почти с каждым компилятором (возможно, под несколько другим именем).
Оператор break вызывает выход только из внутреннего цикла. Например, программа
Функция exit()
Общая форма функции exit() следующая:
Функция exit() часто используется, когда обязательное условие работы программы не выполняется. Рассмотрим, например, компьютерную игру в виртуальной реальности, использующую специальный графический адаптер. Главная функция main() этой игры выглядит так:
Здесь virtual_graphics() возвращает значение ИСТИНА, если присутствует нужный графический адаптер. Если требуемого адаптера нет, вызов функции exit(1) прекращает работу программы.
В следующем примере в новой версии ранее рассмотренной функции menu() вызов exit() используется для выхода из программы и возврата в операционную систему:
Оператор continue
Каждый символ строки сравнивается с пробелом. Если сравниваемый символ не является пробелом, оператор continue передает управление в конец цикла for и выполняется следующая итерация. Если символ является пробелом, значение переменной space увеличивается на 1.
В следующем примере оператор continue применяется для выхода из цикла while путем передачи управления на условие цикла:
[1] Уже одно это (чрезмерная вложенность и неожиданный выход сразу из нескольких циклов) может свидетельствовать о плохой структуре программы.
Операторы переходов – язык программирования Си
Данная категория операторов применяется относительно редко. К их числу относятся: «break», «continue», «goto» и «return». Считается, что слишком частое использование операторов переходов ухудшает читаемость программы и затрудняет её модификацию. Но, все же, бывают моменты, когда без операторов, организующих переходы, — «как без воды».
Оператор «break» (в переводе с англ. «прерывать»).
Этот старый знакомый уже встречался при изучении оператора «switch» на Рис. 6.22, б, в. Именно он организовывал досрочный выход из процедуры множественного сравнения «кейсов».
Оператор «break» в одиночку бесполезен. Его надо вводить внутрь тела одного из четырёх операторов: «switch», «while», «do-while», «for». При помощи оператора «break» досрочно прерывается выполнение основного цикла и пропускаются оставшиеся команды, после чего управление передаётся вниз к самому первому оператору после закрывающей фигурной скобки.
Если оператор «break» находится внутри нескольких вложенных друг в друга циклов, то его действие распространяется только на внутренний цикл, т.е. на тот, в котором он содержится. Именно из-за этого нюанса у программистов возникают трудности и ошибки при отлаживании больших по объёму листингов.
Интересное наблюдение. Оператор «break» является абсолютно прозрачным по отношению к операторам выбора «if» и «if-else». Он беспрепятственно «проходит» сквозь их фигурные скобки, что надо учитывать на практике.
Оператор «continue» (в переводе с англ. «продолжать»).
Сфера применения оператора «continue» меньше, чем у оператора «break». Он работаетлишь с тремя циклами: «while», «do-while», «for» и является прозрачным для операторов «if», «if-else». Главное различие между «continue» и «break» заключается в том, что вместо досрочного завершения цикла осуществляется досрочное завершение текущей итерации с пропуском оставшихся команд. Это более мягкое условие, не приводящее сразу к окончанию цикла (Рис. 6.26, а, б).
Рис. 6.26. Сравнение циклов «for»: а) с оператором «continue»; б) с оператором «break». Оператор «goto» (в переводе с англ. «перейти к»).
Оператор «goto» состоит из двух частей — ключевого слова «goto» и метки. Имена меток образуются по тем же правилам, что и имена переменных. Например, при выполнении оператора «goto metka;» управление передаётся на тот оператор, в начале которого слева указано ключевое слово «metka:». Оно может находиться влюбом, самом неожиданном месте программы. При этом не обращается внимание ни на вложенные циклы, ни на условия проверки, ни на незавершённые вычисления. Переход производится напрямую в любую строку программы, причём без задержек во времени и без окончания текущих операций.
Вот тут-то и кроется «терра инкогнита» для начинающих программистов, поскольку надо иметь большой опыт, чтобы учесть все последствия, возникающие после выхода из прерванной процедуры при неизвестно чем заполненном стеке и загадочном состоянии регистров специальных функций.
Чтобы избежать путаницы, разработаны стандартные приёмы, которые позволяют заменить все без исключения конструкции «goto» связками обычных Сператоров. Конкретные примеры приведены в 6. Родоначальники языка Си, Б.Керниган и Д.Ритчи, тоже призывают применять оператор «goto» как можно реже или не применять его совсем 6.
Существует лишь один частный случай, когда оператор «goto» полезен — это быстрый выход из многократно вложенных циклов при обнаружении каких-либо аварийных или внештатных ситуаций. Оператор «break» здесь пасует, поскольку даёт возможность выхода только из самого внутреннего цикла, а вот оператор «goto» — из любого, в том числе из бесконечного.
На Рис. 6.27, а, б показаны каркасы программ, моделирующие безусловные переходы вверх и вниз. В каком бы глубоком цикле не находился оператор «goto», управление будет сразуже передано на метку «sl:» (имя выбирается произвольно). Если метка указывает на первый оператор программы, то произойдёт «мягкий» сброс MK. В этом случае разработчику надо предусмотреть начальную инициализацию всех без исключения используемых в программе регистров специальных функций и чёткую установку всех задействованных по схеме линий портов.
Рис. 6.27. Форма записи оператора «goto»: а) с переходом вверх; б) с переходом вниз.
В языке Basic тоже существует оператор «GO ТО», причём применяется он настолько часто, что листинги программ аж пестрят прямыми переходами. В языке Си, наоборот, от «goto» стараются избавляться разными способами. Очевидно, что любителям Basic придётся адаптироваться к такому стилю программирования.
Оператор «return» (в переводе с англ. «возвращаться»).
Этот оператор несколько обособлен от своих сородичей, поскольку применяется без ограничений. Его роль — организация корректного выхода из функций. Именно о них и пойдёт речь дальше.
Источник: Рюмик, С. М., 1000 и одна микроконтроллерная схема. Вып. 2 / С. М. Рюмик. — М.:ЛР Додэка-ХХ1, 2011. — 400 с.: ил. + CD. — (Серия «Программируемые системы»).
Операторы перехода в программном коде: использовать или нет?
Со времен «старой школы» существует мнение, что структурное программирование — это хорошо, а любое отступление от него — это плохо. Однако, общение с профессиональными программистами показывает, что использование операторов break, continue, return на практике применяется довольно часто, потому что это удобно и в большинстве случаев делает программу более понятной. Если взять код типовой конфигурации от компании 1С и немного покопаться, то встречаются эти оба подхода вперемешку (предположу, что писали разные люди в разные временные промежутки).
И действительно Дональд Кнут в свое время писал:
«… Настоящая цель программиста состоит в том, чтобы формулировать наши программы таким образом, чтобы их было легко понимать.»
Давайте рассмотрим примеры использования и не использования этих операторов и сравним.
1. Оператор Перейти (GoTo).
Это совсем дурной тон и его использовать не будем). Однако интересно было бы услышать ваши мысли, возможно в сообществе еще есть «староверцы».
2. Оператор Возврат (Return).
Давайте рассмотрим некоторый виртуальный пример. Задача будет следующая: Требуется написать функцию получения математическое ожидание покупок клиента или средний чек.
Какие выводы мы можем сделать из двух вышеуказанных примеров?
3. Оператор Прервать (Break)
Один из самых востребованных операторов, если рассмотреть программирование на C++. В свое время я часто его использовал в связке с Switch и Операторах цикла (For, While). Обратите внимание, что оператор «Прервать» может использоваться и для выхода из бесконечного цикла.
Рассмотрим вариацию типового примера для подключения к клиенту тестирования механизма автоматизированного тестирования от 1С.
Какие отличия мы видим?
4. Оператор Продолжить (Continue)
Оператор «Продолжить» (continue) позволяет сразу перейти в конец тела цикла, пропуская весь код, который находится под ним. Это полезно в тех случаях, когда мы хотим завершить текущую итерацию раньше времени.
Будьте осторожны при использовании оператора «Продолжить» с циклом «Пока» (while). Поскольку в этих циклах инкремент счетчиков выполняется непосредственно в теле цикла, то использование «Продолжить» может привести к тому, что цикл станет бесконечным!
В таблице хранится наименование контрагента и некоторые дополнительные данные (сумма и т.п.). В рамках обработки будем искать ссылку на контрагента в базе данных, если данные битые, то будем пропускать поиск.
Процедура «НайтиСсылкуПоНаименованию» ищет ссылку контрагента в базе 1С.
Функция «ЭтоБитыеДанные» проверяет наличие «кривой» информации в полях Сумма, КонтрагентНаименование.
Как видно, то в результате необдуманного выбора оператора цикла, установки счетчика и размещения условия прервать, мы уйдем в бесконечный цикл. Лучше переписать так:
Теперь рассмотрим вариант без использования оператора «Продолжить».
5. Операторы прервать и продолжить
Многие учебники рекомендуют не использовать операторы «Прервать» (break) и «Продолжить» (continue), поскольку они приводят к произвольному перемещению точки выполнения программы по всему коду, что усложняет понимание и следование логике выполнения такого кода.
Тем не менее, разумное использование операторов «Продолжить» и «Прервать» может улучшить читабельность циклов в программе, уменьшив при этом количество вложенных блоков и необходимость наличия сложной логики выполнения циклов.
Например, рассмотрим следующую задачу: Требуется провести некоторую обработку данных после загрузки из таблицы Excel и еще будет считать баланс. В случае ошибки нужно выдать сообщение оператору о неконсистентности этих данных.
Функция «ЭтоБитыеДанные» проверяет наличие «кривой» информации в полях Сумма, Контрагент.
Рассмотрим результат сравнения:
Заключение
Я считаю, что использование или не использование операторов зависит от ситуации. В некоторых случаях- это позволяет существенно упростить написание и понимание кода. Однако, в некоторых случаях небрежное или «слепое» использование операторов переходов может привести к нежелательным последствиям.