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

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

Подпрограммы-процедуры

Описание процедуры и обращение к ней:
Var
<глобальные переменные>;
Procedure <имя>(<формальные параметры>);
  Var <локальные переменные>;
  Begin
  <тело процедуры>
  end;
Begin
<тело основной программы>
End.
Пояснения:
1) Имя процедуры строится по тем же правилам, что и идентификатор переменной.
2) Формальные параметры - это локальные переменные, предназначенные для хранения данных, принятых из основной программы на обработку, и результатов работы процедуры. В общем виде формальные параметры перечисляются следующим образом: вначале следует список параметров, предназначенных для обработки (входные), а затем, после служебного слова Var, следуют параметры - результаты. Но есть нюансы, которые следует учитывать:
а) формальных параметров может не быть вовсе;
б) входные параметры могут быть одновременно выходными, причем не обязательно все, а лишь некоторые.
3) Глобальные переменные могут быть использованы в теле процедуры, но в том же качестве, что и в основной программе.
4) Локальные переменные (их может и не быть) сосредоточены только в своей конкретной процедуре, и вне тела этой процедуры теряют смысл.
5) В теле основной программы, в необходимый момент (или моменты) происходит обращение к процедуре по ее имени, т.е.:
<Имя процедуры>(<фактические параметры>);
Фактические параметры – это глобальные переменные, обозначающие исходные данные и результаты. Между формальными и фактическими параметрами должно быть четкое соответствие по количеству, по типу и порядку перечисления. При обращении к процедуре происходит обмен значениями между формальными и фактическими параметрами.
Существуют стандартные процедуры. Например: ClrScr; write (x); read (x);
Задача 1. Сформировать массив из n элементов, которые вычисляются по формуле a[i] = 1 / (i!). Пояснение: i! - это факториал числа i, который вычисляется как произведение чисел от 1 до i включительно.
Решение:
Подпрограмма-процедура, будет использована для вычисления факториала любого целого числа k.
Const t = 100;
Var a : array[1..t] of real;
i, n : integer; x : longint;
Procedure factor(k : integer; var f : longint);
 Var j : integer;
 Begin
 F := 1; For j := 1 to k do f := f * j;
 End;
Begin
Read (n);
For i := 1 to n do begin factor(i, x); a[i] := 1 / x; end;
For i := 1 to n do write(a[i] : 5 : 6, ' ');
End.
При обращении к процедуре factor значение переменной i будет передано в процедуру в переменную k, будет рассчитан факториал f и возвращен в программу в переменную x.


Задача 2. Вывести все четырехзначные числа вида abcd, для которых выполняются условия:
1) a, b, c, d - разные цифры;
2) a * b - c * d = a + b + c + d.
Решение:
Переберем все четырехзначные числа и с помощью процедуры проверим каждое число на выполнение предложенного условия.
Var i : integer;
Procedure thislo(k : integer);
 Var a, b, c, d : integer;
 Begin
 a := k div 1000;
 b := (k div 100) mod 10;
 c := (k div 10) mod 10;
 d := k mod 10;
 if (a <> b) and (a <> c) and (a <> d) and (b <> c) and (b <> d) and (c <> d) and (a * b - c * d = a + b + c + d) then writeln (k);
 end;
Begin
For i := 1000 to 9999 do thislo(i);
End.
В предложенном варианте решения, процедура не содержит переменной-результата. Она является процессом проверки числа, которое, в случае выполнения условия,выводится самой процедурой.


Задача 3. Дан массив целых чисел. Перевернуть его элементы (поставить цифры каждого элемента в обратном порядке).
Решение:
Подпрограмма-процедура, будет использована для перевертывания любого целого числа k.
Const t = 100;
Var a : array[1..t] of integer;
i, n : integer;
Procedure perevert(Var k : integer);
 Var y, x : integer;
 Begin 
 y := 1;
 While k <> 0 do begin
                   x := k mod 10;
                   k := k div 10;
                   y := y * 10 + x;
                         end;
 k := y;
 end;
Begin
Read (n);
For i := 1 to n do read (a[i]);
writeln ('исходный массив');
For i := 1 to n do write(a[i], ' ');
For i := 1 to n do perevert(a[i]);
writeln ('новый массив');
For i := 1 to n do write(a[i], ' ');
End.
В предложенном варианте решения, фомальный параметр k является как входным, так и выходным. Он принимает из программы значение элемента массива, изменяет свое значение в процессе выполнения тела процедуры и возвращает новое значение в программу.

