2. ФУНКЦИИ И ПРОЦЕДУРЫ 2.1. Описание функций Ранее мы познакомились со стандартными функциями Паскаля. Кроме них программист может воспользоваться своими собственными функциями, предварительно описав их в программе. Описание функции располагается до исполняемой части программы и является как бы маленькой программой внутри большой. Начинается описание заголовком функции FUNCTION имя (параметры) : тип; где имя — то имя, которое программист решил дать своей функции; параметры — список переменных с указанием их типов, своего рода описание. В отличие от стандартных, функции программиста могут иметь любое число аргументов произвольных типов; тип — это тип значения, которое вычисляет функция. Он обязан быть простым. Заметим, что типы в заголовке функции можно обозначать только именами, поэтому тип массива требует предварительного переобозначения предложением type (см. раздел 1.1). Вслед за заголовком располагается тело функции, которое по структуре ничем не отличается от программы, но заканчивается не точкой, а точкой с запятой. В теле функции должен присутствовать оператор присваивания, в левой части которого стоит имя функции, а в правой — выражение для возвращаемого значения. ПРИМЕР. Описание Функции выбора большего из двух аргументов. function MAX (A,B: real): real; begin if A > В then MAX := A else MAX := В end; ВОПРОС. Опишите функцию выбора меньшего из двух целых чисел. 6 2.2. Обращение к функции После описания функции ее можно использовать в выражениях наряду со стандартными функциями. Аргументами при обращении могут быть любые выражения. Порядок следования и типы аргументов должны быть такими же, как у параметров в заголовке функции. Вычисление выражений, содержащих обращение к функции, происходит по следующему алгоритму: 1) вычисляются выражения для аргументов функции; 2) значения аргументов присваиваются параметрам из заголовка описания; 3) выполняется тело функции и вычисляется ее значение; 4) значение функции ставится в исходное выражение на место обращения к функции; 5) вычисление исходного выражения продолжается. Заметим, что если выражения для аргументов сами содержат обращения к функциям, то пункт 1) выполняется по приведенному алгоритму. В подобных случаях говорят, что алгоритм — рекурсивный. Давайте посмотрим, что дает нам описание функции. Вы правы, если думаете, что без него можно обойтись, заменив обращения к функции переменными нужного типа и заранее вычислив их значения. Но тогда прийдется запрограммировать одни и те же вычисления столько раз, сколько раз мы обращались к функции. Программа удлинится, потеряет наглядность и утратит структуру, т.к. функция решает независимую от всего остального задачу, а мы «размажем» эту задачу по программе. Такой образ действий повредит маленьким программам и катастрофически отразится на больших. Только разбивка задачи на множество относительно независимых подзадач позволяет программисту справляться со сложными программами. 7 2.3. Процедуры Как быть, если выделенная нами подзадача не похожа на функцию, т.е. не возвращает ни одного или возвращает много значений ? Здесь нам пригодится процедура. Процедура — это самостоятельная программная единица, которая выполняется по команде из другой программной единицы (программы, процедуры или функции). Процедура отличается от функции только заголовком и способом обращения к ней. Схема заголовка процедуры следующая: PROCEDURE имя (параметры); Процедура не обязана возвращать значение, поэтому нет нужды указывать тип, как в заголовке функции. Вот примеры заголовков процедур: PROCEDURE ALPHA (X: INTEGER; Y: REAL; Z: CHAR); PROCEDURE BETA (M: ARR); В том месте программы, где нужно выполнить действия, предусмотренные в описании процедуры, ставят оператор процедуры: имя (аргументы) , где имя то же, что в заголовке процедуры. ПРИМЕР. Описание и вызов процедуры, которая печатает сумму N первых элементов вещественного массива. type Arr = array [1..100] of real; procedure PrintSum (R: Arr; N: integer); var Summa: real; i: integer; begin Summa := 0; i:=1; while i< N do begin Summa := Summa + R [i]; i:=i+1 8 end; writein (Summa); end; var A: Arr; Begin …………. PrintSum (A, 20); end. ВОПРОС. Что следует изменить в примере, чтобы печатать сумму элементов, начиная с N1 и кончая N2 ? 2.4. Параметры-переменные Процедура может не только получать значения от вызывающей программы, но и возвращать в программу новые значения. Для этой цели служат параметры-переменные. В то время, как параметр получает значение аргумента путем присваивания, параметр-переменная — это просто другое имя для аргумента. Под этим именем значение аргумента становится доступным в процедуре. Все преобразования, выполняемые в процедуре над параметром-переменной, выполняются, таким образом, над аргументом. В списке параметров заголовка процедуры перед параметрамипеременными ставят слово VAR. Например, procedure PrintSum (var R: Arr; N: integer); Параметры-переменные можно использовагь не toj ко в процедурах, но и в функциях. 9 2.5. Взаимодействие блоков В некоторых вопросах различие между процедурами и функциями не играет роли. Обсуждая такие вопросы, будем называть их общим именем — блок. В программе может быть описано сколько угодно блоков. Внутри этих блоков могут быть описания других блоков и т.д. без видимых ограничений. Важно знать, откуда какие блоки могут быть вызваны или, как говорят программисты, видны. Для ответа на этот вопрос вообразите, что блок — это дом с зеркальными стеклами в окнах. Изнутри через них видно все, что находится снаружи, внутрь же заглянуть нельзя. A B D E C F G На рисунке изображен пример программы А, внутри которой описаны блоки В и С. Внутри В описаны D и Е, внутри С описан блок F, а в нем - G. Если вы пишете код блока F, то, согласно правилу зеркальных стекол, можете обращаться к блокам В, С, а также G и даже самому блоку F. Заметим, что обращение блока к самому себе называется рекурсией, и позже мы познакомимся с нею поближе. ВОПРОС. Что видно из А ? Из D ? Видимость — это свойство всех описаний, а не только блоков. Находясь в блоке, можно пользоваться всем, что видно из него. Так из блока F видны переменные, описанные в С и А, но не видны переменные, описанные в В, D, Е и G. Объекты, описанные в блоке, называются внутренними, а те, что 10 описаны в блоках, охватывающих данный, — внешними по отношению к блоку. Внешние переменные дают дополнительный канал связи между блоками (основным каналом (следует считать параметры и параметрыпеременные). Поль зоваться этим каналом надо осторожно, ибо он усиливает зависимость блоков друг от друга и этим затрудняет разработку программы. Может статься, что имена разных внешних переменных совпадут. Какая из одноименных переменных будет видна из блока? Будет видна та, что описана в ближайшем из внешних блоков. Если же конкуренция возникнет между внешней и внутренней переменными, видна будет внутренняя. 11 • ЗАДАЧИ 1. Определите функцию нахождения наибольшего из трех чисел. 2. Опишите процедуру, которая получает вещественный массив М из 100 элементов и возвращает S — сумму чисел, находящихся в массиве. 3. Опишите функцию вычисления среднего значения для N первых элементов вещественного массива W. 4. Определите функцию, вычисляющую, какой целой степенью числа 2 является ее аргумент. 5. Запрограммируйте сортировку выбором в виде процедуры. Поиск наименьшего числа сделайте ее внутренней процедурой. 6. Опишите массив размером 25 х 80 — образ экрана и определите процедуры построения: 1) горизонтальной линии; 2) прямой линии; 3) окружности; 4) прямоугольника; 5) закрашенного прямоугольника; 6) вывода на экран «графического» образа. - 12