В практике программирования часто складываются ситуации, когда одну и ту же группу операторов, реализующих определённую цель, требуется повторить без изменений в нескольких местах программы. Для избавления от столь нерациональной траты времени была предложена концепция подпрограммы.

Подпрограмма - именованная, логически законченная группа операторов языка, которую можно вызвать для выполнения любое количество раз из различных мест программы. В языке Free Pascal существуют два вида подпрограмм: процедуры и функции. Главное отличие процедуры от функции заключается в том, что результатом исполнения операторов, составляющих тело функции , всегда является некоторое значение , поэтому функцию можно использовать непосредственно в выражениях, наряду с переменными и константами.

4.1 Общие сведения о подпрограммах. Локальные и глобальные переменные

Итак, подпрограмма - это поименованный набор описаний и операторов, выполняющих определенную задачу. Информация , передаваемая в подпрограмму для обработки, называется параметрами, а результат вычислений - значениями. Обращение к подпрограмме называют вызовом. Перед вызовом подпрограмма должна быть обязательно описана в разделе описаний. Описание подпрограммы состоит из заголовка и тела. В заголовке объявляется имя подпрограммы, и в круглых скобках её параметры, если они есть. Для функции необходимо сообщить тип возвращаемого ею результата. Тело подпрограммы следует за заголовком и состоит из описаний и исполняемых операторов.

Любая подпрограмма может содержать описание других подпрограмм. Константы , переменные, типы данных могут быть объявлены как в основной программе, так и в подпрограммах различной степени вложенности. Переменные, константы и типы, объявленные в основной программе до определения подпрограмм, называются глобальными, они доступны всем функциям и процедурам. Переменные, константы и типы, описанные в какой-либо подпрограмме, доступны только в ней и называются локальными.

Для правильного определения области действия идентификаторов (переменных) необходимо придерживаться следующих правил:

  • каждая переменная, константа или тип должны быть описаны перед использованием;
  • областью действия переменной, константы или типа является та подпрограмма, в которой они описаны;
  • все имена в пределах подпрограммы, в которой они объявлены, должны быть уникальными и не должны совпадать с именем самой подпрограммы;
  • одноимённые локальные и глобальные переменные - это разные переменные, обращение к таким переменным в подпрограмме трактуется как обращение к локальным переменным (глобальные переменные недоступны);
  • при обращении к подпрограмме доступны объекты, которые объявлены в ней и до её описания.

4.2 Формальные и фактические параметры. Передача параметров в подпрограмму

Обмен информацией между вызываемой и вызывающей функциями осуществляется с помощью механизма передачи параметров. Переменные, указанные в списке в заголовке функции, называются формальными параметрами, или просто параметрами подпрограммы. Все переменные из этого списка могут использоваться внутри подпрограммы. Список переменных в операторе вызова подпрограммы - это фактические параметры, или аргументы.

Механизм передачи параметров обеспечивает обмен данных между формальными и фактическими параметрами, что позволяет выполнять подпрограмму с различными данными. Между фактическими параметрами в операторе вызова и формальными параметрами в заголовке подпрограммы устанавливается взаимно однозначное соответствие. Количество, типы и порядок следования формальных и фактических параметров должны совпадать.

Передача параметров выполняется следующим образом. Вычисляются выражения, стоящие на месте фактических параметров. В памяти выделяется место под формальные параметры в соответствии с их типами. Выполняется проверка типов, и при их несоответствии выдается диагностическое сообщение . Если количество и типы формальных и фактических параметров совпадают, то начинает работать механизм передачи данных между фактическими и формальными параметрами.

Формальные параметры процедуры можно разделить на два класса: параметры-значения и параметры-переменные.

При передаче данных через параметры-значения в подпрограмму передаются значения фактических параметров, и доступа к самим фактическим параметрам из подпрограммы нет. При передаче данных параметры-переменные заменяют 1Реально в подпрограмму передаются адреса фактических параметров. формальные параметры, и, следовательно, в подпрограмме есть доступ к значениям фактических параметров. Любое изменение параметров-переменных в подпрограмме приводит к изменению соответствующих им формальных параметров. Следовательно, входные данные следует передавать через параметры-значения, для передачи изменяемых в результате работы подпрограммы данных следует использовать параметры-переменные.

От общетеоретических положений перейдём к практическому использованию подпрограмм при решении задач. Изучение подпрограмм начнем с процедур.

4.3 Процедуры

Описание процедуры имеет вид:

procedure имя_процедуры(список_формальных_параметров); label список_меток; const список_констант; type список_типов; var список_переменных; begin //Тело процедуры. end;

Описание начинается с заголовка процедуры, где procedure - ключевое слово языка, имя_процедуры - любой допустимый в языке Free Pasacal идентификатор , список_формальных_параметров - имена формальных параметров и их типы, разделённые точкой с запятой. Рассмотрим примеры заголовков процедур с параметрами-значениями:

procedure name_1(r: real ; i: integer ; c: char );

Однотипные параметры могут быть перечислены через запятую:

procedure name_2(a, b: real ; i, j, k: integer );

Список формальных параметров необязателен и может отсутствовать:

procedure name_3;

Если в заголовке процедуры будут применяться параметры-переменные, то перед ними необходимо указывать служебное слово var :

procedure name_4(x, y: real ; var z: real );

//x, y - параметры-значения,

//z - параметр - переменная .

После заголовка идет тело процедуры , которое состоит из раздела описаний 2Раздел описаний в процедуре может отсутствовать, если в нём нет необходимости. ( константы , типы, переменные, процедуры и функции, используемые в процедуре) и операторов языка, реализующих алгоритм процедуры.

Для обращения к процедуре необходимо использовать оператор вызова:

имя_процедуры(список_фактических_параметров);

Фактические параметры в списке оператора вызова отделяются друг от друга запятой:

a: = 5. 3; k: = 2; s:= ’ a ’;

name_1(a, k, s);

Если в описании процедуры формальные параметры отсутствовали, то и при вызове их быть не должно:

ЗАДАЧА 4.1. Найти действительные корни квадратного уравнения .