Подпрограммы-функции

Подпрограмму-функцию удобно использовать тогда, когда подпрограмма имеет одно результирующее значение простого типа. Функция может использоваться в выражениях.
Описание функции и обращение к ней:
Var
<глобальные переменные>;
Function <имя>(<формальные параметры>):<тип результата>;
 Var <локальные переменные>;
 Begin <тело функции> end;
Begin
<тело основной программы>
End.
Пояснения:
1) Имя функции строится по темже правилам, что и идентификатор переменной.
2) Формальные параметры - это локальные переменные, предназначенные для хранения данных, принятых из основной программы на обработку. Формальные параметры перечисляются в соответствии с типами и называются параметрами-аргументами.
3) В теле подпрограммы-функции имени функции обязательно должно быть присвоено значение по типу совпадающее с типом результата. Именно это значение будет передано в программу после выполнения функции.
4) Глобальные переменные могут быть использованы в теле функции, но в том же качестве, что и в основной программе.
5) Локальные переменные (их может и не быть) сосредоточены только в своей конкретной функции, и вне тела этой функции теряют смысл.
6) В теле основной программы, в необходимый момент (или моменты) происходит обращение к функции по ее имени, т.е.:
<имя переменной-результата>:=<имя функции>(<фактические параметры>);
Переменная-результат и фактические параметры – это глобальные переменные. Между формальными и фактическими параметрами должно быть четкое соответствие по количеству, по типу и порядку перечисления. При обращении к функции происходит передача фактических значений в формальные параметры, вычисляется значение функции и передается в программу.
Существуют стандартные функции. Например: Sin(x), cos(x), abs(x), sqr(x) и т.д.
Внимание: переменная не может быть описана дважды!
По количеству использования процедур и функций в программе ограничений нет!


Задача 1. Найти сумму факториалов четных чисел на промежутке от 1 до n.
Решение:
Var
i, n : integer; x : longint;
Function factor(k : integer) : longint;
 Var j : integer; f : longint;
 Begin
 F := 1;
 For j := 1 to k do f := f * j;                 {вычисление факториала числа k}
 factor := f;                                          {имени функции присвоено значение}
 End;
Begin
Read (n);
For i := 1 to n do if i mod 2 = 0 then x := x + factor(i);
write (x);
End.


Задача 2. Натуральное число называется числом Армстронга, если сумма его цифр в степени количества цифр равна самому числу. Составить массив из чисел Армстронга, взятых из диапазона от 1 до n (самостоятельно решают у компьютера).
Решение:
Var mas : array [1..100] of longint;
i, n, t : longint;
Function Arm(a : longint) : longint;
 Var j, s, k, st : longint;
 Begin
 s := 0;
 k := 0;
 While a <> 0 do begin
                        x := a mod 10;
                        a := a div 10;
                        s := s + x;
                        k := k + 1;
                           end;
 st := 1;
 For j := 1 to k do st := st * s;
 Arm := st;
 End;
Begin
Read (n); t := 1;
For i := 1 to n do if i = Arm(i) then 
                                             begin
                                             mas[t] := i;
                                             t := t + 1;
                                             end;
For i := 1 to t do write(mas[t], ' ');
End.


Обратите внимание! В языке Pascal допустимы вложенные подпрограммы (подпрограмма в подпрограмме). В языке Pascal любой програмный объект (константа, переменная, тип, подпрограмма и др.) должен быть описан перед своим употреблением. Любая подпрограмма может использоваться лишь в пределах области действия ее описания.
Задача. Дан массив целых чисел. Составить массив, элементами которого являются суммы факториалов цифр элементов данного массива.
Решение:
Var mas : array [1..100] of longint; i, n : integer;        {глобальные переменные}
Function Sum(a : longint) : longint;      {функция, описанная в основной пограмме; к ней можно обращаться из основной программы}
     Var  x, y, s : longint; 
     Procedure factor(k : integer; var f : longint); {процедура, описанная в функции Sum; к ней можно обращаться как в теле программы,

                                                             так и в теле функции Sum}
       Var j : integer;
       Begin 
       F := 1; For j := 1 to k do f := f * j;
       End;
     Begin
     s := 0;
     While a <> 0 do begin
                 x := a mod 10;
                 a := a div 10;
                 Factor(x, y);        {обращение к процедуре, вычисляющей факториал}
                 s := s + y;
                              end;
    Sum:=s;
    End;
