Поясним изложенное.
.....
var
a, b: integer;
......
procedure squar(a: integer; var b: integer);
begin
a:=sqr(a);
b:=sqr(b);
writeln(‘в квадрате они выглядят так: ’,a,’, ’,b);
end;
........
begin
a:=4; b:=6;
writeln(‘внимательно посмотрите на эти числа: ’, a,’, ’, b);
squar(a,b);
writeln(‘а так а не в квадрате: ’,a, ’, ’,b);
end.
Результаты выглядят так: внимательно посмотрите на эти числа: 4, 6
в квадрате они выглядят так: 16, 36
а так а не в квадрате: 4, 36
Этот пример может служить еще и иллюстрацией механизма «закрывания» глобальной переменной а одноименной локальной: хотя переменная объявлена как глобальная (она описана в вызывающей программе перед описанием процедуры), в теле процедуры ее «закрыла» локальная переменная а, объявленная как параметр-значение.
Итак, параметры-переменные используются как средство связи алгоритма, реализованного в подпрограмме, с «внешним миром»: с помощью этих параметров подпрограмма может передавать результаты своей работы вызывающей программе. Разумеется, в распоряжении программиста всегда есть и другой способ передачи результатов - через глобальные переменные. Однако злоупотребление глобальными связями делает программу , как правило, запутанной, трудной в понимании и сложной в отладке. В соответствии с требованиями хорошего стиля программирования рекомендуется там, где это возможно, использовать передачу результатов через фактические параметры-переменные.
С другой стороны, описание всех формальных параметров как параметров-переменных нежелательно по двум причинам. Во-первых, это исключает возможность вызова подпрограммы с фактическими параметрами в виде выражений, что делает программу менее компактной. Во-вторых, и главных, в подпрограмме возможно случайное использование формального параметра, например, для временного хранения промежуточного результата, т.е. всегда существует опасность непреднамеренно «испортить» фактическую переменную. Вот почему параметры-переменные следует объявлять только те, через которые подпрограмма в действительности передает результаты вызывающей программе. Чем меньше параметров объявлено параметрами-переменными и чем меньше в подпрограмме используется глобальных переменных, тем меньше опасность получения непредусмотренных программистом побочных эффектов, связанных с вызовом подпрограммы, тем проще программа в понимании и отладке.
Существует одно обстоятельство, которое следует учитывать при выборе вида формальных параметров. Как уже говорилось, при объявлении параметра-значения осуществляется копирование фактического параметра во временную память. Если этим параметром будет массив большой размерности, то существенные затраты времени и памяти на копирование при многократных обращениях к подпрограмме могут стать peшающим доводом в пользу объявления такого параметра параметром-переменной или передачи его в качестве глобальной переменной.
Параметры массивы и параметры строки
Может сложиться впечатление, что объявление переменных в списке формальных параметров подпрограммы ничем не отличается от объявления их в разделе описания переменных. Действительно, в обоих случаях много общего, но есть одно существенное различие: типом любого параметра в списке формальных параметров может быть только стандартный или ранее объявленный тип. Поэтому нельзя, например, объявить следующую процедуру:
Procedure S (а : array (1..10] of real);
так как в списке формальных параметров фактически объявляется тип - диапазон, указывающий границы индексов массива.
Если мы хотим передать какой-то элемент массива, то проблем, как правило, не возникает, но если в подпрограмму передается весь массив, то следует первоначально описать его тип. Например:
…...
type
mas = array [1..10] of real;
.......
PROCEDURE S (a : mas);
…...
Поскольку строка является фактически своеобразным массивом, ее передача в
подпрограмму осуществляется аналогичным образом:
.......
type
intype =string[15];
outype = string[30];
FUNCTION St (i : intype) : outype:
Требование описать любой тип-массив или тип-строку перед объявлением подпрограммы на первый взгляд кажется несущественным. Действительно, в рамках простейших вычислительных задач обычно заранее известна структура всех используемых в программе данных, поэтому статическое описание массивов не вызывает проблем. Однако разработка программных средств универсального назначения связана со значительными трудностями. По существу, речь идет о том, что в Турбо Паскале невозможно использовать в подпрограммах массивы с «плавающими» границами изменения индексов. Например, если разработана программа, обрабатывающая матрицу из 10 х 10 элементов, то для обработки матрицы из 9 х 11 элементов необходимо переопределить тип, т.е. перекомпилировать всю программу. Этот недостаток, как и отсутствие в языке средств обработки исключительных ситуаций (прерываний), унаследован из стандартного Паскаля и представляет собой объект постоянной и вполне заслуженной его критики. Разработчики Турбо Паскаля не рискнули кардинально изменить свойства базового языка, но, тем не менее, включили в него некоторые средства, позволяющие в известной степени смягчить отмеченные недостатки.
Прежде всего, в среде Турбо Паскаля можно установить режим компиляции, при котором отключается контроль над совпадением длины фактического и формального параметра-строки. Это позволяет легко решить вопрос о передаче подпрограмме строки произвольной длины. При передаче строки меньшего размера формальный параметр будет иметь ту же длину, что и параметр обращения; передача строки большего размера приведет к ее усечению до максимального размера формального параметра. Следует сказать, что контроль включается только при передаче строки, объявленной как формальный параметр-переменная. Если соответствующий параметр объявлен параметром-значением, эта опция игнорируется и длина не контролируется.
Значительно сложнее обстоит дело с передачей массивов произвольной длины. Решить эту проблему при помощи не типизированных параметров
Процедурные типы
Процедурные типы - это нововведение фирмы Borland (в стандартном Паскале таких типов нет). Основное назначение этих типов - дать программисту гибкие средства передачи функций и процедур в качестве фактических параметров обращения к другим процедурам и функциям.
Для объявления процедурного типа используется заголовок процедур, в котором опускается ее имя, например:
type
Proc = Procedure (a, b, с : real; Var d : real);
Proc2 = Procedure (var a, b);
РгосЗ = Procedure;
В программе могут быть объявлены переменные процедурных типов, например, так:
var
р1 : Proc;
ар : array [1..N] of Proc2;
Переменным процедурных типов допускается присваивать в качестве значений имена соответствующих подпрограмм. После такого присваивания имя переменной становится синонимом имени подпрограммы.
В отличие от стандартного Паскаля, в Турбо Паскале разрешается использовать в передаваемой процедуре как параметры-значения, так и параметры-переменные.
Нетипизированные параметры-переменные
Еще одно и очень полезное нововведение фирмы Borland - возможность использования нетипизированных параметров. Параметр считается нетипизированным, если тип формального параметра-переменной в заголовке подпрограммы не указан, при этом соответствующий ему фактический параметр может быть переменной любого типа. Заметим, нетипизированными могут быть только параметры-переменные.
Нетипизированные параметры обычно используются в случае, когда тип данных несущественен. Такие ситуации чаще всего возникают разного рода копированиях одной области памяти в другую. Нетипизированные параметры очень удобно использовать для передачи подпрограмме одномерных массивов переменной длины.
Параметры- сложные типы данных
Рассмотрены прежде категории параметров не исчерпывают всех вопросов передачи информации в Pascal-e. Использование в качестве параметров сложных типов данных имеет свои особенности.
Рассмотрим массивы и строки открытого типа. Открытый массив (строка) – массив (строка) без указания типа индекса (размера массива(строки)).
Пример:
Procedure getfive(var massiv: array of real);
В данном случае вместо формального параметра может использоваться любой массив с элементами типа real. Индексация элементов открытого массива всегда начинается с нуля. Такие массивы введены для того, чтобы подпрограмма могла обрабатывать массивы любого размера.
Программа вычисления x=(m!+n!)/(m+n)!, где m, n целые (неотрицательные)
program factorial_(input,output); {название программы}
label 0; {описываем метку}
var
rez:real;
m,n:longint; {описали глобальные переменные, используемые в программе}
functionfact(z: longint): real; {заголовок функции с формальным параметром-значением, типом}
var
y: real; {описали локальную переменную}
begin
y:=1; {для получения результата необходимо присвоить у значение 1. также при помощи этого реализуется вычисление 0! и 1!}
whilez>1 do {запускаем цикл в обратную сторону, для упрощения опустим множитель 1}
begin
y:=y*z;
z:=z-1
end;
fact:=y{вычисляем факториал, присваиваем его значение функции}
end; {конец функции}
begin{начало тела программы}
writeln('введите неотрицательные числа'); {для удобства пользователя просим ввести числа}
0:readln(m,n); {в память вводятся числа}
if m or n <0 then begin
writeln(‘вы ошиблись, вводите неотрицательные числа’);