Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Алгоритмические языки высокого уровня. Курс лекций

.pdf
Скачиваний:
0
Добавлен:
12.08.2026
Размер:
940 Кб
Скачать

Begin

For i:=4 to 25 do For j:=1 to 80 do Begin

Gotoxy(j,i); write(“”); End;

Gotoxy(1,4); While p1<>nil do Begin

Write(“ Val - ”, p1^.val,”;”); P1:=p1^.Next;

End;

End;

Procedure Add_Element(var p_uk:uk); Begin

New(p_pr); P_pr^.next:=nil; K:=k+1; P_pr^.val:=k;

If p_uk=nil then Begin P_beg:=p_pr; P_end:=p_pr; End

Else Begin

P_uk^.next:=p_pr; P_uk:=p_pr;

End;

End;

Procedure Del_Element(var p_uk:uk); Begin

If p_uk<>nil then Begin P_pr:=p_uk;

P_uk:=p_uk^.next; Dispose(p_pr); End

else begin

gotoxy(1,4); write(“spisok - pust” ); p_end:=nil;

end;

end;

begin {основная программа} clrscr;

p_beg:=nil; p_end:=nil; new(p_pr);

p_pr^.Next:=nil;

121

p_pr^.val:=1; p_beg:=p_pr; p_end:=p_pr;

k:=3; fin:=false; while not Fin do

begin gotoxy(1,1);

write(“1-Vivod spisok,”,“2–add element,”,“3- delete”,“4-exit”);

ch:=readkey; write(ch); case ch of

“1”: Vivod_Spisok(p_beg); “2”: Add_Element(p_end); “3”: Del_Element(p_beg); “4”: fin:=true;

end;

end;

end.

122

5.ПРОЦЕДУРЫ И ФУНКЦИИ

ВPascal предусмотрены средства, позволяющие оформлять вспо- могательный фрагмент как подпрограмму. Это бывает необходимо, когда какие-либо действия неоднократно повторяются в программе или имеется возможность использовать некоторые фрагменты уже разработанных ранее алгоритмов. Кроме того, подпрограммы приме- няются для разбиения крупных программ на отдельные смысловые части в соответствии с модульным принципом в программировании (в языке имеется два вида подпрограмм процедуры и функции).

Для использования фрагмента в качестве подпрограммы ему не- обходимо присвоить имя и описать алгоритм по правилам языка Pascal. В дальнейшем, при необходимости вызвать его в программе, делают вызов подпрограммы упоминанием в нужном месте имени соответствующего подалгоритма со списком входных и выходных данных. Такое упоминание приводит к выполнению входящих в подпрограмму операторов, работающих с указанными данными. По- сле выполнения подпрограммы работа продолжается с той команды, которая непосредственно следует за вызовом подпрограммы. Проце- дуры и функции помещаются в раздел описаний программы. Для об- мена информацией между процедурами и функциями и другими бло- ками программы существует механизм входных и выходных пара- метров. Входными параметрами называют величины, передающиеся из вызывающего блока в подпрограмму (исходные данные для под- программы), а выходными передающиеся из подрограммы в вызы- вающий блок (результаты работы подпрограммы). Подпрограмма может вызываться неоднократно, выполняя одни и те же действия с разными наборами входных данных. Параметры, использующиеся при записи текста подпрограммы в разделе описаний, называют фор- мальными, а те, что используются при ее вызове, – фактическими.

5.1.Описание и вызов процедур и функций

Структура описания процедур и функций до некоторой степени похожа на структуру Pascal-программы: у них также имеются заго- ловок, раздел описаний и исполняемая часть. Раздел описаний со- держит те же подразделы, что и раздел описаний программы: описа- ния констант, типов, меток, процедур, функций, переменных. Испол- няемая часть содержит собственно операторы процедур.

123

Формат описания процедуры:

procedure имя процедуры (формальные параметры); {раздел описаний процедуры}

begin

{исполняемая часть процедуры} end;

Формат описания функции:

