В.Г. Абрамов, Н.П. Трифонов, Г.Н. Трифонова - Введение в язык Паскаль (1107618), страница 23
Текст из файла (страница 23)
Все метки операторов в данной программе должныбыть различны. Все операторы, являющиеся преемниками каких-либооператоров перехода, должны быть помечены.Примеры помеченных операторов:25:i:=0642:-for i : = 1 to 20 do y:=y*xOs if x > y then begin r : =x ; x : = y ; у: =r endОператор перехода определяется следующим образом:(оператор перехода):: = goto (метка)где goto (перейти к) — основной символ языка.Оператор перехода указывает, что далее должен выполняться оператор,помеченный указанной в операторе перехода меткой.В паскале имеются определенные ограничения на использование операторов перехода: с помощью этого оператора запрещается осуществлятьпереход внутрь любого производного оператора, а также переходить с одной альтернативы на другую в выбирающем операторе (в частности, в условном операторе).Примеры операторов перехода:goto 25goto 672Напомним, что все метки, которыми помечены операторы в даннойпрограмме, должны быть объявлены (описаны) в разделе меток этойпрограммы, например:label 25,0,672(порядок перечисления меток здесь безразличен).
При этом в разделеметок не должны присутствовать описания меток, которые фактическине используются в качестве меток операторов.Вообще говоря, оператор перехода вместе с условным операторомявляется наиболее универсальным средством управления порядком выполнения других основных операторов. В частности, любой циклическийпроцесс, задаваемый каким-либо оператором цикла, может быть заданбез использования операторов цикла. Например, фрагмент программыwhile В do S, SIэквивалентен последовательности операторов22: if not (В) them goto 26;S; goto 22;26: SI85хотя такая запись более громоздка и менее наглядна.Следует, однако, иметь в виду, что использование операторов перехода(а особенно злоупотребление ими) обычно ухудшает наглядность программы, затрудняет ее понимание и проверку, а тем самым снижает и еенадежность.
Поэтому можно высказать рекомендацию не использоватьоператоры перехода без особой на то необходимости (подробнее об этомбудет говориться в гл. 5 ) .В связи с этой рекомендацией у читателя может возникнуть вопрос —а зачем же тогда в паскале предусмотрен оператор перехода?Дело в том, что — к а к об этом уже говорилось ранее — при разработкеэтого языка должное внимание уделялось возможности получения достаточно эффективных программ.
Операторы перехода как раз и позволяютв некоторых случаях повысить эту эффективность. В качестве иллюстрации сказанному рассмотрим следующую задачу.Пусть во входном файле input задано целое п (п > 0 ) , за которым следует п вещественных чисел. Требуется найти сумму s последовательныхвещественных чисел из этого файла, предшествующих первому по порядкуотрицательному числу, а если такового числа не найдется, то сумму всехзаданных п чисел; при л = 0 принять s = 0Общий ход решения этой задачи очевиден: предварительно положимs = 0 и прочтем из файла значение п, а затем в цикле будем читать из файлаочередное вещественное число (если оно там имеется), и если это числонеотрицательно, будем прибавлять его к текущему значению s. Этот циклический процесс должен завершиться в двух случаях: либо просуммированы все п чисел, либо из файла было прочитано отрицательное число.Поскольку процесс носит циклический характер, то для его задания естественно использовать операторы цикла.
Какой же вид оператора цикла следует здесь использовать?Очевидно, что оператор цикла с параметром в данном случае, вообщеговоря, неудобен, так как число повторений заранее неизвестноведьотрицательное число может быть прочитано в любой момент. Операторцикла с постусловием тоже непосредственно использовагй нельзя, поскольку при п = 0 действия, предусмотренные в цикле, вообще не должнывыполняться. В случае же оператора цикла с постусловием, как мы знаем,цикл заведомо будет выполняться хотя бы один раз, что может привестик попытке чтения из файла несуществующего в нем числа.Следовательно, придется воспользоваться оператором цикла с предусловием. Как же сформулировать это предусловие? Поскольку количествообрабатываемых чисел не должно быть больше и, то придется ввести в употребление целочисленную переменную (например / ) , которая будет выполнять роль счетчика обработанных чисел.
Однако алгоритм решения рассматриваемой задачи, записанный в виде (г — вспомогательная вещественнаяпеременная)s:=0;i:=0;while i*n do begin read(r);i-f r>0 then s: =s+r; i : =i+ 1 endswri teln(s)неверен — ведь после ввода отрицательного числа выполнение оператора86цикла должно быть завершено Поэтому в предусловии необходимо проверять знак очередного прочитанного в цикле числа (значения г):s:=0;i:=0;while<iand<r>0>dobegin read<r);if r>0 then s:=s+r;i:=i +1 end;writeln(s)На самом деле этот алгоритм тоже ошибочен, ибо при первой проверкепредусловия значение г оказывается неопределенным — это значение определяется лишь при выполнении составного оператора, входящего в составоператора цикла. Чтобы устранить эту неопределенность, придется переменной г предварительно присвоить некоторое искусственное значение —так, чтобы при п Ф 0 не препятствовать первому выполнению тела цикла(т.е.
это значение должно быть неотрицательным) :з: =0; i : =0; г : =0. 5;while<i*n)and(r>0)dobegin read(r);if r>0 then s:=s+r;i:=i +1 end;wr i tel n (s)Как видно, в данной задаче использование операторов цикла вызвалоопределенные трудности, да и программа получилась не очень эффективной: в ней пришлось предусмотреть вспомогательный оператор присваивания г: =0.5 и в цикле дважды проверяется справедливость отношения г> 0 - для обработки очередного введенного числа и для управленияциклом.Использование операторов перехода позволяет устранить эти недостатки и получить более компактную и эффективную программу. В этомслучае можно использовать оператор цикла с параметром, исходя из того,что в общем случае надо обработать все п заданных чисел, а для "досрочного" выхода из этого цикла — в случае ввода отрицательного числа воспользоваться оператором перехода:program СУМ(input,output);label 25;var n,i: integer; s,r: real;begin read<n>;s:=0;•for i : =1 to n dobegin read<r);if r<0 then goto 25;s:=s+r end;25:wri teln('s=',5)end.Заметим, что по выходе из оператора цикла путем выполнения оператораперехода значение параметра цикла определено и равно тому его значению,при котором был выполнен оператор перехода.874.7.
Пустой операторЭтот оператор имеет тривиальный смысл - пустой оператор не задаетникаких действий, кроме определения своего преемника: если пустойоператор фигурирует среди последовательности операторов, отделенныхдруг от друга точкой с занятой, то его преемником является следующийпо порядку оператор. Синтаксически непомеченному пустому операторусоответствует отсутствие каких-либо символов (т.е. пустая последовательность символов ), что и принято называть термином пусто:(пусто) :: =(пустой оператор) :: = (пусто)Пустой оператор является тем не менее полноправным оператороми может присутствовать везде, где в синтаксическом определении фигурирует понятие (оператор). В частности, в последовательности операторовпустой оператор отделяется от других операторов точкой с запятой, можетбыть помечен и т.д.
Например, в составном оператореbegin22:;i:=0;endприсутствуют три оператора: помеченный (меткой 22) пустой оператор,оператор присваивания и следующий за ним непомеченный пустой оператор. Допустимы и такие условные операторы:if х>0 then else х:=-хif х<0 then х:=-х else(эквивалентно if х<0 then х:=-х>Несмотря на свою тривиальность пустой оператор часто бывает полезендля упрощения описания тех или иных вычислительных процессов. Наиболее часто пустой оператор используется для того, чтобы пометить некоторую точку в программе, на которую должен осуществляться переход пооператору перехода, но где уже не нужно выполнять никаких действийнапример, надо просто выйти из программы: в этом случае перед заключительным служебным словом end программы удобно поместить помеченный пустой оператор.
Пустой оператор может быть полезен и для снятиятрудностей, связанных с тем обстоятельством, что в паскале оператор может быть помечен только одной меткой: если перед помеченным оператором S поместить помеченный пустой оператор (например, записать55 :, 56: х : = 0), то на оператор S можно ссылаться по любой из этих меток.Примеры разумного и полезного использования пустых операторовбудут встречаться в последующих главахГЛАВА5РАЗРАБОТКА И ОФОРМЛЕНИЕ ПРОГРАММ5.1. Структурное программированиеВ главе 3 уже говорилось о роли повышения надежности программы и обеспечения удобства ее последующего сопровождения, а также о некоторыхмерах, предусмотренных в языке паскаль для достижения этих целей, которые были названы термином "структурирование программ".
Там, вчастности, речь шла о том, что паскаль-программа четко разбивается наотдельные разделы, в каждом из которых содержится вполне определенная информация. Это позволяет и программисту делать меньше ошибокпри написании текста программы, и транслятору выявлять многие типыошибок, оставшиеся незамеченными программистом.В данной главе мы рассмотрим некоторые другие аспекты структуризации, позволяющие повышать надежность вновь изготовляемых программ и облегчать их последующее сопровождение.Одна из трудностей изготовления надежной программы состоит в том,что не существует какого-либо формального аппарата для получения нужного алгоритма — хотя бы потому, что практически для любой задачи существует много разных алгоритмов ее решения, каждый из которых имеети свои достоинства, и свои недостатки.
Поэтому разработка алгоритма(а значит и программы) в значительной мере ведется методом "проб иошибок", при котором полученный из тех или иных соображений варианталгоритма подлежит проверке на его правильность и анализу на его эффективность. Эта работа состоит в прослеживании выполнения заданных этималгоритмом действий и анализа того, обеспечивает ли алгоритм решениеинтересующей нас задачи, и какой ценой (в отношении затрат машинноговремени и требуемого объема памяти) это достигается. Однако если длямашины выполнение даже многих сотен тысяч команд — независимо отпорядка их размещения в памяти и от их назначения - не представляетпроблемы, поскольку это выполнение осуществляется аппаратурой чистомеханически, то для человека, которого интересует и смысловое назначение каждого действия, проблема прослеживания и понимания сотен илитысяч однообразных машинных команд становится практически непреодолимой.Алгоритмические языки, позволяющие формулировать алгоритм в более понятных для человека терминах и с использованием более содержательных операций, конечно, упрощают эту проблему, но не снимают ееполностью, поскольку в достаточно сложных программах прослеживание89всех возможных путей вычислительного процесса, определяемых этойпрограммой, с проверкой их правильности и анализом эффективностиостается одной из наиболее трудных проблем в процессе изготовленияпрограммы и ее последующих — в случае необходимости — модификаций.Для уменьшения возникающих здесь трудностей в последние годы всеболее широкое признание и практическое применение получают идеиструктурного программирования.