Механизм передачи параметров
В заголовках процедур и функций может быть задан список формальных параметров - имен для обозначения исходных данных и результатов работы процедуры.
При вызове подпрограммы на их место будут поставлены конкретные значения.
Список формальных параметров может включать в себя:
- параметры-значения;
- параметры-переменные;
- параметры-процедуры;
- параметры-функции;
- нетипизированные параметры.
В списке имена формальных параметров отделяются друг от друга точкой с запятой, а от типа имя параметра отделяется двоеточием.
Примеры заголовков:
procedure P (procedure B; function C: real; Q, W, R: char);
procedure A;
Между формальными и фактическими параметрами должно быть полное соответствие:
- формальных и фактических параметров должно быть одинаковое количество;
- порядок следования формальных и фактических параметров должен быть один и тот же;
- тип каждого фактического параметра должен совпадать с типом соответствующего формального параметра.
Параметры-значения используются для передачи исходных данных основной программы в подпрограмму. В списке формальных параметров они перечисляются через запятую с обязательным указанием типов.
procedure Abort (Msg: string);
function Step (N: integer; X: real): real;
Фактическим параметром может быть произвольное выражение, которое вычисляется и используется как начальное значение формального параметра, т.е. происходит подстановка значений.
Параметры-значения в ходе выполнения подпрограммы могут изменяться, поэтому их нельзя использовать для передачи результатов из подпрограммы в основную программу.
Пример:
Program Par_Znach;
var
A, B: real;
procedure Sum_Square (X, Y: real); {X, Y - формальные параметры}
begin
X := X*X;
Y := Y*Y;
Writeln ('Сумма квадратов =', X + Y);
end;
begin
A := 1.5;
B := 3.4;
Sum_Square (A, B); {Вызов процедуры с передачей ей фактических параметров А и В}
end.
Параметры-переменные используются для определения результатов выполнения процедуры и в списке формальных параметров перечисляются после зарезервированного слова var с обязательным указателем типа.
Procedure Example (var M, N: integer; var Y: real);
Изменение параметра-переменной приводит к изменению фактического параметра в вызывающей программе.
Т.е. результаты работы процедуры возвращаются в вызываемую программу только через параметры-переменные.
Пример:
Program Sum_Sub_Square;
var
A, B: real;
Sum AB, Sub AB: real; {Sum, Sub - параметры-переменные}
procedure Sum_Sub (X, Y: real; var Sum, Sub: real);
begin
Sum := X*X + Y*Y;
Sub := X*X - Y*Y;
end;
begin
A := 1.5;
B := 3.4;
Sum_Sub (A, B, Sum AB, Sub AB); {вызов процедуры с передачей значений фак. Параметров А и В и параметров-переменных Sum AB и Sub AB}
Writeln ('Сумма квадратов чисел', A, 'и', B, '=', Sum AB);
Writeln ('Разность квадратов чисел', A, 'и', B, '=', Sub AB);
end.
Параметры-процедуры и параметры-функции.
Turbo Pascal рассматривает процедуры и функции как объекты, которые присваиваются переменным, которые называются процедурными, и могут выступать в качестве формальных параметров при вызове процедур и функций.
Процедурной переменной можно присвоить процедурные значения, которые могут быть и идентификаторами процедур или функций.
Переменные в левой и правой части должны быть совместимыми по присваиванию, т.е. должны иметь:
- одинаковое число параметров;
- параметры в соответствующих позициях должны быть тождественными;
- типы результатов функций должны быть идентичны.
Если процедура или функция присваивается процедурной переменной, то она должна удовлетворять следующим требованиям:
- объявляться с директивой far компилироваться в состоянии {$F+}
- не должна быть: 1) стандартной процедурой или функцией;
2) вложенной процедурой или функцией;
3) inline процедурой или функцией;
4) interrupt процедурой или функцией.
При использовании параметров-процедур или параметров-функций в списке перед соответствующими формальными параметрами указывается зарезервированное слово procedure или function:
Procedure Example (K, L: intrgrt; var M: real; procedure Prob; function Step: real);
где K, L - параметры-значения,
М - параметр-переменная,
Prob - параметр-процедура,
Step - параметр-функция.
Пример: программа, в которой с помощью одной и той же процедуры печати таблицы производится вывод на экран трех таблиц арифметических функций (сложения, умножения и произведения суммы на разность чисел).
Program Demo_Tab1;
type
Func = function (X, Y: integer_: integer; {описание процедурного типа Func}
{$F+}
function Add (X, Y: integer): integer; {описание функции сложения двух чисел}
begin
Add := X + Y;
end;
function Mult (X, Y: integer): integer; {описание функции умножения 2-х чисел}
begin
Mult := X*Y;
end;
function Funny (X, Y: integer): integer; {описание функции умножения суммы на разность 2-х целых чисел}
begin
Funny := (X + Y)*(X + Y);
end;
{$F-}
procedure Type_Tab1 (W, H: integer; Operation: Func); {описание процедуры вывод таблицы из 2-х чисел от 1 до 10}
var
X, Y: integer;
begin
for Y := 1 to H do
begin
for X := 1 to W do
Write (operation (X, Y): 5);
Writeln;
end;
end;
begin {начало главной программы}
Type_Tab1 (10, 10, Add); {Вызов процедур
Type_Tab1 (10, 10, Mult); печати таблиц: +, - и
Type_Tab1 (10, 10, Funny); произведения}
end.
Область действия параметров
Все объекты, описываемые после заголовка процедуры, называются локальными и доступны в пределах этой процедуры.
Все объекты, описанные в вызывающей программе, называются глобальными и являются доступными внутри процедур, вызываемыз
программой.
Структура блоков некоторой Pascal-программы:
Для доступа к объектам, описанным в различных блоках, требуется соблюдать следующие правила:
1. Имена объектов, описанных в некотором блоке, считаются известными в пределах данного блока, включая и вложенные.
2. Имена блоков, описанных в блоке, должны быть универсальны в пределах данного блока и могут совпадать с именами в других блоках.
3. Если в некотором блоке описан объект, имя которого совпадает с именем объекта, описанного в объемлющем блоке, то это последнее имя не доступно в данном блоке.
В предыдущей схеме:
Объекты, описанные в блоке В известны еще и в блоках С и D, но неизвестны в блоке А. объекты, описанные в блоке F известны только в пределах этого блока.
Пример:
Program Example_proc;
procedure P;
procedure A;
var J: integer; {локальная переменная J является глобальной по
отношению к процедуре В}
procedure B;
var J: integer;
begin
Writeln (J);
end;
begin
J := 1;
B; {Вывод процедуры В}
end;
begin
A; {Вывод процедуры А}
End
Билет 31
Функция
Подпрограмма-функция служит, как правило, для получения одного результата простого типа, типа «указатель» или стандартных типов string и PChar.
Функция представляет собой отдельную программную единицу, структура которой идентична структуре основной программы, за исключением заголовка:
function FuncName (q1: t1; q2: t2; . . .): FuncType;
<Раздел описаний локальных объектов>
begin {FuncName}
p1;
. . .
pn;
FuncName := . . .; {Возвращаемый результат функции}
end; {FuncName}
где FuncName – имя функции (имеет статус переменной);
qi – имена формальных параметров;
ti – идентификаторы типов формальных параметров;
FuncType – идентификатор типа результата (имени) функции;
pj – операторы тела функции.
Основные правила оформления и использования функций:
1. Описание подпрограммы располагается в разделе описаний основной программы после раздела var.
2. Формальные параметры не имеют конкретных значений, они лишь обозначают место и действия, которые нужно совершить над фактическими параметрами.
Например: если f (x) =
то f (5) =
Здесь x – формальный, а 5 – фактический параметр.
3. Объекты (метки, константы, типы, переменные и т.д.), описанные внутри подпрограммы, являются локальными, т.е. действуют только в пределах данной подпрограммы. Объекты, описанные в основной программе, являются глобальными, т.е. действуют как внутри подпрограммы, так и в основной программе.
Это означает, в частности, что подпрограмма может модифицировать (изменять) глобальные переменные, что чаще всего нежелательно или чревато трудно диагностируемыми ошибками. Поэтому следует по возможности все переменные, с которыми оперирует подпрограмма, описывать как локальные. Особенно это касается параметров циклов for – do, для них это требование обязательно.
4. Обращение к функции в основной программе осуществляется автоматически при использовании ее имени со списком фактических параметров в качестве операнда выражения, например:
r := . . . + FuncName (b1, b2, . . .);
Перед выполнением подпрограммы формальные параметры автоматически заменяются на фактические. После выполнения функции результат должен быть присвоен переменной – имени функции для передачи его в вызывающую программу. Поэтому в теле функции программист должен хотя бы один раз записать имя функции в левой части оператора присваивания.
5. Должно соблюдаться взаимооднозначное соответствие между фактическими и формальными параметрами подпрограмм по количеству, порядку следования в списке и типу.
Пример: составить программу для вычисления количества сочетаний из n по m
1(13.1)
Сочетаниями из n элементов по m называется их соединения (комбинации), различающиеся друг от друга только самими элементами, при этом порядок их следования безразличен. Например, сочетания из трех элементов a, b, c по 2:
ab; ac; bc.
Основное свойство сочетаний:
2(13.2)
Как видно из приведенных формул, количество сочетаний из n по m выражается через факториалы n, m, (n-m). Факториалом числа k (обозначается k!) называется произведение:
3(13.3)
Основное свойство факториала:
4(13.4)
Практическое вычисление количества сочетаний по формуле (13.1) нерационально, так как числитель и знаменатель содержат повторяющиеся группы сомножителей. Если применить формулы (13.2) и (13.3) и произвести соответствующие сокращения, то получим гораздо более экономичную формулу:
5(13.5)
Теперь рассмотрим программно-алгоритмическую сторону задачи. Из (13.5) видно, что для вычисления необходимо несколько раз вычислить произведение натуральных чисел с разными пределами перемножения. Поэтому целесообразно перемножение натуральных чисел от First до Last выделить в подпрограмму-функцию:
function Multiple (First, Last: Byte): Longint;
Тогда в основной программе достаточно несколько раз вызвать эту функцию при разных значениях параметров
if M < N / 2 then
Cnm := Multiple (N – M + 1, N) / Multiple (2, M)
else
Cnm := Multiple (M + 1, N) / Multiple (2, N - M);
Ниже приводится текст программы, которая выводит таблицу факториалов M и количеств сочетаний из 20 по М для всех 0 ? M ? 20.
program Combine;
{Факториалы и количество сочетаний из 20 по M}
uses
CRT;
{Глобальные описания}
const
N = 20;
var
M : Byte;
function Multiple (First, Last: Byte) : Single;
{Произведение натуральных чисел от First до Last}
var {Локальные переменные}
Mult: Single;
i: Byte;
begin {Multiple}
Mult := 1;
for i := First to Last do
Mult := Mult * i;
Multiple := Mult; {Возвращаемый результат функции}
end; {Multiple}
begin {Combine}
ClrScr; Writeln;
{"Шапка" таблицы}
Writeln (' M', ' ':10, 'Факториал M', ' ':3, '(из 20 по M)');
Writeln;
for M := 0 to N do {Перебор M}
begin
{Многократный вызов функции при разных значениях параметров}
Write (M:4, ' ', Multiple (2, M):20:0, ' '); {Факториал M}
{Количество сочетаний из N по M}
if M < N / 2 then
Writeln (Multiple (N - M + 1, N) / Multiple (2, M):10:0)
else
Writeln (Multiple (M + 1, N) / Multiple (2, N - M):10:0);
end; {for i}
end. {Combine}
Замечание по программе:
Функция k! растет очень быстро и уже при k=13 результат выходит за пределы числа максимального целого типа Longint. Поэтому для результата функции Multiple использован вещественный тип Single.
Назначение подпрограмм.
Подпрограммы изначально появились как средство оптимизации программ по объёму занимаемой памяти — они позволили не повторять в программе идентичные блоки кода, а описывать их однократно и вызывать по мере необходимости. К настоящему времени данная функция подпрограмм стала вспомогательной, главное их назначение — структуризация программы с целью удобства её понимания и сопровождения.
Выделение набора действий в подпрограмму и вызов её по мере необходимости позволяет логически выделить целостную подзадачу, имеющую типовое решение. Такое действие имеет ещё одно (помимо экономии памяти) преимущество перед повторением однотипных действий: любое изменение (исправление ошибки, оптимизация, расширение функциональности), сделанное в подпрограмме, автоматически отражается на всех её вызовах, в то время как при дублировании каждое изменение необходимо вносить в каждое вхождение изменяемого кода.
Даже в тех случаях, когда в подпрограмму выделяется однократно производимый набор действий, это оправдано, так как позволяет сократить размеры целостных блоков кода, составляющих программу, то есть сделать программу более понятной и обозримой...