Алгоритм решения этой задачи был подробно описан в задаче 3.3 (рис. 3.14). Однако там не была рассмотрена ситуация некорректного ввода значений коэффициентов. Например, если пользователь введёт , то уравнение из квадратного превратится в линейное. Алгоритм решения линейного уравнения тривиален: , при условии, что . Чтобы не усложнять уже составленный алгоритм решения квадратного уравнения, запишем его в виде подпрограммы-процедуры. Далее приведён фрагмент программы с комментариями:

//Процедура для вычисления действительных //корней квадратного уравнения. procedure korni (a, b, c: real; var x1, x2: real; var pr: boolean); //Входные параметры процедуры: //a,b,c - коэффициенты квадратного уравнения; //Выходные параметры процедуры: //x1,x2 - корни квадратного уравнения, //pr - логическая переменная, //принимает значение "ложь", если в уравнении нет корней, //и значение "истина" в противном случае. var d: real; begin d:=b * b-4 * a * c; if d<0 then pr:= false else begin pr:= true; x1:=(-b+sqrt (d)) / 2 / a; x2:=(-b-sqrt (d)) / (2 * a); end end; //Конец подпрограммы //Основная программа var a_, b_, c_, x1_, x2_, x_ : real; pr_ : boolean; begin write (’a_:= ’); readln (a_); write (’b_:= ’); readln (b_); write (’c_:= ’); readln (c_); if a_=0 then //Если а=0, то уравнение //квадратным не является. begin //Решение линейного уравнения bx+c=0. if b_<>0 then begin x_:=-c_/b_; writeln (’ x= ’,x_); end else writeln (’Нет корней ’); end else //Решение квадратного уравнения ax^2 + bx + c = 0. begin korni (a_, b_, c_, x1_, x2_, pr_); //Вызов процедуры. if pr_=false then writeln (’Нет корней ’) else writeln (’ x1= ’,x1_, ’ _x2= ’,x2_); end; end.

ЗАДАЧА 4.2. Вводится последовательность из целых положительных чисел. В каждом числе найти наибольшую и наименьшую цифры.

Для решения задачи создадим процедуру max_min , результатом работы которой будут два значения: минимальная и максимальная цифры в заданном числе.

Текст программы:

//Процедура возвращает //max наибольшую и min наименьшую цифры в числе M. //В списке параметров: //M параметр-значение (входной параметр), //max и min параметры-переменные (выходные параметры). procedure max_min(M: longint; var max: byte; var min: byte); var i: byte; begin i: = 1; while M div 10>0 do begin if i =1 then begin //Предположим, что первая цифра является max:=M mod 10; //наибольшей или min:=M mod 10; //наименьшей. i:= i +1; end; //Поиск цифры больше max или меньше min. if M mod 10 > max then max:=M mod 10; if M mod 10 < min then min:=M mod 10; M:=M div 10; end; end; var X: longint; N, i,X_max, X_min: byte; begin //Количество элементов в последовательности. write (’N= ’); readln (N); for i:=1 to N do begin write (’X= ’); readln (X); //Элемент последовательности. if X>0 then //Если элемент положительный, то begin max_min(X,X_max, X_min); //вызов процедуры. //Печать результатов. writeln (’ max= ’,X_max, ’ min= ’,X_min); end; end; end.

При решении новых задач можно попытаться воспользоваться ранее написанными программами. Алгоритм, ранее разработанный и целиком используемый в составе других алгоритмов, называется вспомогательным. Применение вспомогательных алгоритмов позволяет разбить задачу на части, структурировать ее.

Вся программа условно может быть разделена на две части: основную и вспомогательную. В основной части производится простейшая обработка информации, организуется обращение к разным вспомогательным модулям (подпрограммам).

Вспомогательный алгоритм тоже может вызывать другие вспомогательные, длина такой цепочки вызовов теоретически не ограничена. Здесь и далее следующие пары слов используются как синонимы: алгоритм и программа, вспомогательный алгоритм и подпрограмма, команда и оператор, программа и модуль. Вспомогательными и основными алгоритмы являются не сами по себе, а по отношению друг к другу.

При использовании вспомогательных алгоритмов необходимо учитывать способ передачи значений исходных данных для них и получения результата от них. Аргументы вспомогательного алгоритма - это переменные, в которых должны быть помещены исходные данные для решения соответствующей подзадачи. Результаты вспомогательного алгоритма - это также переменные, где содержаться результаты решения этих подзадач, а также результатом может быть конкретное действие, которое совершает компьютер под действием подпрограммы.

Подпрограммы могут быть двух видов: подпрограмма без параметров и подпрограмма с параметрами. Обращение к подпрограмме может быть организовано из любого места основной программы или другой подпрограммы сколько угодно раз.

При работе с подпрограммами важными являются понятия формальных и фактических параметров. Формальные параметры - это идентификаторы входных данных для подпрограммы. Если формальные параметры получают конкретные значения, то они называются фактическими. Формальные параметры могут получить конкретные значения только в той программе, где производится обращение к данному модулю-подпрограмме. Тип и порядок записи фактических параметров должны быть такими же, как и формальных параметров. В противном случае результат работы программы будет непредсказуемым. Из этого следует, что фактические параметры используются при обращении к подпрограмме из основной, а формальные параметры - только в самом модуле.

Подпрограмма с параметрами используется для записи многократно повторяющихся действий при разных исходных данных. Подпрограммы с параметрами можно разделить на два типа: подпрограммы-функции и просто подпрограммы с параметрами (их называют процедурами).

При составлении подпрограмм с параметрами надо соблюдать следующие правила:

1) каждая подпрограмма имеет свое имя и список формальных параметров;

2) процедура из основной программы вызывается командой вызова, которая по форме ничем не отличается от вызова команды исполнителя. Результат присваивается одной или нескольким переменным, которые находятся в списке формальных параметров. Но результатом могут быть, конечно, не только значения переменных, но какое либо действие, выполненное ЭВМ.

