В.Г. Абрамов, Н.П. Трифонов, Г.Н. Трифонова - Введение в язык Паскаль (1107618), страница 41
Текст из файла (страница 41)
Конечно, эту переменную можно было сделать глобальной, описавее в разделе переменных основной программы. Однако для избежаниявозможных ошибок не следует возлагать на какой-либо блок забот о потребностях других блоков. Заметим также, что переменной i можно было быпредписать тип integer. Но поскольку мы знаем, что в любой процедурезначение этой переменной заведомо не должно превышать значения N,то эту информацию целесообразно сообщить транслятору (путем заданиядля i соответствующего типа) для повышения надежности программы.168Теперь рассмотрим пример описания и использования процедур дляобработки данных нечислового характера.П р и м е р 8.2.
Задаются две строки strl и str2, каждая из которыхсодержит N литер. Подсчитать число цифр в строке strl и количество строчных латинских букв в строке str2.В программе, предназначенной для решения этой задачи, целесообразноввести в употребление процедуры ввода и вывода литерного массива,а также процедуру подсчета числа литер, принадлежащих некоторому отрезку упорядоченного множества значений типа char.
При этом мы исходимиз того, что в конкретной реализации и цифры, и строчные латинскиебуквы перенумерованы последовательными целыми числами. Программунапишем для N = 30.{Пример 8.2.Тюляева В.В.ф-т ВМиК МГУ7.2.87г.Подсчет числа цифр в первой из задаваемых строк литери числа строчных латинских букв- во второй из этих о т р о к ){Использование процедур)>program АНАЛИЗСТРОК (i nput,output) ;const N=30;type инд=1..N;строка=аггау Синд] of char;var strl,str2: строка; k: инд;>{procedure BBOACTP(var s: строка);var i: инд;begin for i:=l to N do read(sCi3)end;{>procedure BbiBCTP(var s: строка);var i:инд;begin for i:=l to N do write<sCi]);writeln end;procedure BX0)KA(var s: строка; p,q: char; var m: инд);»ar i: инд;begin m:=0;for i : •= 1 to N doif (sC i 3>p) and <sCi3<q) then m:=m+lend;{)beginВВОДСТР(str1); writeln<'СТРОКА strl:');ВВ0ДСТР(str2); writeln('СТРОКА str2:'); ВЫВСТР<str2);ВЫВСТР(str1);ВХОЖД(str1, 0' , '9' ,k);writeln < 'ЦИФР В СТРОКЕ strl =,k>;ВХОЖД <st.r2 , ' a ' , ' z ' , b) 5writeln<'ЛАТИНСКИХ БУКВ В СТРОКЕ str2=',k>end;169ГЛАВА 9ПРОЦЕДУРЫ-ФУНКЦИИВ математике понятие функции хорошо известно — с помощью функций задаются самые различные зависимости одних значений (являющихся значением функции) от других значений, называемыхаргументамифункции.
Как известно, эти зависимости могут задаваться различнымиспособами: таблично, графически, аналитически и т.д. В отличие от общематематического понятия функции, в алгоритмических языках, в томчисле и в паскале, рассматриваются только такие функции, для которыхможно задать алгоритм определения их значений.При этом в паскале допустимы только такие функции, значения которых относятся к простым типам, так что значением функции не может быть, например, массив. В частности, каждое арифметическое илилогическое выражение паскаля, даже не использующее понятия функции, определяет некоторую функциональную зависимость.Однако далеко не каждую функциональную зависимость, допустимуюв алгоритмическом языке, можно задать в виде такого выражения.
Вряде случаев значение функции определяется достаточно сложным вычислительным процессом (вычислительной процедурой). Например, хорошо известную функциональную зависимость, обозначаемую в математике через и!, на паскале невозможно задать в виде арифметическоговыражения (заметим, что часто используемая в математике запись вида1 • 2 • 3 • . . . • п на алгоритмическом языке недопустима, поскольку синтаксис языка нигде не допускает использования многоточия). Поэтомуалгоритм вычисления значения у - п\ на паскале придется задать некоторойпоследовательностью операторов, например:у: =1;for i:= 1 to n do y:=y*i;Если необходимость использования какой-либо функциональной зависимости встречается в нескольких местах программы, то было бы нерационально каждый раз выписывать соответствующий алгоритм.
Как и вслучае процедур-операторов, удобнее однаждыопределить требуемуюфункциональную зависимость, дав ей некоторое имя, а в случае необходимости использовать эту зависимость путем указания ее имени и задания конкретных значений аргументов.Процедуры, предназначенные для определения функциональных зависимостей, будем называть процедуры-функции.1709.1. Описание процедур-функцийДля определения функций в паскале служит понятие (описание функции > — все такие описания размещаются в разделе процедур и функцийтого блока, в котором эти функции вводятся в употребление.Синтаксис описания функции очень похож на синтаксис описания процедуры-оператора:<описание функции?- :: =(заголовок Функции}<заголовок Функции>function•<список;^<блок>::=ГС>.
<имя Ф у н к ц и и } — |Формальных параметров}> <имятипа>)Как видно, заголовок функции начинается служебным словом function,что и является признаком того, что здесь речь идет об описании функции. Как обычно, вводимому в употребление программному объекту —в данном случае функции — дается свое имя в виде идентификатора. Заименем функции в общем случае следует взятый в круглые скобкисписок формальных параметров, представляющих аргументы описываемой функции. Этот список определяется точно так же, как и в описании процедуры-оператора, поэтому мы не будем повторять это определение. Как видно из определения, допускаются и функции без параметров(например функция, значением которой является случайное число изфиксированного отрезка, или функция, аргументы которой заданы глобальными переменными).
Параметрами процедуры-функции также могутбыть к а к параметры-значения, так и параметры-переменные, т.е. конкретные аргументы функции могут вызываться как значениями, так ипо имени (по ссылке). При этом аргументы могут иметь разные типыи притом не обязательно скалярные, так что и в этом отношении процедуры-функции ничем не отличаются от процедур-операторов.Заголовок функции завершается указанием имени типа значения описываемой функции. Обратим внимание на то, что здесь может бытьуказано только имя типа, но не его задание.
Так что типы значений всехописываемых функций либо должны быть стандартными, либо должныбыть предварительно описаны (а следовательно, каждому из них должнобыть дано имя).Необходимость явного указания типа значений описываемой функциидиктуется двумя обстоятельствами. Во-первых, для определения типаарифметического выражения необходимо знать тип каждой из используемых в нем функций. Во-вторых, это необходимо для контроля правильности использования данной функции в программе, т.е. для повышения надежности программы.Блок, являющийся телом процедуры, определяется обычным образом,однако здесь имеется одна особенность.Как уже было отмечено, в общем случае значение функции определяется некоторой вычислительной процедурой, в процессе выполнениякоторой может вычисляться довольно много различных, в том числе ипромежуточных результатов. В связи с этим возникает вопрос — а ка171/кое же из вычисляемых в теле процедуры значений должно быть принято в качестве искомого значения функции? Для однозначного ответа наэтот вопрос и служит упомянутая особенность тела процедуры-функции,которая состоит в том, что в ее разделе операторов обязательно долженприсутствовать хотя бы один оператор присваивания вида< имя функции > := < выражение >который и означает, что в качестве значения функции принимается значение заданного в нем выражения.
Операторов присваивания указанного вида может быть и несколько, но хотя бы один из них должен выполняться в процессе выполнения тела процедуры. Результат последнего по времени выполнения оператора присваивания указанного вида ипринимается в качестве окончательного значения функции.Следует обратить внимание на то, что операторы присваивания указанного вида могут использоваться только в описаниях процедур-функщй, и нигде больше.Таким образом, описание процедуры-функции имеет три отличия отописания процедуры-оператора:1) описание начинается служебным словом function;2) в заголовке функции указывается имя типа значения описываемойфункции;3) в теле процедуры-функции должен присутствовать хотя бы одиноператор присваивания, в левой части которого фигурирует имя описываемой функции, причем хотя бы один оператор такого вида долженбыть выполнен.Например, функцию / ( и ) = п! можно описать на паскале следующимобразом:•function FACT<n:var i,k:begininteger):integer;integer;k:=l;for i:=l to n do k:=k*i;FACT:=kendСразу же обратим внимание на две типичные ошибки, допускаемыеучащимися при изучении паскаля.1.
В левой части оператора присваивания,определяющегозначениефункции, наряду с именем функции записывается и ее аргумент (аргументы), например F A C T ( n ) : = k . Во-первых, такая запись недопустима по синтаксису (здесь в левой части фактически записано выражение,к а к о в ы м является вызов функции). Во-вторых, запись FACT(n) означает, что надо вычислить значение функции FACT при указанном в скобках аргументе.