Begin
Read (n);
For i := 1 to n do read (mas[i]);
writeln ('исходный массив');
For i := 1 to n do write(mas[i], ' ');
For i := 1 to n do mas[i] :=Sum(mas[i]);       {обращение к функции, вычисляющей сумму факториалов}
writeln ('новый массив');
For i := 1 to n do write(mas[i], ' ');
End.


Замечание! Если не заострять внимание на конкретной задаче, то следует отметить, что ограничений на количество подпрограмм и на количество вложенных подпрограмм нет. К вложенной подпрограмме можно обращаться как из тела основной программы, так и из тел подпрограмм, внутри которых она описана, но не наоборот.

Рекурсивные подпрограммы

Рекурсия - это подпрограмма, которая в своем описании обращается сама к себе.
В общем виде тело рекурсии выглядит так:
 begin
 <действия на входе в рекурсию>
 If <условие-заглушка> then <рекурсия> {else ...}
 <действия на выходе из рекурсии>
 end;
В математике рекурсивным называется определение любого понятия через самого себя. Например, определение факториала числа.
n! = 1, если n = 0,
n! = n * (n - 1)!, если n > 0.
Здесь функция факториал определена через факториал. Вариант 0! = 1 является тривиальным. Но это "опорное" значение, от которого начинается раскручивание всех последующих значений факториала: 1! = 1 * 0! = 1 * 1 = 1; 2! = 2 * 1! = 2 * 1 = 2; 3! = 3 * 2! = 3 * 2 = 6 и т.д.
Рассмотрим рекурсивные подпрограммы, вычисления факториала.


Рекурсивная функция:
Var n : integer;
 Function factor(a : integer) : integer;
 begin
 if a = 0 then factor := 1 else factor := a * factor(a - 1);
 end;
Begin
read (n);
write (factor(n));
End.


Рекурсивная процедура:
Var
n, f : integer;
 Procedure factor(a : integer; var b : integer);
 begin
 if a = 0 then b := 1 else factor(a - 1, b);
 end;
Begin
read (n);
factor(n, f);
write (f);
End.


Пояснения.

Пусть, например, в основной программе в переменную n будет введено значение 3.
При вычислении подпрограммы с аргументом 3, произойдет повторное обращение к ней, но уже с аргументом 2.
При вычислении подпрограммы с аргументом 2, произойдет повторное обращение к ней, но уже с аргументом 1.
При вычислении подпрограммы с аргументом 1, произойдет повторное обращение к ней, но уже с аргументом 0.
При вычислении подпрограммы с аргументом 0, будет достигнуто условие-заглушка и получен числовой результат 1.
Затем цепочка вычислений раскрутится в обратном порядке.
Последовательность рекурсивных обащений должна обязательно выходить на тривиальный случай (выполнение условия-заглушки). Весь маршрут последовательных вхождений компьютер запоминает в специальной области памяти - стеке. Таким обазом, выполнение рекурсии происходит в два этапа: прямой ход - заполнение стека; обратный ход - цепочка вычислений по обратному маршруту, сохраненному в стеке.


Задача 1. Дано вещественное число х и целое число n. Найти xn.
Решение:
Если х = 0, то результат 0.
Если n < 0, то результат 1 / (x|n|).
Рассмотрим решение подзадачи для положительного n и не равного 0 числа х:
xn = 1, если n = 0,
xn = х * х n-1, если n > 0.
Программа:
Var
x : real; n : integer; r : real;
Function st(k : integer) : real;
 begin
 if k = 0 then st := 1 else st := x * st(n - 1);
 end;
Begin
read (x, n);
if (x < 0) or (x > 0) then 
                             begin
                             if n > 0 then r := st(n) else r := 1 / st(abs(n));
                             end;
write (r : 6 : 2);
End.


Замечание! Использование рекурсии - красивый прием с точки зрения програмистской эстетики, но не всегда рациональный. Рассмотренные задачи могут быть легко решены без использования подпрограмм.

Адрес: 614039, г. Пермь, ул. Комсомольский проспект, 45
Телефон: +7 (342) 212-80-71
E-Mail: school9-perm@ya.ru
Вопрос администратору сайта