Пример 1. Используем алгоритм нахождения наибольшего общего делителя двух натуральных чисел в качестве вспомогательного при решении задачи: составить программу вычитания дробей (a, b, c, d - натуральные числа). Результат представить в виде обыкновенной несократимой дроби.

Подпрограмма.

1) Ввести натуральные числа M, N.

2) Если M=N, перейти к п. 5, иначе к следующему пункту.

3) Если M>N, то M:=M-N, иначе N:=N-M.

4) Перейти к п. 2.

5) Передать значение M в основную программу.

6) Конец подпрограммы.

Основная программа.

1) Ввести значения A, B, C, D.

2) E:=A*D - B*C.

4) Если E=0, вывести значение E и перейти к п. 9, иначе перейти к следующему пункту.

5) M:=|E|, N:=F, перейти к подпрограмме вычисления НОД.

7) E и F нацело разделить на G.

8) Вывести значения E и F на печать.

9) Конецпрограммы.

Var A, B, C, D, G, E, F: Integer;

Procedure Nod(M, N: Integer; Var K: Integer);

While M <> N Do

If M >

Write("Введите числители и знаменатели дробей:");

ReadLn(A, B, C, D);

E:= A * D - B * C;

If E = 0 Then WriteLn(E)

Nod(Abs(E), F, G);

WriteLn("Ответ: ", E, "/", F)

Как видно из примера, объявление и тело подпрограмм находится в разделе описаний. В заголовке подпрограммы содержится список формальных параметров с указанием их типа, которые условно можно разделить на входные и выходные (перед ними стоит служебное Var). При обращении к процедуре указывается ее имя и список фактических параметров. Формальные и фактические параметры должны соответствовать по количеству и по типу.

Вызов процедуры осуществляется следующим образом:

<Идентификатор (имя) процедуры>(<список фактических параметров>);

Например,

Nod(Abs(E), F, G);

По способу передачи фактических значений в подпрограмму в Turbo Pascal 7.0 выделяют параметры-переменные, параметры-значения, параметры-константы и массивы открытого типа, строки открытого типа, параметры-процедуры, параметры-функции (подробности - в литературе).

Функция (в отличие от процедуры) всегда возвращает единственное значение.

Покажем, как изменится подпрограмма из примера, если ее записать в виде функции.

Function Nod(M, N: Integer) : Integer;

While M <> N Do

If M > N Then M:= M - N Else N:= N - M;

Итак, после списка параметров указывается тип значения функции, а в теле функции хотя бы один раз встречается присваивание переменной, имя которой совпадает с именем функции, соотответствующего значения.

Вызов функции будет следующим:

G:= Nod(Abs(E), F);

Вообще, вызов функции может присутствовать в выражении, стоящем: в правой части оператора присваивания, в процедуре вывода, в качестве фактического параметра в вызове другой подпрограммы и т.д.

При решении задач целесообразно проанализировать условие, записать решение в крупных блоках (не являющихся операторами Pascal), детализировать каждый из блоков (записав в виде блоков, возможно, по-прежнему не операторов Pascal), и т.д., продолжать до тех пор, пока каждый из блоков не будет реализован с помощью операторов языка.

Пример 2. Дано натуральное число n. Переставить местами первую и последнюю цифры этого числа.

If Impossible(N)

Then WriteLn("Невозможно переставить цифры, возникнет переполнение")

WriteLn("Ответ: ", N)

Можно заметить, что необходимо детализировать логическую функцию Impossible, которая диагностирует, возможна ли перестановка, и процедуру Change, которая эту перестановку (в случае, если она возможна) выполняет.

Function Impossible(N: Integer) : Boolean;

If Number(N) < 5

Then Impossible:= False

Else Impossible:= (N Mod 10 > 3) Or

(N Mod 10 = 3) And

(N Mod 10000 Div 10 * 10 + N Div 10000 > MaxInt Mod 10000)

Здесь необходимо детализировать функцию Number, возвращающую количество цифр в записи натурального числа (т.к. функция Impossible содержит ее вызов, то в разделе описаний функция Number должна ей предшествовать).

Function Number(N: Integer) : Integer;

Var Vsp: Integer;

While N > 0 Do

Vsp:= Vsp + 1; N:= N Div 10

Наконец, последняя процедура.

Procedure Change(Var N: Integer);

Var Kol, P, S, R: Integer;

Kol:= Number(N);

P:= N Mod 10; {последняяцифра}

If Kol > 1 Then

S:= N Div Round(Exp((Kol - 1) * Ln(10)))

Else S:= 0; {перваяцифра}

R:= N Mod Round(Exp((Kol - 1) * Ln(10))) Div 10;

N:= P * Round(Exp((Kol - 1) * Ln(10))) + R * 10 + S

Возможны также подпрограммы, которые вызывают сами себя. Они называются рекурсивными. Создание таких подпрограмм является красивым приемом программирования, но не всегда целесообразно из-за чрезмерного расхода памяти ЭВМ.

Пример 3. Найти максимальную цифру в записи данного натурального числа.

Program MaxDigit;

Type NaturLong = 1..(High(LongInt));

Function Maximum(N: LongInt) : Digit;

Then Maximum:= N

Else If N Mod 10 > Maximum(N Div 10)

Then Maximum:= N mod 10

Else Maximum:= Maximum(N Div 10)

Write("Введите натуральное число: ");

WriteLn("Максимальнаяцифраравна ", Maximum(A))

При создании функции Maximum было использовано следующее соображение: если число состоит из одной цифры, то она является максимальной, иначе если последняя цифра не является максимальной, то ее следует искать среди других цифр числа. При написании рекурсивного алгоритма следует позаботиться о граничном условии, когда цепочка рекурсивных вызовов обрывается и начинается ее обратное «раскручивание». В нашем примере это условие N < 10.

Более подробно о рекурсии говорится в следующей статье.

На занятии будет объяснен алгоритм работы с процедурами на Паскале. Будут разобраны примеры использования процедуры с параметрами и без параметров. Познакомитесь с понятиями: формальные и фактические параметры, параметр-переменная и параметр-значение