function имя функции (формальные параметры):тип результата;

{раздел описаний функции} begin

{исполняемая часть функции} end;

Формальные параметры в заголовке процедур и функций записы- ваются в виде:

var имя праметра: имя типа

и отделяются друг от друга точкой с запятой. Ключевое слово var может отсутствовать (об этом далее). Если параметры однотипны, то их имена можно перечислять через запятую, указывая общее для них имя типа. При описании параметров можно использовать только стандартные имена типов, либо имена типов, определенные с помо- щью команды type. Список формальных параметров может отсут- ствовать.

Вызов процедуры производится оператором, имеющим следую- щий формат:

имя процедуры(список фактических параметров);

При вызове фактические параметры как бы подставляются вместо формальных, стоящих на тех же местах в заголовке. Таким образом происходит передача входных параметров, затем выполняются опе- раторы исполняемой части процедуры, после чего происходит воз- врат в вызывающий блок. Передача выходных параметров происхо- дит непосредственно во время работы исполняемой части. Вызов функции в Pascal может производиться аналогичным способом, кро- ме того имеется возможность осуществить вызов внутри какого-либо выражения. В частности имя функции может стоять в правой части оператора присваивания, в разделе условий оператора if и т.д.

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

имя функции := результат;

124

При вызове процедур и функций необходимо соблюдать следую- щие правила:

количество фактических параметров должно совпадать с коли- чеством формальных;

соответствующие фактические и формальные параметры долж- ны совпадать по порядку следования и по типу.

Замечание: имена формальных и фактических параметров могут совпадать. Это не приводит к проблемам, так как соответствую- щие им переменные все равно будут различны из-за того, что хра- нятся в разных областях памяти. Кроме того, все формальные па- раметры являются временными переменными они создаются в момент вызова подпрограммы и уничтожаются в момент выхода из нее.

Пример использования процедуры

(программа поиска максимума из двух целых чисел)

var x,y,m,n: integer;

procedure MaxNumber(a,b: integer; var max: integer); begin

if a>b then max:=a else max:=b; end;

begin

write('Введите x,y '); readln(x,y); MaxNumber(x,y,m); MaxNumber(2,x+y,n); writeln('m=',m,'n=',n);

end.

Пример использования функции

(программа поиска максимума из двух целых чисел)

var x,y,m,n: integer;

function MaxNumber(a,b: integer): integer; var max: integer;

begin

if a>b then max:=a else max:=b; MaxNumber := max;

end; begin

write('Введите x,y '); readln(x,y);

m := MaxNumber(x,y);

n := MaxNumber(2,x+y); writeln('m=',m,'n=',n);

end.

Program test1;

125

Const i1=1; I2=2;

Procedure D (var i1:byte, I2:byte); Begin

I1:=i1*2;

I2:=i2*2; Write (i1, i2);

End;

Begin D(i1, i2);

Write (i1, 2); End.

Результатом работы программы будет:

12

22

Рекурсией называется процедура или функция, которая содержит обращение к самой себе. Такая рекурсия называется прямой. При косвенной рекурсии две или более подпрограммы (процедуры, функ- ции) вызывают друг друга. Рекурсивная подпрограмма должна со- держать хотя бы одну ветвь, заканчивающуюся возвратом в вызы- вающую программу.

Пример рекурсии: вычисление факториала.

Чтобы получить значение факториала числа n, требуется ум- ножить на n факториал числа (n-1). Известно, что 0!=1 и 1!=1.

Function fact(n:byte):longint; Begin

If (n=0) or (n=1) then fact:=1

else fact:=n*fact(n-1);

End;

Достоинством рекурсии является компактная запись, недостатка- ми опасность переполнения стека, а также расход времени и памя- ти на повторные вызовы функции.

Передача параметров. В стандарте языка Pascal передача парамет- ров может производиться двумя способами по значению и по ссылке. Параметры, передаваемые по значению, называют параметрамизначениями, передаваемые по ссылке параметрамипеременными.

