оператор break можно использовать только внутри цикла или выражения для выбора вариантов
BestProg
Содержание
Поиск на других ресурсах:
Оператор break осуществляет выход из блока фигурных скобок оператора цикла или оператора switch и передает управление следующему оператору в программе. Если используются вложенные операторы, то оператор break осуществляет выход из самого внутреннего оператора.
Общая форма оператора break следующая
2. Оператор break с меткой. Особенности применения. Ключевое слово goto
Общая форма оператора break с меткой имеет следующий вид:
где labelName – это метка, которая соответствует кодовому блоку. Кодовый блок – это набор операторов, взятых в фигурные скобки .
Если в программе встречается оператор break с меткой, то происходит переход к метке, которая должна быть реализована в программе.
Общая форма объявления метки следующая
где labelName – имя метки. Имя метки задается также как и для любого идентификатора.
Общая форма оператора continue имеет вид:
Чаще всего оператор continue вызывается при достижении некоторого условия в теле цикла.
5. Оператор continue с меткой
Оператор continue может быть реализован с меткой. В этом случае общая форма оператора continue следующая
Оператор continue можно применять только в циклах. Другими словами, оператор continue нельзя применять за пределами цикла.
7. Примеры решения задач, в которых используется оператор break
Пример 1. Определение наличия отрицательного числа в одномерном массиве.
Пример 2. Определение наличия заданного числа n в двумерном массиве размером 2*3. В данном примере оператор break вызывается два раза. Первый раз, когда нужно выйти из внутреннего цикла, в котором переменная j есть итератором. Второй раз, когда нужно выйти из внешнего цикла, в котором переменная i есть итератором.
Если двумерный массив есть большим по размеру, то использование оператора break повышает скорость выполнения цикла.
8. Пример использования оператора break с меткой
Оператор break с меткой работает так же, как и оператор goto в других языках программирования. В языке Java оператор goto не используется. Однако, ключевое слово goto зарезервировано. Вместо goto используется оператор break с меткой с некоторыми ограничениями.
Задан двумерный массив целых чисел. Определить, есть ли в массиве отрицательные элементы. Ниже приведен фрагмент кода, решающий данную задачу.
то происходит выход с обоих циклов и переход к следующему оператору программы:
то компилятор Java сгенерирует ошибку
так как в операторе break с меткой, метка может размещаться только перед циклом, в котором она используется.
9. Примеры решения задач, в которых используется оператор continue
10. Примеры решения задач, в которых используется оператор continue с меткой
11. Какие преимущества дает использование операторов break и continue в программах
Использование break и continue дает следующие преимущества:
12. Какое отличие между оператором break с меткой и оператором continue с меткой
Операторы break с меткой и continue с меткой могут использоваться только тогда, когда в программе есть вложенные циклы. Оператор break с меткой осуществляет полный выход из всех вложенных циклов. Оператор continue с меткой осуществляет выход из текущего вложенного цикла и переход к следующей итерации внешнего цикла.
Операторы break и continue — что это? Оператор break в Java
Оператор break применяется для прерывания текущей итерации (break (broke, broken) — ломать, разрывать). С его помощью происходит выход из блока фигурных скобок оператора цикла либо оператора switch с дальнейшей передачей управления следующему оператору. Если задействуются вложенные операторы, break обеспечивает выход из самого внутреннего оператора.
Общая форма оператора break (брейк) выглядит следующим образом:
Оператор break с меткой. Специфика использования. Ключевое слово goto
На практике оператор break с меткой применяется в качестве аналога оператора goto, который есть во многих языках программирования. В Java такой оператор не используется, однако само ключевое слово goto зарезервировано.
В общем виде оператор break выглядит так:
Здесь labelName — не что иное, как имя метки, соответствующее кодовому блоку. Под кодовым блоком понимается набор операторов, которые взяты в фигурные скобки < >.
Когда присутствует оператор break с меткой, осуществляется переход к метке для её реализации в программе.
В каких операторах используют оператор break?
Оператор break подходит для применения в операторе switch и во всех операторах цикла. Иными словами, break нельзя использовать за пределами цикла либо оператора switch.
Оператор continue. Общая форма и особенности применения
Оператор continue используется в циклах, обеспечивая переход в цикле к следующей итерации. Общая форма оператора выглядит соответствующим образом:
Как правило, continue вызывается в том случае, если достигнуто некоторое условие в теле цикла.
Оператор continue с меткой
Как и в случае с break, возможна реализация continue с меткой. В этом случае форма оператора будет выглядеть так:
Здесь labelName — это имя метки, соответствующей циклу, в котором как раз таки и реализован вызов посредством оператора continue.
Когда применяют оператор continue?
Оператор используют исключительно в циклах, то есть continue нельзя применять за их пределами.
Преимущества использования операторов continue и break в программах
Применение break и continue имеет следующие плюсы: — при выполнении циклического процесса отпадает необходимость осуществлять излишние итерации, если нужный результат достигнут либо искомое значение уже найдено. Всё это повышает скорость работы программного обеспечения; — в случае преждевременного прекращения циклического процесса структура кода не искажается.
Каковы отличия между break и continue при наличии метки?
Операторы continue/break с меткой используются в том случае, если в программе присутствуют вложенные циклы. При этом break с меткой обеспечивает полный выход изо всех вложенных циклов. А continue с меткой выходит из текущего вложенного цикла с последующим переходом к очередной итерации внешнего цикла.
Примеры решения задач с break
Пример 1. Давайте определим, есть ли отрицательное число в одномерном массиве:
Пример 2. Давайте найдём, есть ли заданное число n в 2-мерном массиве, размер которого 2 х 3. Здесь break вызывается дважды: 1) когда требуется выйти из внутреннего цикла, в котором переменная j является итератором; 2) когда нужно покинуть внешний цикл, где итератором является переменная i.
Очевидно, что если наш 2-мерный массив будет огромным по размеру, использование break повысит скорость выполнения циклического процесса.
Пример 3. Рассмотрим работу break с меткой. Здесь break работает так же, как и goto в других языках программирования. Как мы уже говорили, в Java это ключевое слово зарезервировано, однако вместо goto применяется оператор break с меткой и рядом ограничений.
Итак, задан 2-мерный массив целых чисел. Давайте определим, есть ли в нём отрицательные элементы:
В нашем случае перебор всех элементов 2-мерного массива производится в 2-х вложенных циклах. При этом перед вызовом циклов помещена метка M1. Если же в цикле нижнего уровня (счетчик j) встречается команда break M1, то производится выход с обоих циклов с последующим переходом к очередному оператору программы:
А вот если M1 разместить непосредственно перед оператором if:
То компилятор в Java выдаст ошибку:
А всё потому, что метка здесь может размещаться лишь перед тем циклом, в котором используется.
Использование оператора break
В Java оператор break находит три применения. Во-первых, как уже было показано, он завершает последовательность операторов в операторе switch. Во-вторых, его можно использовать для выхода из цикла. И, в-третьих, его можно использовать в качестве «цивилизованной» формы оператора безусловного перехода («goto»). Рассмотрим последние два применения.
Использование оператора break дли выхода из цикла
Используя оператор break, можно вызвать немедленное завершение цикла, пропуская условное выражение и любой остальной код в теле цикла. Когда программа встречает оператор break внутри цикла, она прекращает выполнение цикла, и управление передается оператору, следующему за циклом. Ниже показан простой пример.
// Использование оператора break для выхода из цикла.
class BreakLoop <
public static void main(String args[]) <
for(int i=0; i
Эта программа генерирует следующий вывод:
i: 0
i: 1
i: 2
i: 3
i: 4
i: 5
i: 6
i: 7
i: 8
i: 9
Цикл завершен.
Как видите, хотя цикл for должен был бы выполняться для значений управляющей переменной от 0 до 99, оператор break приводит к более раннему выходу из него, когда значение переменной i становится равным 10.
Оператор break можно использовать в любых циклах Java, в том числе в преднамеренно бесконечных циклах. Например, в предыдущей программе можно было применить цикл while. Эта программа генерирует вывод, совпадающий с предыдущим.
// Использование оператора break для выхода из цикла while.
class BreakLoop2 <
public static void main(String args[]) <
int i = 0;
while (i
В случае его использования внутри набора вложенных циклов оператор break осуществляет выход только из самого внутреннего цикла. Например:
// Использование оператора break во вложенных циклах.
class BreakLoop3 <
public static void main(String args[]) <
for (int i=0; КЗ; 1++) <
System.out.print(«Проход » + i + «: «);
for (int j=0; j
Эта программа генерирует следующий вывод:
Проход 0: 0 1 2 3 4 5 6 7 8 9
Проход 1: 0 1 2 3 4 5 6 7 8 9
Проход 2: 0 1 2 3 4 5 6 7 8 9
Циклы завершены.
Как видите, оператор break во внутреннем цикле может приводить к выходу только из этого цикла. На внешний цикл он не оказывает никакого влияния.
При использовании оператора break необходимо помнить следующее. Во-первых, в цикле можно использовать более одного оператора break. Однако при этом следует соблюдать осторожность. Как правило, применение слишком большого числа операторов break приводит к деструктуризации кода. Во-вторых, оператор break, который завершает последовательность операторов в операторе switch, оказывает влияние только на данный оператор switch, а не на какие-либо содержащие его циклы.
Помните! Оператор break не был разработан в качестве обычного средства выхода из цикла. Для этого служит условное выражение цикла. Оператор break следует использовать для выхода из цикла только в определенных особых ситуациях.
Использование оператора break в качестве формы оператора безусловного перехода
Кроме его применения с операторами switch и циклами, оператор break можно использовать и сам по себе в качестве «цивилизованной» формы оператора безусловного перехода («goto»). Язык Java не содержит оператора «goto», поскольку он позволяет выполнять ветвление программ произвольным и неструктурированным образом. Как правило, код, который управляется оператором «goto», труден для понимания и поддержки. Кроме того, этот оператор исключает возможность оптимизации кода для определенного компилятора. Однако в некоторых случаях оператор «goto» — ценная и вполне допустимая конструкция управления потоком команд. Например, оператор «goto» может быть полезен при выходе из набора вложенных циклов с большим количеством уровней. Для таких ситуаций Java определяет расширенную форму оператора break. Используя эту форму, можно, например, осуществлять выход из одного или нескольких блоков кода. Эти блоки не обязательно должны быть частью цикла или оператора switch. Они могут быть любым блоком. Более того, можно точно указать оператор, с которого будет продолжено выполнение программы, поскольку эта форма оператора break работает с метками. Как будет показано, оператор break предоставляет все преимущества оператора «goto», не порождая его проблемы. Общая форма оператора break с меткой имеет следующий вид:
Чаще всего, метка — это имя метки, идентифицирующей блок кода. Им может быть как самостоятельный блок кода, так и целевой блок другого оператора. При выполнении этой формы оператора break управление передается названному блоку кода. Помеченный блок кода должен содержать оператор break, но он не обязательно должен быть непосредственно содержащим его блоком. В частности это означает, что оператор break с меткой можно применять для выхода из набора вложенных блоков. Однако его нельзя использовать для передачи управления внешнему блоку кода, который не содержит данный оператор break.
Чтобы пометить блок, необходимо поместить метку в его начале. Метка — это любой допустимый идентификатор Java, за которым следует двоеточие. Как только блок помечен, его метку можно использовать в качестве цели оператора break. В результате выполнение программы будет продолжено с конца помеченного блока. Например, следующая программа содержит три вложенных блока, каждый из которых помечен своей меткой. Оператор break приводит к переходу к концу блока с меткой second с пропуском двух операторов println ().
// Использование оператора break в качестве цивилизованной формы оператора goto.
class Break <
public static void main(String args[]) <
boolean t = true;
first: <
second: <
third: <
System.out.println(«Предшествует оператору break.»);
if(t) break second; // выход из блока second
System.out.println(«Этот оператор не будет выполняться»);
>
System.out.println(«Этот оператор не будет выполняться»);
>
System.out.println(«Этот оператор следует за блоком second.»);
>
>
>
Эта программа генерирует следующий вывод:
Предшествует оператору break.
Этот оператор следует за блоком second.
Одно из наиболее распространенных применений оператора break с меткой — его использование для выхода из вложенных циклов. Например, в следующей программе внешний цикл выполняется только один раз:
// Использование оператора break для выхода из вложенных циклов. class BreakLoop4 <
public static void main(String args[]) <
outer: for(int i=0; i
Эта программа генерирует следующий вывод:
Проход 0: 0123456789 Циклы завершены.
Как видите, когда внутренний цикл выполняет выход во внешний цикл, это приводит к завершению обоих циклов. Следует иметь в виду, что нельзя выполнить переход к какой-либо метке, которая определена не для содержащего данный оператор break блока. Например, следующая программа содержит ошибку и поэтому ее компиляция будет невозможна:
// Эта программа содержит ошибку.
class BreakErr <
public static void main(String args[]) <
one: for(int i=0; i
Поскольку блок, помеченный меткой one, не содержит оператор break, передача управления этому внешнему блоку невозможна.
Операторы цикла в языке Си
Рассмотрим третью алгоритмическую структуру — цикл.
Циклом называется блок кода, который для решения задачи требуется повторить несколько раз.
Каждый цикл состоит из
Цикл выполняется до тех пор, пока блок проверки условия возвращает истинное значение.
Тело цикла содержит последовательность операций, которая выполняется в случае истинного условия повторения цикла. После выполнения последней операции тела цикла снова выполняется операция проверки условия повторения цикла. Если это условие не выполняется, то будет выполнена операция, стоящая непосредственно после цикла в коде программы.
В языке Си следующие виды циклов:
Цикл с предусловием while
Общая форма записи
Пример на Си : Посчитать сумму чисел от 1 до введенного k
Пример бесконечного цикла
while — цикл с предусловием, поэтому вполне возможно, что тело цикла не будет выполнено ни разу если в момент первой проверки проверяемое условие окажется ложным.
Например, если в приведенном выше коде программы ввести k=-1, то получим результат
Цикл с постусловием do. while
Общая форма записи
Использовать цикл do. while лучше в тех случаях, когда должна быть выполнена хотя бы одна итерация, либо когда инициализация объектов, участвующих в проверке условия, происходит внутри тела цикла.
Результат выполнения:
Параметрический цикл for
Общая форма записи
for — параметрический цикл (цикл с фиксированным числом повторений). Для организации такого цикла необходимо осуществить три операции:
Эти три операции записываются в скобках и разделяются точкой с запятой ; ;. Как правило, параметром цикла является целочисленная переменная.
Инициализация параметра осуществляется только один раз — когда цикл for начинает выполняться.
Проверка Условия повторения цикла осуществляется перед каждым возможным выполнением тела цикла. Когда выражение, проверяющее Условие становится ложным (равным нулю), цикл завершается. Модификация параметра осуществляется в конце каждого выполнения тела цикла. Параметр может как увеличиваться, так и уменьшаться.
Пример на Си : Посчитать сумму чисел от 1 до введенного k
Результат выполнения
В записи цикла for можно опустить одно или несколько выражений, но нельзя опускать точку с запятой, разделяющие три составляющие цикла.
Код предыдущего примера можно представить в виде
Параметры, находящиеся в выражениях в заголовке цикла можно изменить при выполнении операции в теле цикла, например
Вложенные циклы
В Си допускаются вложенные циклы, то есть когда один цикл находится внутри другого:
Пример : Вывести числа от 0 до 99, по 10 в каждой строке
Результат выполнения
Рекомендации по выбору цикла
При выборе цикла необходимо оценить необходимость проверки условия при входе в цикл или по завершении прохождения цикла.
Цикл с постусловием удобно применять в случаях, когда для проверки условия требуется вычислить значение выражения, которое затем будет размещено в теле цикла (см. выше пример ввода числа от 0 до 10).
Цикл c предусловием используется в случае если все переменные, участвующие в выражении, проверяющем условие, проинициализированы заранее, но точное число повторений цикла неизвестно или предполагается сложная модификация переменных, участвующих в формировании условия повторения цикла.
Если цикл ориентирован на работу с параметром, для которого заранее известно число повторений и шаг изменения, то более предпочтительным является параметрический цикл. Очень удобно использовать параметрический цикл при работе с массивами для перебора элементов.
Операторы прерывания и продолжения цикла break и continue
Оператор break позволяет выйти из цикла, не завершая его.
Оператор continue позволяет пропустить часть операторов тела цикла и начать новую итерацию.
Пример на Си : Вывести числа от 0 до 99 ниже главной диагонали
Результат выполнения
Пример на Си : Вывести числа от 0 до 99 исключая числа, оканчивающиеся на 5 или 8
Результат выполнения
При вложенных циклах действия операторов break и continue распространяется только на самую внутреннюю структуру, в которой они содержатся.
Оператор безусловного перехода goto
Общая форма записи
Пример на Си : Вывести все целые числа от 5 до 0.
Комментариев к записи: 24
#include
#include
const N = 4;
struct komp
<
char nazvanie[30];
int chastota_cp;
int operativa;
char nalichie_dvd[30];
int cost;
>;
setlocale(0, «» );
int count = 0;
int i;
Мысли вслух
пятница, 5 октября 2012 г.
Break или не break?
В общении с коллегами — учителями информатики — я много раз сталкивался с твёрдым убеждением, что использование оператора break для досрочного выхода из цикла — это «неграмотно», «грязный хак», «не соответствует принципам структурного программирования» и вообще «я своим ученикам такое не зачту». В то же время общение с профессиональными программистами показывает, что такой прием на практике применяется очень часто, потому что это удобно и в большинстве случаев делает программу более понятной.
Такой «разброд» имеет совершенно объяснимые причины. Большинство преподавателей, с одной стороны, когда-то заучили, что структурное программирование — это хорошо, а любое отступление от него — это плохо. С другой стороны, сами они уже фактически отошли от промышленного программирования: я могу на пальцах одной руки пересчитать знакомых (в том числе и по Интернету) учителей информатики, которые сами написали что-то стóящее. Таким образом, наблюдаем закон Дж.Б. Шоу в действии.
Попробуем разобраться в сути вещей. Оператор break — это фактически оператор перехода, знаменитый GOTO, который в 1970-е годы был морально уничтожен, прежде всего, стараниями «отца структурного программирования» Эдсгера Дейкстры [1]. Однако сами «отцы» хорошо понимали, что программа без GOTO ещё не становится автоматически структурной программой. Поэтому появилось на свет эссе Дональда Кнута «Структурное программирование с операторами GOTO» [2]. Кнут писал (перевод мой):
«Другими словами, мы не должны просто удалять операторы GOTO из-за того, что сейчас модно это делать; присутствие или отсутствие операторов GOTO — это не главный вопрос. Истинная цель состоит в том, чтобы формулировать наши программы таким образом, чтобы их было легко понимать.»
Посмотрим, как обстоит дело с пониманием программ, содержащих циклы с операторами break и сравним их с программами, где операторов break умышленно избегают.
Пример 1. С клавиатуры вводятся числа, ввод заканчивается числом 999. Вычислить сумму введенных чисел.
Вот решение с использованием break:На взгляд автора, этот алгоритм очень хорошо соответствует словесному описанию: «строим цикл, выход из которого происходит при получении числа 999».
Теперь посмотрим на «кошерные» альтернативы. Нужно как-то выполнить те же действия (то есть, выйти из цикла при получении числа 999), не используя оператор выхода из цикла.
Во-первых, можно поставить условие цикла x <> 999, но при этом нужно будет инициализировать переменную x до цикла каким-то «магическим числом», отличным от 999, например, 1 (или 998 :-). Программист, который будет разбираться в таком коде через некоторое время, спасибо вам не скажет. Кроме того, вторую часть тела цикла придется взять в условный оператор, а эта вторая часть может быть достаточно большой. Читабельность явно не повышается. Зато программа «структурная», можно «взять с полки пирожок». :-)Заметим, что число 999 появляется в программе дважды: в заголовке цикла и в условии в теле цикла, что само по себе уже нехорошо.
Можно вынести оператор Readln за цикл, продублировав его в теле цикла:На взгляд автора, при этом два оператора ввода, выполняющие одну и ту же функцию, «размывают» логику программы и не добавляют ей «прозрачности». Кроме того, вместо Readln в других ситуациях может стоять целая группа операторов, и тут уже дублирование будет выглядеть совсем некрасиво.
Кроме того, можно ввести логическую переменную (флаг), которой присваивается истинное значение при получении числа 999:Но тут нужно вспомнить о «бритве Оккама» — не плоди лишних сущностей. И ещё — любое усложнение системы, как правило, снижает её надежность.
Еще один вариант — перейти на цикл с постусловием:Во-первых, как и в одном из предыдущих вариантов, здесь два раза всплывает число 999. Во-вторых, вторую часть тела цикла снова нужно помещать в условный оператор. В-третьих, читать программы с циклами repeat — это сущее наказание: встретив слово repeat, судорожно пытаемся найти соответствующий until с условием, без этого всё вообще непонятно. Потом опять нужно смотреть наверх: что же там в теле цикла.
Можно, конечно, и так :-):Но по сути это то же самое, что и break. Использовать здесь исключения — всё равно, что гвозди микроскопом забивать.
Рассмотрим еще один пример.
Пример 2. Найти в массиве A[1..N] элемент, равный X, или сообщить, что такого элемента нет.
Решение с помощью break:Как и для первого примера, программа с break почти дословно повторяет словесное описание идеи решения: «просматриваем все элементы массива с первого до последнего; как только нашли нужный элемент, запоминаем его номер и выходим из цикла».
Вот альтернатива без break:Теперь представим себе, что будет, если в трансляторе включена проверка выхода за границы массива, логические выражения вычисляются полностью и элемента, равного X, в массиве нет: программа вылетит в результате обращения за пределы массива.
Вот еще вариант, с логической переменной:Какая программа понятнее, каждый решает сам. 🙂
«Классическое» решение выглядит так:Вроде бы всё хорошо. Но мы потеряли «локальность»: при достаточно длинном теле условного оператора нужно еще «сканировать» цикл до конца, проверяя, не выполняются ли какие-то действия в том случае, когда x <> 1. А эту проблему может элегантно решить continue:Здесь уже точно ясно, что при x <> 1 никаких дополнительных операций не происходит. По мнению автора, такой вариант более «прозрачен» и, по крайней мере, не хуже предыдущего.
Остается еще один «смежный» вопрос: можно ли писать подпрограммы с несколькими выходами? Давайте посмотрим пример рекурсивной процедуры.
Пример 4. Разработать процедуру, которая выводит на экран решение задачи «Ханойская башня» [4].
Рекурсивное решение этой задачи хорошо известно, одна из реализаций выглядит так:Здесь n — количество дисков, которые нужно перенести; k — номер начального стержня и m — номер конечного стержня.
И все было бы хорошо, но тут нарушен ещё один принцип, который стал «священной коровой» ортодоксального структурного программирования: процедура имеет (увы 🙂 два выхода, один естественный, и второй — по признаку окончания рекурсии.
Можно ли было обойтись без этого? Да, можно, «упаковав» все тело процедуры внутрь условного оператора:Но тут мы опять теряем локальность — при достаточно длинном тексте процедуры нужно еще посмотреть, не выполняются ли какие-то действия после условного оператора. Да и не совсем понятно, зачем добавлять лишний уровень вложенности. «Не плоди лишних сущностей». По мнению автора, первое приведенное решение более понятное и более красивое.
Пример 5. Разработать функцию, которая определяет, если ли в квадратной матрице элемент, равный заданному значению.
Будем предполагать, что введен тип данныхТогда функцию можно написать так:Здесь оператор exit фактически выполняет роль break для вложенного цикла. С формальной точки зрения у функции два выхода. В общем, «я своим ученикам никогда такое не зачту» — уже слышу я от учителей информатики.
А давайте подумаем, какие альтернативы? Можно вот так:Но тут вообще «криминал» — метка и goto! Хотя по сути ничего не изменилось, тот же выход из вложенного цикла.
Конечно, здесь можно использовать исключение:Но ведь это далеко не «исключительная ситуация», поэтому по смыслу исключения здесь всё-таки не особо уместны. Кроме того, нужно учитывать, что при обработке исключений выполняется большое число машинных команд, что снижает эффективность программы.
Любителей «чистого» структурного программирования наверняка устроит такой вариант решения:Но, к сожалению, по эффективности он не может составить конкуренцию предыдущим, так как в любом случае рассматриваются все N 2 элементов массива, даже если элемент A[1,1] равен X.
Эта статья, прежде всего, о том, что любые идеи и принципы нужно воспринимать в контексте конечной цели. Одна из основных целей концепции структурного программирования — повысить читаемость программ и за счёт этого облегчить их отладку, тестирование и сопровождение. Поэтому применение операторов break, continue и exit нельзя считать отступлением от структурного программирования, если это не ухудшает читаемость программы и не приводит к запутыванию логики алгоритма.
В то же время попытки избавиться от этих операторов (для того, чтобы формально соблюсти «классические правила») могут привести к ухудшению читаемости программы.
Комментарии: 23:
По моему опыту, брейк совершенно незаменим в случае, если нужно обработать исключительную ситуацию в схемах большой вложенности. Он существенно повышает читаемость в тех местах, где использование try except finally не критично.
Я вот усугублю: найти элемент в матрице:
IsFound := False;
for i:=1 to n do
for j:=1 to n do
if a[i,j]=x then
begin
IsFound := True;
goto en;
end;
en:
Предложите лучший вариант 🙂
>> Предложите лучший вариант 🙂
Попробую. 🙂
type matr = array[1..N,1..N] of integer;
function FindMatr(A: matr; X: integer): boolean;
var i, j: integer;
begin
Result := True;
for i:=1 to N do
for j:=1 to N do
if A[i,j] = X then Exit;
Result := False;
end;
Да нет, это ведь то же самое! Фактически, в данном случае Exit = break из вложенного цикла. Или GOTO, который вы предложили применить.
Это я неудачно шучу так. Просто без exit и goto этот пример вообще безобразно программируется.
По поводу continue — это ведь тот же goto. Думаю, что вот этот случай оправдывает его использование, если T — достаточно большой блок операторов:
for i:=1 to N do begin
x := S(. );
if not Good(x) then continue;
T;
end;
Вопрос серьёзный: без break можно обойтись, но как обойтись без обработки исключений?
Решение первой задачи без Break:
s := 0;
Readln(x);
while x<>999 do begin
s := s + x;
Readln(x);
end;
> Решение первой задачи без Break:
Я знаю про это решение, но мне очень не нравится, что дважды используется оператор Readln. Это «размазывает» логику и делает программу менее понятной.
> как обойтись без обработки исключений?
Теоретически можно. Раньше ведь обходились, до начала 90-х. Коды возврата из функций.
Возвращаясь к решению первой задачи без Break: мне, напротив, это решение кажется наиболее логичным, естественным, поскольку в заголовке цикла сформулировано простое и понятное условие завершения, а Readln(x)перед циклом можно сравнить с инициализацией счетчика, которую мы делаем при замене цикл for на while
> Возвращаясь к решению первой задачи без Break: мне, напротив, это решение кажется наиболее логичным
Это дело вкуса, конечно. Да и речь, собственно, не о том. Мысль состоит в том, что решение с break, по крайней мере, ничем не хуже решения без break, и часто выглядит значительно понятнее. Вместо того же Readln могут быть совершенно другие операторы.
О первой задаче. А если так:
s:=0;
x:=0;
while x<>999 do
begin
s := s+x;
Readln(x)
end;
> О первой задаче. А если так:
Это ведь тоже искусственно. При чтении кода сразу возникает вопрос: «А почему в x записываем 0»? И потом: «А почему еще ничего не ввели, а уже суммируем?»
Понятность повышается? Нет.
To break or not to break. 🙂
Я бы немного переформулировал Кнута. Думаю, есть определенная неточность перевода с английского. Простота (simplicity) это в смысле программирования скорее «очевидность».
По возможности, нужно избавить программы от неочевидных и нестандартных ходов, пусть даже это и рождает некоторый оверхед в плане объема кода или его оптимальности.
Давно хотел спросить, хотя это и не очень в теме этого поста. Что вы думаете об использовании в обучении программированию сред типа Squeak (Smalltalk)? Если отвлечься от методических требований, конечно.
На эту тему:
http://www.oberoncore.ru/wiki/%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BF%D1%80%D0%BE%D0%BC%D1%8B%D1%88%D0%BB%D0%B5%D0%BD%D0%BD%D0%BE%D0%B3%D0%BE_%D1%86%D0%B8%D0%BA%D0%BB%D0%B0
В конце статьи разобраны убедительные аргументы против брейка (о том, КАК думает программист, привыкший анализировать свойства программы в терминах утверждений и почему такому программисту очень не хочется читать цикл построчно в поисках брейка и «гонять его в уме»).
Также в эту тему статья «Базовые паттерны циклов»:
http://www.oberoncore.ru/wiki/%D0%BF%D0%B0%D1%82%D1%82%D0%B5%D1%80%D0%BD%D1%8B_%D1%86%D0%B8%D0%BA%D0%BB%D0%BE%D0%B2
Потому что стоит заметить, что такая инструкция выполняется n+1 раз, в отличие от остальных, которые выполняются n раз. И совершенно логично такой дополнительный раз вынести за цикл.
Это же касается циклов в духе:
for.
.
if НАШЛИ then
что-то делаем; break
end if
end for
Никого не коробит, что внутри цикла оказалось однократное действие, которое, вообще-то, должно находится логичным образом после цикла? 🙂
Всё это, мне кажется, от недостаточного внимания к логическим свойствам программ. От отношения к ним, как «литературному произведению». «Лишь бы машина понимала». Более продвинутое: «ну и лишь бы читателям потом тоже было нормально». Но никто не доходит до «лишь бы обладало понятными, гарантированными, доказуемыми свойствами».
Но, Константин Юрьевич, Вы же сами привели чистый классический вариант линейного поиска (который обязан знать и использовать любой образованный программист, имхо):
[ЦИТАТА]
Вот альтернатива без break:
nX := 1;
while (nX X) do
Inc(nX);
if nX > N then
writeln(‘Не нашли!’)
else writeln(‘nX = ‘, nX);
[/ЦИТАТА]
С уважением.
Простите за некоторый «напор», но на Вас большая ответственность, потому что Вас читают многие-многие 🙂
а как с постусловием решить это? Дан массив действительных чисел. Среди них есть равные. Найти первый max элемент и заменить ТОЛЬКО его нулем. Подробно, если не сложно. Заранее преблагодарен.
> Дан массив действительных чисел. Среди них есть равные.
> Найти первый max элемент и заменить ТОЛЬКО его нулем.
Зачем тут цикл с условием? Почему не так:
nMax := 1;
for i:=1 to N do
if A[i] > A[nMax] then
nMax := i;
A[nMax] := 0;
Подпишитесь на каналы Комментарии к сообщению [Atom]
Константин Поляков Санкт-Петербург