Подпрограмма — это фрагмент кода, который имеет свое имя и создается в случае необходимости выполнять этот код несколько (много) раз. Подпрограмма описывается единожды перед началом основной программы (до begin). Компилятор пропускает данный фрагмент кода, пока в основной программе не встретит «вызов» подпрограммы, который выглядит как обращение к ней по имени (возможно, имени с аргументами, указанными в скобках).

Во многих языках программирования подпрограммы существуют только в виде функций. Однако в Паскале подпрограмма — и функция и процедура . Разница между ними станет очевидна в данном уроке.

Итак, рассмотрим синтаксис объявления и описания процедуры в Паскале

var …;{область объявления глобальных переменных} procedure название (параметры); {начало процедуры} var …;{объявление локальных переменных} begin … {тело процедуры} end;{конец процедуры} begin … {основная программа} end.

Пример: Процедура без параметров, которая печатает 60 звездочек, каждую с новой строки

procedure pr; var i:integer; begin for i:=1 to 60 do begin {тело подпрограммы} write("*"); writeln; end; end; {конец подпрограммы} begin pr; {вызов процедуры} end.

В данном примере работы с процедурой в Паскале очевидно, что компилятор пропустит блок описания процедуры и дойдет до основной программы (9 строка кода). И только после того, как встретится вызов процедуры (10 строка), компилятор перейдет к ее выполнению, вернувшись к строке 1.

Процедуры с параметрами. Фактические и формальные параметры

Рассмотрим пример необходимости использования процедуры.

Пример:
Построить фигуру

