Пример 1 Написать программу вычисления площади круга с помощью функции и процедуры.
2. Примеры вызова процедуры и функции
Пример 2. Дано натуральное число n. Переставить местами первую и последнюю цифры этого числа.
Пример 3. Найти максимальную цифру в записи данного натурального числа.
3. Передача имен процедур и функций в качестве параметров
4. Примечание
Приведем примеры описания процедуры и функции:
Пример 1 Написать программу вычисления площади круга с помощью функции и процедуры.
Технология разработки программы приведена в таблице.
Таблица
N |
Этап программирования |
Выполнение |
1 |
Постановка задачи |
Написать программу вычисления площади круга с помощью функции и процедуры |
2 |
Математическое описание |
Формула для площади круга S=π∙R2 |
3 |
Разработка структограммы |
|
3.1 |
С использованием функции |
|
3.2 |
С использованием процедуры |
|
4. |
Написание программы |
|
4.1 |
С использованием функции |
Program PY; Var
R,S:real; Begin End; Begin R:=3; Writeln(R,S); End. |
4.2 |
С использованием процедуры |
Program PY; Var
R,S:real; Begin End; Begin R:=3; Writeln(R,S); End. |
5. |
Отладка и получение результатов |
Выполнить самостоятельно |
procedure
NumString(N: integer; var S: string);
var V: integer;
begin
V := Abs(N);
S := ' ';
repeat
S := Chr(N mod 10 + Ord('0')) + S;
N := N div 10;
until N = 0;
if N < 0 then S := '-' + S;
end;
function
Max(a: Vector; n: integer): real;
var x: real; i: integer;
begin
x := a[1];
for i := 2 to n do if x < a[i] then x := a[i];
Max := x;
end;
Процедура активизируется с помощью оператора процедуры, в котором содержатся имя процедуры и необходимые параметры. Операторы, которые должны выполняться при запуске процедуры, содержатся в операторной части модуля процедуры. Если в содержащемся в процедуре операторе внутри модуля процедуры используется идентификатор процедуры, то процедура будет выполняться рекурсивно (будет при выполнении обращаться сама к себе).
Пример вызова процедуры и функции:
NumString(25432, str);
rMax := Max(rV, 10);
Передача имен процедур и функций в качестве параметров.
Во многих задачах, особенно в задачах вычислительной математики, необходимо передавать имена процедур и функций в качестве параметров. Для этого в Турбо Паскаль введен новый тип данных – процедурный или функциональный, в зависимости оттого, что описывается.
Описание процедурных и функциональных типов производится в разделе описания типов:
type
FuncType = Function(z: Real): Real;
ProcType = Procedure (a,b: Real; var x,y: Real);
Функциональный и процедурный тип определяется как заголовок процедуры и функции со списком формальных параметров, но без имени. Можно определить функциональный или процедурный тип без параметров, например:
type Proc = Procedure;
После объявления процедурного или функционального типа его можно использовать для описания формальных параметров – имен процедур и функций.
Кроме того, необходимо написать те реальные процедуры или функции, имена которых будут передаваться как фактические параметры. Эти процедуры и функции должны компилироваться в режиме дальней адресации с ключом {$F+}.
Функция (в отличие от процедуры) всегда возвращает единственное значение.
Покажем, как изменится подпрограмма из примера, если ее записать в виде функции.
Function Nod(M, N : Integer) : Integer;
Begin
While M <> N Do
If M > N Then M := M - N Else N := N - M;
Nod := M
End;
Итак, после списка параметров указывается тип значения функции, а в теле функции хотя бы один раз встречается присваивание переменной, имя которой совпадает с именем функции, соответствующего значения.
Вызов функции будет следующим:
G := Nod(Abs(E), F);
Вообще, вызов функции может присутствовать в выражении, стоящем: в правой части оператора присваивания, в процедуре вывода, в качестве фактического параметра в вызове другой подпрограммы и т.д.
При решении задач целесообразно проанализировать условие, записать решение в крупных блоках (не являющихся операторами Pascal), детализировать каждый из блоков (записав в виде блоков, возможно, по-прежнему не операторов Pascal), и т.д., продолжать до тех пор, пока каждый из блоков не будет реализован с помощью операторов языка.
Пример 2. Дано натуральное число n. Переставить местами первую и последнюю цифры этого числа.
Program Integ;
Var N : Integer;
Begin
Write('Введите натуральное число: ');
ReadLn(N);
If Impossible(N)
Then WriteLn('Невозможно переставить цифры, возникнет переполнение')
Else Begin
Change(N);
WriteLn('Ответ: ', N)
End;
End.
Можно заметить, что необходимо детализировать логическую функцию Impossible, которая диагностирует, возможна ли перестановка, и процедуру Change, которая эту перестановку (в случае, если она возможна) выполняет.
Function Impossible(N : Integer) : Boolean;
Begin
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)
End;
Здесь необходимо детализировать функцию Number, возвращающую количество цифр в записи натурального числа (т.к. функция Impossible содержит ее вызов, то в разделе описаний функция Number должна ей предшествовать).
Function Number(N : Integer) : Integer;
Var Vsp : Integer;
Begin
Vsp := 0;
While N > 0 Do
Begin
Vsp := Vsp + 1; N := N Div 10
End;
Number := Vsp
End;
Наконец, последняя процедура.
Procedure Change(Var N : Integer);
Var Kol, P, S, R : Integer;
Begin
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
End;
Возможны также подпрограммы, которые вызывают сами себя. Они называются рекурсивными. Создание таких подпрограмм является красивым приемом программирования, но не всегда целесообразно из-за чрезмерного расхода памяти ЭВМ.
Пример 3. Найти максимальную цифру в записи данного натурального числа.
Program MaxDigit;
Type NaturLong = 1..(High(LongInt));
Digit = 0..9;
Var A : LongInt;
Function Maximum(N : LongInt) : Digit;
Begin
If N < 10
Then Maximum := N
Else If N Mod 10 > Maximum(N Div 10)
Then Maximum := N mod 10
Else Maximum := Maximum(N Div 10)
End;
Begin
Write('Введите натуральное число: ');
ReadLn(A);
WriteLn('Максимальная цифра равна ', Maximum(A))
End.
При создании функции Maximum было использовано следующее соображение: если число состоит из одной цифры, то она является максимальной, иначе если последняя цифра не является максимальной, то ее следует искать среди других цифр числа. При написании рекурсивного алгоритма следует позаботиться о граничном условии, когда цепочка рекурсивных вызовов обрывается и начинается ее обратное «раскручивание». В нашем примере это условие N < 10.
Использование процедур и функций в Паскале тесно связано с некоторыми особенностями работы с идентификаторами (именами) в программе. В частности, не все имена всегда доступны для использования. Доступ к идентификатору в конкретный момент времени определяется тем, в каком блоке он описан.
Имена, описанные в заголовке или разделе описаний процедуры или функции, называют локальными для этого блока. Имена, описанные в блоке, соответствующем всей программе, называют глобальными. Следует помнить, что формальные параметры процедур и функций всегда являются локальными переменными для соответствующих блоков.
Основные правила работы с глобальными и локальными именами можно сформулировать так:
· Локальные имена доступны (считаются известными, "видимыми") только внутри того блока, где они описаны. Сам этот блок, и все другие, вложенные в него, называют областью видимости для этих локальных имен.
· Имена, описанные в одном блоке, могут совпадать с именами из других, как содержащих данный блок, так и вложенных в него. Это объясняется тем, что переменные, описанные в разных блоках (даже если они имеют одинаковые имена), хранятся в разных областях оперативной памяти.
Глобальные имена хранятся в области памяти, называемой сегментом данных (статическим сегментом) программы. Они создаются на этапе компиляции и действительны на все время работы программы.
В отличие от них, локальные переменные хранятся в специальной области памяти, которая называется стек. Они являются временными, так как создаются в момент входа в подпрограмму и уничтожаются при выходе из нее.
Имя, описанное в блоке, "закрывает" совпадающие с ним имена из блоков, содержащие данный. Это означает, что если в двух блоках, один из которых содержится внутри другого, есть переменные с одинаковыми именами, то после входа во вложенный блок работа будет идти с локальной для данного блока переменной. Переменная с тем же именем, описанная в объемлющем блоке, становится временно недоступной и это продолжается до момента выхода из вложенного блока.
Рекомендуется все имена, которые имеют в подпрограммах чисто внутреннее, вспомогательное назначение, делать локальными. Это предохраняет от изменений глобальные объекты с такими же именами.
1. Какие алгоритмы называют вспомогательными?
2. Какое количество вспомогательных алгоритмов может присутствовать в основном алгоритме?
3. Можно ли вспомогательные алгоритмы, написанные для решения данной задачи, использовать при решении других задач, где их применение было бы целесообразно?
4. Какие параметры называют формальными? фактическими?
5. Какое соответствие должно соблюдаться между формальными и фактическими параметрами?
6. Может ли фактических параметров процедуры (функции) быть больше, чем формальных? А меньше?
7. Существуют ли подпрограммы без параметров?
8. Существуют ли ограничения на число параметров подпрограмм? Если нет, то чем же всё-таки ограничивается это количество в Turbo Pascal?
9. В каком разделе объявляются и реализуются подпрограммы в Turbo Pascal?
10. Какие виды формальных параметров существуют? Чем они отличаются друг от друга?
11. В чём состоит отличие процедур и функций?
12. В каких случаях целесообразно использовать функции?
13. Почему, если в функции используются параметры-переменные, необходимо преобразовать её в процедуру?
14. Какого типа может быть значение функции?
15. Расскажите о методе последовательной детализации при разработке программ.
16. Какие подпрограммы называют рекурсивными?
17. Что такое граничное условие при организации рекурсивной подпрограммы?