Последние отличаются тем, что в заголовке процедуры (функции) перед ними ставится служебное слово var.

126

При первом способе (передача по значению) значения фактиче- ских параметров копируются в соответствующие формальные пара- метры. При изменении этих значений в ходе выполнения процедуры (функции) исходные данные (фактические параметры) измениться не могут. Поэтому таким способом передают данные только из вызы- вающего блока в подпрограмму (т.е. входные параметры). При этом в качестве фактических параметров можно использовать и констан- ты, и переменные, и выражения.

При втором способе (передача по ссылке) все изменения, проис- ходящие в теле процедуры (функции) с формальными параметрами, приводят к немедленным аналогичным изменениям соответствую- щих им фактических параметров. Изменения происходят с перемен- ными вызывающего блока, поэтому по ссылке передаются выходные параметры. При вызове соответствующие им фактические параметры могут быть только переменными.

Выбор способа передачи параметров при создании процедуры (функции) происходит в соответствии со сказанным выше: входные параметры нужно передавать по значению, а выходные по ссылке. Практически это сводится к расстановке в заголовке процедуры (функции) описателя var при всех параметрах, которые обозначают результат работы подпрограммы. Однако в связи с тем, что функция возвращает только один результат, в ее заголовке использовать па- раметрыпеременные не рекомендуется.

Локальные и глобальные идентификаторы. Использование процедур и функций в Pascal тесно связано с некоторыми особенно- стями работы с идентификаторами (именами) в программе. В частно- сти, не все имена всегда доступны для использования. Доступ к идентификатору в конкретный момент времени определяется тем, в каком блоке он описан.

Имена, описанные в заголовке или разделе описаний процедуры или функции, называют локальными для этого блока. Имена, опи- санные в блоке, соответствующем всей программе, называют гло- бальными. Следует помнить, что формальные параметры процедур и функций всегда являются локальными переменными для соответ- ствующих блоков.

Основные правила работы с глобальными и локальными именами можно сформулировать так:

локальные имена доступны (считаются известными, «видимы- ми») только внутри того блока, где они описаны. Сам этот блок и все

127

другие, вложенные в него, называют областью видимости для этих локальных имен;

имена, описанные в одном блоке, могут совпадать с именами из других, как содержащих данный блок, так и вложенных в него. Это объясняется тем, что переменные, описанные в разных блоках (даже если они имеют одинаковые имена), хранятся в разных областях опе- ративной памяти;

глобальные имена хранятся в области памяти, называемой сег- ментом данных (статическим сегментом) программы. Они создают- ся на этапе компиляции и действительны на все время работы про- граммы. В отличие от них, локальные переменные хранятся в специ- альной области памяти, которая называется стек. Они являются вре- менными, так как создаются в момент входа в подпрограмму и унич- тожаются при выходе из нее.

Имя, описанное в блоке, «закрывает» совпадающие с ним имена из блоков, содержащих данные. Это означает, что если в двух бло- ках, один из которых содержится внутри другого, есть переменные с одинаковыми именами, то после входа во вложенный блок работа будет идти с локальной для данного блока переменной. Переменная с тем же именем, описанная в объемлющем блоке, становится времен- но недоступной, и это продолжается до момента выхода из вложен- ного блока.

Рекомендуется все имена, которые имеют в подпрограммах чисто внутреннее, вспомогательное назначение, делать локальными. Это предохраняет от изменений глобальные объекты с такими же имена- ми.

5.2. Параметрымассивы и параметрыстроки

Может сложиться впечатление, что объявление переменных в списке формальных параметров подпрограммы ничем не отличается от объявления их в разделе описания переменных. Действительно, в обоих случаях много общего, но есть одно существенное различие: типом любого параметра в списке формальных параметров может быть только стандартный или ранее объявленный тип. Поэтому нель- зя, например, объявить следующую процедуру:

Procedure S (a: array [1..10] of Real);