Особенность: Три похожие фигуры.

  • общее: размеры, угол поворота
  • отличия: координаты, цвет
  • Алгоритм решения:

    • выделить одинаковые или похожие действия (три фигуры);
    • найти в них общее (размеры, форма, угол поворота) и отличия (координаты, цвет);
    • отличия записать в виде неизвестных переменных, они будут параметрами процедуры.

    Решение на паскале:
    Процедура:

    Программа:

    15 uses GraphABC; procedure Tr( x, y: integer ; color: system. Drawing . Color ) ; begin MoveTo(x, y) ; LineTo(x, y- 60 ) ; LineTo(x+ 100 , y) ; LineTo(x, y) ; FloodFill(x+ 20 , y- 20 , color) ; end ; begin SetPenColor(clBlack) ; Tr(100 , 100 , clBlue) ; Tr(200 , 100 , clGreen) ; Tr(200 , 160 , clRed) ; end .

    uses GraphABC; procedure Tr(x, y: integer; color:system.Drawing.Color); begin MoveTo(x, y); LineTo(x, y-60); LineTo(x+100, y); LineTo(x, y); FloodFill(x+20, y-20,color); end; begin SetPenColor(clBlack); Tr(100, 100, clBlue); Tr(200, 100, clGreen); Tr(200, 160, clRed); end.

    Рассмотрим синтаксис объявления и описания процедуры с параметрами в Паскале.

    var …;{область объявления глобальных переменных} procedure pr(параметр1, параметр2: integer; параметр3:char); {начало процедуры} var …;{объявление локальных переменных} begin … {тело процедуры} end;{конец процедуры} begin … {основная программа} pr (параметр1, параметр2, параметр3); {вызов процедуры} end.

    Задание procedure 1: N вертикальных линий. N задается параметром процедуры.


    Задание procedure 2: Написать процедуру рисования N окружностей, сдвинутых по горизонтали. N , радиус R и отступ O задаются параметрами процедуры (всего 3 параметра).

    Пример: Написать процедуру, которая печатает 60 раз указанный символ (введенный с клавиатуры), каждый с новой строки

    Параметры процедуры (в некоторых языках они называются аргументами) указываются в скобках после ее имени (в объявлении).

    В данном примере в качестве введенного символа будем использовать параметр процедуры. Формальный параметр процедуры указывается в скобках при ее описании. Обязательно необходимо указать тип формального параметра через двоеточие.

    Фактический параметр — это то значение, которое указывается в скобках при вызове процедуры. Фактическим параметром может быть конкретное значение (литерал: число, символ, строка…) либо переменная, которые компилятор подставит вместо формального параметра. Поэтому тип данных у формального и фактического параметра процедуры должен быть одинаковым.

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 var s: char ; procedure pr(a: char ) ; {a - формальный параметр} var i: integer ; begin for i: = 1 to 60 do begin write (a) ; writeln ; end ; end ; begin writeln ("simvol" ) ; readln (s) ; pr(s) ; {s - фактический параметр} end .

    var s:char; procedure pr(a:char); {a - формальный параметр} var i:integer; begin for i:=1 to 60 do begin write(a); writeln; end; end; begin writeln("simvol"); readln(s); pr(s); {s - фактический параметр} end.

    В данном примере при вызове процедуры компилятор заменит формальный параметр a фактическим параметром s , т.е. тем символом, который будет введен с клавиатуры. Оба параметра имеют тип данных char .

    Задача procedure 3. Написать процедуру, которая складывает два любых числа (два параметра).

    Процедуры с параметрами. Параметр-переменная

    1. способ:
    2. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 var x, y, m, n: integer ; procedure MaxNumber(a, b: integer ; var max: integer ) ; {a и b - параметры значения, max - параметр-переменная} begin if a>b then max: = a else max: = b; end ; begin write ("vvedite x,y" ) ; readln (x, y) ; MaxNumber(x, y, m) ; {фактические параметры} writeln ("max=" , m) end .

      var x,y,m,n:integer; procedure MaxNumber(a,b:integer;var max:integer); {a и b - параметры значения, max - параметр-переменная} begin if a>b then max:=a else max:=b; end; begin write("vvedite x,y"); readln(x,y); MaxNumber(x,y,m); {фактические параметры} writeln("max=",m) end.

      В примере формальные параметры a и b служат для помещения в них сравниваемых чисел, а параметр-переменная max — для сохранения в ней максимального из двух чисел. Параметр-переменная или выходной параметр передает свое значение в основную программу (фактическому параметру m), т.е. возвращает значение, тогда как формальные параметры-значения (входной параметр), наоборот, принимают значения из основной программы (из фактических параметров x и y). Для параметра-переменной (max) используются те ячейки памяти, которые отведены под соответствующий параметр при вызове процедуры (ячейка m).

      Таким образом, сформулируем понятия:

      Если в качестве формального параметра указана обычная переменная с указанием ее типа, то такой параметр есть параметр-значение или входной параметр (a и b в примере). Тип данных формального параметра-значения должен соответствовать типу данных его фактического параметра (a и b должны попарно соответствовать типу данных x и y).

      Если перед именем формального параметра в объявлении процедуры стоит служебное слово var , то такой параметр называется параметром-переменной или выходным параметром (max в примере). Для него используются те ячейки памяти, которые отведены под соответствующий параметр при вызове процедуры (m). Фактический параметр, соответствующий параметру-переменной, может быть только переменной (не константой, не литералом и не выражением).

    3. способ:
    4. Использование параметров-переменных позволяет тратить меньше памяти

      1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 var x, y: integer ; procedure exchange(a: integer ; var b: integer ) ; {b - параметр-переменная или выходной параметр} var c: integer ; begin if a>b then begin c: = a; a: = b; b: = c; {второй параметр процедуры - b - всегда будет максимальным} end ; end ; begin writeln ("введите два числа" ) ; readln (x, y) ; exchange (x, y) ; writeln ("max=" , y) end .

      var x,y:integer; procedure exchange(a: integer;var b:integer); {b - параметр-переменная или выходной параметр} var c:integer; begin if a>b then begin c:=a; a:=b; b:=c; {второй параметр процедуры - b - всегда будет максимальным} end; end; begin writeln("введите два числа"); readln(x,y); exchange (x,y); writeln("max=",y) end.

      Используя данный способ решения задачи, мы обошлись без третьего параметра. Для этого в процедуре мы использовали еще одну локальную переменную c . Процедура меняет значения переменных a и b таким образом, чтобы b всегда была максимальной. Поэтому в 15 строке программы в качестве максимальной выводится второй параметр (y), соответствующий формальному параметру b .

    Задача procedure 4.

    1. Необходимо определить наибольший общий делитель двух введенных чисел, используя цикл.
    2. Необходимо определить наибольший общий делитель двух введенных чисел, используя процедуру (два параметра-значения, один параметр-переменная).


    Словесный алгоритм:

    • Вводятся a и b (например, 18 и 24 )
    • В цикле повторяем действия:
    • Если а < b , то меняем переменные местами (1 шаг: a=24 , b=18 ; 2 шаг: a=18 , b=6 )
    • Переменной a присваиваем остаток от деления a на b (1 шаг: a=6 , b=18 ; 2 шаг: a=0 , b=6 )
    • Когда остаток равен 0 , выводится результат (значения переменной b ) (b=6 )

    Алгоритм решения поиска НОД:

    Задача procedure 5. Используя процедуры, построить фигуру:


    Задача procedure 6. Даны 3 различных массива целых чисел (размер каждого 15 элементов). В каждом массиве найти и среднее арифметическое значение.
    Для формирования элементов массива и подсчета суммы и среднего арифметического использовать одну процедуру (среднее арифметическое и сумму оформить как параметры-переменные).

    В задачах на Паскале часто встречается необходимость заполнить массив данными и затем вывести значения на экран. Почему бы не автоматизировать данную задачу заполнения и вывода массива — т.е. оформить при помощи процедур, а в дальнейшем использовать данные процедуры при надобности.

    Пример: Создать процедуру для вывода десяти элементов массива (два параметра: количество элементов, массив)

    Показать решение:

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 const n = 10 ; var i: integer ; a, b: array [ 1 .. n ] of integer ; procedure arr_out (k: integer ; arr: array [ 1 .. n ] of integer ) ; var i: byte ; begin write ("вывод массива: " ) ; for i : = 1 to k do write (arr[ i] : 4 ) ; writeln ; end ; begin for i: = 1 to n do a[ i] : = random(10 ) ; arr_out (n, a) ; end .

    const n = 10; var i:integer; a, b: array of integer; procedure arr_out (k:integer; arr: array of integer); var i: byte; begin write ("вывод массива: "); for i:= 1 to k do write (arr[i]:4); writeln; end; begin for i:=1 to n do a[i]:=random(10); arr_out (n, a); end. integer ; procedure arr_rand (k: integer ; var arr: array [ 1 .. n ] of integer ) ; var i: byte ; begin write ("Заполнение массива случайными числами " ) ; randomize; for i : = 1 to k do arr[ i] : = random(100 ) ; end ; begin arr_rand (n, a) ; end .

    const n = 10; var a, b: array of integer; procedure arr_rand (k:integer; var arr: array of integer); var i: byte; begin write ("Заполнение массива случайными числами "); randomize; for i:= 1 to k do arr[i]:=random(100); end; begin arr_rand (n, a); end.

    Задача procedure 7. Объедините обе решенные задачи (для заполнения и вывода массива).


    Задача procedure 8. Добавьте в задачу процедуру для заполнения значений массива пользователем (ввод значений с клавиатуры). Оформите вывод двух разных массивов: один — со значениями, сформированными случайным образом, другой — со значениями, введенными пользователем.


    Задача procedure 9. Составить программу с процедурой для вычисления (входные параметры: число и степень). Для вывода результата использовать параметр-переменную.

    Самостоятельная работа

    1 вариант: для 5 одномерных массивов определять произведение элементов каждого массива, используя процедуру с двумя параметрами - число элементов массива и параметр-переменная для вывода произведения.

    2 вариант: для 5 одномерных массивов определять минимальный элемент каждого массива, используя процедуру с двумя параметрами - число элементов массива и параметр-переменная для вывода минимального элемента.

    * сложное С помощью процедуры формировать случайным образом одномерные массивы из 10 элементов (значения от -20 до +20). Вызывать процедуру до тех пор, пока среди значений не появится ноль.

    Содержащая описание определённого набора действий. Подпрограмма может быть многократно вызвана из разных частей программы. В языках программирования для оформления и использования подпрограмм существуют специальные синтаксические средства.

    Назначение подпрограмм

    Подпрограммы изначально появились как средство оптимизации программ по объёму занимаемой памяти - они позволили не повторять в программе идентичные блоки кода, а описывать их однократно и вызывать по мере необходимости. К настоящему времени данная функция подпрограмм стала вспомогательной, главное их назначение - структуризация программы с целью удобства её понимания и сопровождения.

    • Выделение набора действий в подпрограмму и вызов её по мере необходимости позволяет логически выделить целостную подзадачу, имеющую типовое решение. Такое действие имеет ещё одно (помимо экономии памяти) преимущество перед повторением однотипных действий: любое изменение (исправление ошибки, оптимизация, расширение функциональности), сделанное в подпрограмме, автоматически отражается на всех её вызовах, в то время как при дублировании каждое изменение необходимо вносить в каждое вхождение изменяемого кода.
    • Даже в тех случаях, когда в подпрограмму выделяется однократно производимый набор действий, это оправдано, так как позволяет сократить размеры целостных блоков кода, составляющих программу, то есть сделать программу более понятной и обозримой.

    Преимущества

    Преимущества разбиения программы на подпрограммы включают:

    • Декомпозиция комплексной программной задачи на простые шаги: это один из двух основных инструментов структурированного программирования и структур данных
    • Уменьшение дублированного кода
    • Возможность повторного использования кода в других программах
    • Разделение крупной программной задачи между различными программистами, или различными стадиями проекта
    • Сокрытие деталей реализации от пользователей подпрограммы
    • Улучшение прослеживания (большинство языков предоставляют способ получить след вызова который включает в себя имена задействованных подпрограмм и возможно даже больше такой информации как имена файлов и номера строк). Без декомпозиции кода на подпрограммы, отладка была бы серьезно затруднена.

    Механизм подпрограмм, их описание и вызов

    В следующем примере на языке Паскаль подпрограмма subprog вызывается из основной программы трижды:

    Program SubProgExample ; procedure subprog ; begin // начало тела подпрограммы WriteLn ("Bye" ) ; end ; // конец тела подпрограммы begin WriteLn ("Hello" ) ; subprog ; // 1-й вызов subprog ; // 2-й вызов subprog ; // 3-й вызов end .

    Результатом выполнения такой программы станет вывод строки «Hello» и трёх строк «Bye».

    Для сохранения и восстановления контекста выполнения вызывающей процедуры, с целью исключения побочных эффектов, связанных с возможным нежелательным изменением используемых машинных регистров, компилятор формирует для каждой процедуры специальные последовательности команд, называемые прологом и эпилогом процедуры.

    Некоторые языки программирования (например, Паскаль, Ада, Модула-2) допускают описание вложенных подпрограмм, то есть помещение подпрограмм внутрь других подпрограмм. Такие вложенные подпрограммы могут использоваться только в той подпрограмме, в которой они описаны. В иных случаях (например, в языке Си) вложение подпрограмм не допускается. Никаких принципиальных преимуществ вложение подпрограмм не даёт, но может быть удобно для более логичной структуризации программы (если какая-то подпрограмма используется только в некоторой другой подпрограмме, логично поместить первую во вторую).

    Параметры подпрограмм

    Назначение параметров

    Подпрограммы часто используются для многократного выполнения стереотипных действий над различными данными. Подпрограмма обычно имеет доступ к объектам данных, описанным в основной программе (по крайней мере, к некоторым из них), поэтому для того, чтобы передать в подпрограмму обрабатываемые данные, их достаточно присвоить, например, глобальным переменным. Но такой путь не особенно удобен и чреват ошибками.

    Для обеспечения контролируемой передачи параметров в подпрограмму и возврата результатов из неё используется механизм параметров . Параметры описываются при описании подпрограммы (в её заголовке) и могут использоваться внутри процедуры аналогично переменным , описанным в ней. При вызове процедуры значения каждого из параметров указываются в команде вызова (обычно после имени вызываемой подпрограммы).

    Program SubProgExample2 ; // Описание подпрограммы subprog procedure subprog (Line : String ) ; // Заголовок, включающий имя подпрограммы begin // начало тела подпрограммы WriteLn (Line ) ; end ; // конец тела подпрограммы begin WriteLn ("Hello" ) ; subprog ("Good bye," ) ; // 1-й вызов subprog ("my love," ) ; // 2-й вызов subprog ("good bye!" ) ; // 3-й вызов end .

    В приведённом примере параметр Line подпрограммы subprog в каждом вызове получает различное значение, благодаря чему выводятся не одинаковые строки, а разные.

    Формальные и фактические параметры

    Чтобы отличать параметры подпрограммы, описанные в её заголовке и теле, от параметров, указываемых при вызове подпрограммы, используются формальные и фактические параметры. Формальные параметры указываются при объявлении или определении подпрограммы, а фактические - непосредственно при её вызове. Так, в последнем примере параметр Line в заголовке и теле подпрограммы subprog - это формальный параметр, а строка "Good bye" , использованная в первом вызове этой подпрограммы - фактический параметр. При вызове подпрограммы фактические параметры, указанные в команде вызова, становятся значениями соответствующих формальных параметров, чем и обеспечивается передача данных в подпрограмму.

    Способ передачи параметров в подпрограмму

    Существует несколько способов передачи параметров в подпрограмму.

    • Передача параметров по значению. Формальному параметру присваивается значение фактического параметра. В этом случае формальный параметр будет содержать копию значения, имеющегося в фактическом, и никакое воздействие, производимое внутри подпрограммы на формальные параметры, не отражается на параметрах фактических. Так, если в качестве фактического параметра будет использована переменная, и внутри подпрограммы значение соответствующего формального параметра будет изменено, то фактический параметр останется без изменений.

    int func1(int x)

    { x=x+2; return x;

    • Передача параметров по ссылке. В формальный параметр может быть помещён сам фактический параметр (обычно это реализуется путём помещения в формальный параметр ссылки на фактический). При этом любое изменение формального параметра в подпрограмме отразится на фактическом параметре - оба параметра во время вызова подпрограммы суть одно и то же. Параметры, передаваемые по ссылке, дают возможность не только передавать параметры внутрь подпрограммы, но и возвращать вычисленные значения в точку вызова. Для этого параметру внутри подпрограммы просто присваивается нужное значение, и после возврата из подпрограммы переменная, использованная в качестве фактического параметра, получает это значение.
    • Передача параметров по имени. В формальный параметр может быть помещено произвольное выражение. При этом вычисление этого выражения произойдёт внутри подпрограммы в тот момент, когда потребуется его значение. Если это значение фигурирует несколько раз, то и вычисляться оно будет тоже несколько раз. Параметры, передаваемые по имени, дают возможность писать довольно универсальные подпрограммы. Такой способ передачи параметров используется, к примеру в языках Алгол или Алгол 68 .
    • Передача параметров через стек. Это фактически разновидность передачи параметра по значению «с ручным приводом», в данном случае отсутствует понятие формальных и фактических параметров. Все параметры лежат на стеке, причём их типы, количество и порядок не контролируются компилятором. Данный подход реализован в языке Форт .

    Язык программирования может предоставлять возможность передавать параметры в подпрограммы либо только по значению, либо по значению и по ссылке, либо по имени и значению. В последних двух случаях для различения способов передачи параметра используются отдельные синтаксическая конструкции (в Паскале это ключевое слово var при описании параметра). В действительности, если язык содержит понятие ссылки (указателя), то можно обойтись и без передачи параметра по ссылке (её всегда можно смоделировать, описав параметр типа «ссылка»), но эта возможность удобна, так как позволяет работать с формальным параметром-ссылкой без разыменования, а также повышает надёжность и безопасность программы.

    Это подпрограмма специального вида, которая, кроме получения параметров, выполнения действий и передачи результатов работы через параметры имеет ещё одну особенность- она всегда должна возвращать результат. Вызов функции является, с точки зрения языка программирования, выражением, он может использоваться в других выражениях или в качестве правой части присваивания.

  • Процедура - это независимая именованная часть программы, которую после однократного описания можно многократно вызвать по имени из последующих частей программы для выполнения определенных действий.
  • В -подобных языках подпрограмма всегда описывается как функция. Процедура реализуется как функция типа void , то есть имеющая «пустой» тип и, соответственно, не возвращающая никакого значения.

    Подпрограммы, входящие в состав классов в объектных языках программирования, обычно называются методами . Этим термином называют любые подпрограммы-члены класса, как функции, так и процедуры; когда требуется уточнение, говорят о методах-процедурах или методах-функциях .

    Определение . Подпрограмма – это отдельная функционально независимая часть программы. Любая подпрограмма обладает той же структурой, которой обладает и вся программа.

    Подпрограммы решают три важные задачи:

    Избавляют от необходимости многократно повторять в тексте программы аналогичные фрагменты;

    Улучшают структуру программы, облегчая ее понимание;

    Повышают устойчивость к ошибкам программирования и непредвидимым последствиям при модификациях программы.

    Очень важно понимать, что в подпрограммы выделяется любой законченный фрагмент программы. В качестве ориентиров просмотрите следующие рекомендации.

    1. Когда Вы несколько раз перепишите в программе одни и те же последовательности команд, необходимость введения подпрограммы приобретает характер острой внутренней потребности.

    2. Иногда слишком много мелочей закрывают главное. Полезно убрать в подпрограмму подробности, заслоняющие смысл основной программы.

    3. Полезно разбить длинную программу на составные части – просто как книгу разбивают на главы. При этом основная программа становится похожей на оглавление.

    4. Бывают сложные частные алгоритмы. Полезно отладить их отдельно в небольших тестирующих программах. Включение программ с отлаженными алгоритмами в основную программу будет легким, если они оформлены как подпрограммы.

    5. Все, что Вы сделали хорошо в одной программе, Вам захочется перенести в новые. Для повторного использования таких частей лучше сразу выделять в программе полезные алгоритмы в отдельные подпрограммы.

    Подпрограммы могут быть стандартными, т.е. определенными системой, и собственными, т.е. определенными программистом.

    Стандартная подпрограмма (процедура или функция) - подпрограмма, включенная в библиотеку программ ЭВМ, доступ к которой обеспечивается средствами языка программирования. Вызывается она по имени с заданием фактических параметров с типом описанным при описании данной процедуры в библиотечке процедур и функций.

    Из набора стандартных процедур и функций по обработке одного типа информации составляются модули. Каждый модуль имеет своё имя (мы уже хорошо знакомы с модулями Crt, Graph). Доступ к процедурам и функциям модуля осуществляется при подключении этого модуля (Uses Crt, Graph).

    Help содержит подробные описания предусмотренных средой программирования процедур и функций. Для вызова помощи при работе со стандартнымипроцедурами и функциями нужно поставить на имя подпрограммы курсор и нажать клавиши . Описание процедур и функций в Help строится по стандартному принципу.

    Задание . Вызовите помощь по функции Cos и рассмотрите предоставленную информацию.


    Сначала идет краткое описание подпрограммы (в одну фразу). Далее под словом Declaration (Объявление) следует интерфейсная часть процедуры или функции, которая особенно часто необходима для определения типа переменных при обращении к ним. Далее под словом Target приводятся платформы, на которых может использоваться подпрограмма: Windows, real (реальный режим DOS), protected (защищенный режим DOS). После слова Remarks следуют заметки, содержащие необходимые детали использования. В разделе See Also приведены имена подпрограмм, связанных с данной по смыслу или по совместному применению. Если перемещать курсор по этим именам (они выделяются курсорной рамкой), то выбрав одно из них (нажать клавишу ), можно получить справку по следующей функции. Каждая процедура и функция сопровождается примером применения, переключение к которому дает последняя строка программы. Любой текст из Help может быть скопирован в редактируемый файл обычными приемами копирования через буфер. Копирование примеров или заголовков функций облегчает работу.

    Существует другой способ получения помощи по процедурам и функциям. Для этого нужно использовать пункт меню Help/Reserved words (зарезервированные слова) или Help/Standard units (стандартные модули).

    Задание . Рассмотрите список процедур и функций, выберите какие-либо и просмотрите предлагаемую информацию.

    В стандартных модулях содержится большое количество стандартных подпрограмм, но невозможно создать модуля, который бы содержал все нужные программисту подпрограммы. Поэтому большую роль в создании программ играют собственные подпрограммы, которые создает программист для решения конкретной задачи.

    Существует два способа объединения программ и подпрограмм:

    1. Текст подпрограмм может быть приведен в разделе описания использующей их программы.

    2. Подпрограммы группируются в отдельных файлах, имеющих специальную структуру – модулях. Для того чтобы основная программа могла использовать модуль, он должен быть подключен к основной программе.

    Первый способ применяется тогда, когда программа в целом не очень большая, а ее подпрограммы, скорее всего, не будут использоваться в других программах. Второй способ желателен, в частности, для той программы, которую Вы будете создавать в качестве курсовой работы при завершении учебы в городской школе юного программиста.

    Структура текста подпрограммы соответствует структуре текста основной программы за двумя исключениями:

    Подпрограмма начинается с заголовка, содержащего имя подпрограммы, передаваемые в нее и возвращаемые от нее периметры, запись заголовка подпрограммы отличается от заголовка программы;

    Подпрограмма кончается не точкой, а точкой с запятой.

    Вызов подпрограммы происходит при каждом употреблении ее имени в основной (или вызывающей) программе. При вызове подпрограммы выполнение основной программы приостанавливается, и управление передается в подпрограмму, где выполняются команды, заданные в ней. Подпрограмма завершается, если выполнены все ее процедуры до завершающего слова End или по специальной команде выхода из подпрограммы Exit. По окончании работы подпрограммы управление возвращается основной программе, иначе говоря, к первой команде, следующей за обращением к этой подпрограмме.

    В языке Pascal определяются два типа подпрограмм – процедуры и функции. Основное различие между процедурой и функцией состоит в том, что процедура только выполняет какую-либо законченную последовательность действий, не возвращая результата работы в основную программу, а функция и выполняет действия, и возвращает результат.

    Например, вызов функции

    вернет в основную программу значение наименьшего из двух чисел и это значение будет присвоено переменной M.

    Любая подпрограмма должна быть описана до того, как она будет вызвана в программе или в другой подпрограмме. Все переменные, которые использует подпрограмма, могут быть либо глобальные либо локальные.

    Определение . Глобальными называются переменные, объявленные в основной программе и доступные как программе, так и всем ее подпрограммам.

    Определение . Локальными называются переменные, объявленные внутри подпрограммы и доступные только ей самой.

    Обмен информацией между основной программой и подпрограммой может осуществляться только с помощью глобальных переменных.

    Подпрограмма может использовать любые глобальные переменные кроме тех, которые имеют те же имена, что и локальные переменные. Переменные с совпадающими именами, которые могут быть описаны в основной программе или других подпрограммах, не имеют ничего общего с локальными переменными. если переменная описана. Если переменная описана в основной программе и не переопределена в подпрограмме, она может использоваться в подпрограмме. Память для локальных (т.е. описанных в подпрограмме) переменных выделяется на время исполнения данной подпрограммы в специальной области, называемой стеком . При завершении работы подпрограммы память освобождается, поэтому все внутренние результаты работы подпрограммы не сохраняются от одного обращения к другому.

    Если говорить о плюсах использования в программировании подпрограмм, то можно назвать следующие:

    Программы с использованием подпрограмм позволяют реализовать один из самых прогрессивных методов программирования – структурное программирование.

    Программа становится более читаемой.

    Экономия памяти, которая получается из-за того, что память для хранения переменных, используемых в подпрограммах, выделяется только на время работы подпрограммы.

    В языке Паскаль выделяют два вида подпрограмм: процедуры (Procedure) и функции (Function). Любая программа может содержать несколько процедур и функций. Структура любой подпрограммы аналогична структуре всей программы. Подпрограмма должна быть описана до того, как будет использована в программе или другой подпрограмме.

    Процедуры и функции объявляются в разделе описания вслед за разделом переменных.

    Тогда общая структура программы выглядит так:

    Label; {описание меток}

    Const; {описание констант}

    Type; {описание типов}

    Var; {описание переменных}

    Procedure; {описание процедур}

    Function; {описание функций}

    Выполнение программы начинается с операторов основной программы. При необходимости вызывается подпрограмма и начинают действовать её операторы. Затем управление передаётся в основную программу, которая продолжает выполняться.

    Обращение к подпрограмме - переход к выполнению подпрограммы с заданием информации, необходимой для ее выполнения и возврата.

    Подпрограмма вызывается по своему имени с указанием необходимых параметров .

    На этом занятии рассмотрим примеры организации наиболее простого вызова подпрограмм.

    Задание . Рассмотрите решение предложенных задач, наберите на компьютере, проверьте работоспособность, внесите свои изменения и дополните своими комментариями.

    Задача 1 . Написать программу, состоящую из трех подпрограмм и основной программы. Подпрограммы должны организовывать ввод чисел, вычисление их суммы и вывод результата.

    Program AkulovE;

    Procedure Input ;

    writeln("По вызову активизировалась процедура "Input"",#10);

    writeln("Введите два числа через пробел - ");

    Procedure Summa ;

    writeln("Для сложения подключилась процедура "Summa"",#10);

    {- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}

    Procedure Output ;

    writeln("Заключительная часть. Процедура "Output"",#10,#13);

    writeln("Их сумма - ",x);

    {- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}

    Задача 2 . Найти среднее арифметическое двух чисел.

    {- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}

    Function SredArif (A, B:integer):real;

    SredArif :=(A+B)/2;

    {- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}

    write("Введите два числа ");

    Rez:=SredArif (A,B);


    Close