Компания ALT Linux
Опубликован: 10.04.2015 | Доступ: свободный | Студентов: 762 / 0 | Длительность: 14:03:00
Специальности: Программист, Преподаватель
Лекция 4:

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

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

Подпрограмма — именованная, логически законченная группа операторов языка, которую можно вызвать для выполнения любое количество раз из различных мест программы. В языке 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 );

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

name_3;

ЗАДАЧА 4.1. Найти действительные корни квадратного уравнения ax^2 + bx + c = 0.

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

//Процедура для вычисления действительных
//корней квадратного уравнения.
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. Вводится последовательность из N целых положительных чисел. В каждом числе найти наибольшую и наименьшую цифры.

Для решения задачи создадим процедуру 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, а его все так и не проверили.