так как в списке формальных параметров фактически объявляется тип-диапазон, указывающий границы индексов массива. Если мы хотим передать какой-то элемент массива, то проблем, как правило,

128

не возникает, но если в подпрограмму передается весь массив, то следует первоначально описать его тип.

type

atype = array [1..10]of Real; Procedure S (a: atype);

Поскольку строка является фактически своеобразным массивом, ее передача в подпрограмму осуществляется аналогичным образом:

type

intype = String [15] ; outype = String [30] ;

Function St (s : intype): outype;

Требование описать любой тип-массив или тип-строку перед объ- явлением подпрограммы на первый взгляд кажется несущественным. Действительно, в рамках простейших вычислительных задач обычно заранее известна структура всех используемых в программе данных, поэтому статическое описание массивов не вызывает проблем. Одна- ко разработка программных средств универсального назначения свя- зана со значительными трудностями. По существу, речь идет о том, что в Pascal невозможно использовать в подпрограммах массивы с «плавающими» границами изменения индексов. Например, если раз- работана программа, обрабатывающая матрицу 10×10 элементов, то для обработки матрицы 9×11 элементов необходимо переопределить тип, т.е. перекомпилировать всю программу (речь идет не о динами- ческом размещении массивов в куче, а о статическом описании мас- сивов и передаче их как параметров в подпрограммы). Этот недоста- ток разработчики Turbo Pascal не рискнули кардинально изменить, но, тем не менее, включили некоторые средства, позволяющие в из- вестной степени его смягчить. Прежде всего, в среде Turbo Pascal можно установить режим компиляции, при котором отключается контроль за совпадением длины фактического и формального пара- метра-строки. Это позволяет легко решить вопрос о передаче под- программе строки произвольной длины. При передаче строки мень- шего размера формальный параметр будет иметь ту же длину, что и параметр обращения; передача строки большего размера приведет к ее усечению до максимального размера формального параметра. Следует сказать, что контроль включается только при передаче стро- ки, объявленной как формальный параметр-переменная. Если соот- ветствующий параметр объявлен параметром-значением, эта опция игнорируется и длина не контролируется. Значительно сложнее об- стоит дело с передачей массивов произвольной длины. Наиболее

129

универсальным приемом в этом случае будет работа с указателями и использование индексной арифметики. В версии Turbo Pascal 7.0 язык поддерживает так называемые открытые массивы, легко ре- шающие проблему передачи подпрограмме одномерных массивов переменной длины. Открытый массив представляет собой фор- мальный параметр подпрограммы, описывающий базовый тип эле- ментов массива, но не определяющий его размерности и границы:

Procedure MyProc(OpenArray: array of Integer);

Внутри подпрограммы такой параметр трактуется как одномер- ный массив с нулевой нижней границей. Верхняя граница открытого массива возвращается функцией HIGH. Используя 0 как минималь- ный индекс и значение, возвращаемое функцией HIGH как макси- мальный индекс, подпрограмма может обрабатывать одномерные массивы произвольной длины.

Пример программы

Описание: использование открытых массивов. Программа выво- дит на экран содержимое двух одномерных массивов разной длины с помощью одной процедуры ArrayPrint.

Procedure ArrayPrint(aArray: array of Integer); var k: Integer;

begin

for k := 0 to High(aArray) do Write(aArray[k]:8); WriteLn

end; const

A:array [-1..2] of Integer = (0,1,2,3); B: array [5..7] of Integer = (4,5,6);

begin

ArrayPrint(A);

ArrayPrint(B)

end.

Как видно из этого примера, фактические границы массивов А и В, передаваемых в качестве параметров вызова процедуре ArrayPrint, не имеют значения. Однако размерность открытых массивов (количество индексов) всегда равна 1 – за этим следит ком- пилятор. Если бы, например, мы добавили в программу двухмерный массив С:

var С: array [1..3,1..5] of Integer; то обращение

ArrayPrint(С) вызывало бы сообщение об ошибке Error26: Type mismatch (Ошибка 26: Несоответствие типов).

130

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]