Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Алгоритмизация и языки программирования. Учебно-методический комплекс.pdf
Скачиваний:
0
Добавлен:
06.09.2026
Размер:
1 Мб
Скачать
Описания двух различных подпрограмм не могут пересекаться:
каждый блок должен быть логически законченным. Однако внутри
любой подпрограммы (она ведь тоже является программой, помните?) могут быть описаны другие процедуры или функции ­вложенные. На них распространяются все те же правила объявления и описания подпрограмм.
Возвращаемые значения
Основное различие между функциями и процедурами состоит в количестве возвращаемых ими значений.
Любая функция, завершив свою работу, должна вернуть основ-
ной программе (или другой вызвавшей ее подпрограмме) ровно одно значение, причем его тип нужно явным образом указать уже при
объявлении функции.
Для возвращения результата применяется специальная "пере­менная", имеющая имя, совпадающее с именем самой функции.
Оператор присваивания значения этой "переменной" обязательно
должен встречаться в теле функции хотя бы один раз.
Например:
function min(a,b: integer): integer; begin
if a>b then min:= b
else min:= a
end;
Вызов подпрограмм
Любая подпрограмма может быть вызвана не только из основ­ного тела программы, но и из любой другой подпрограммы, объяв­ленной позже нее.
При вызове в подпрограмму передаются фактические пара­метры или аргументы (в круглых скобках после имени подпро­граммы, разделенные запятыми):
<имя_подпрограммы>(<список_аргументов>)
Аргументами могут быть переменные, константы и выражения, включающие в себя вызовы функций.
Количество и типы передаваемых в подпрограмму аргументов
должны соответствовать количеству и типам ее параметров. Кроме
того, тип каждого аргумента должен обязательно учитывать способ
51
подстановки, указанный для соответствующего параметра (подроб­нее об этом будет рассказано в разделе "Способы подстановки аргу­ментов"). Если у подпрограммы вообще нет объявленных парамет­ров, то при вызове список передаваемых аргументов будет отсут­ствовать вместе с обрамляющими его скобками.
Вызов функции не может быть самостоятельным оператором, потому что возвращаемое значение нужно куда-то записывать. Зато оно может стать равноправным участником арифметического выра­жения. Например:
c:= min(a,a*2); if min(z, min(x,y))= 0 then...;
Процедура же ничего не возвращает явным образом, поэтому ее вызов является отдельным оператором в программе. Например:
err(res,'Привет!');
Замечание: После того как вызванная подпрограмма завершит
свою работу, управление передается оператору, следующему за
оператором, вызвавшим эту подпрограмму.
В качестве примера рассмотрим процедуру kwad, которая также служит для печати квадрата в процедуре:
procedure kwad;
var i:integer;
begin
for i:=1 to 3 do write(‘*’);
writeln;
write(‘* *’);
for i:=1 to 3 do write(‘*’);
writeln;
end.
Данный пример ясно показывает, что внутри процедуры также можно объявлять новые переменные. Так как эти переменные могут действовать только в самой процедуре, то говорят, что эти переменные являются локальными. Термин «локальные» объявляет, что переменные могут использоваться (имеют смысл) только в самой
процедуре.
В процедуре можно также определять метки, константы, типы и т.д. (и даже новые процедуры). Подобная процедура имеет точно
52
такую же структуру, как и программы, которые мы до сих пор
описывали.
Процедуры с параметрами-значениями
Представьте себе, что нам нужно воспроизвести рисунок, на
котором должны быть нарисованы друг под другом квадраты и
размеры квадратов должны быть разными. Для этого случая было бы очень удобно, если бы в процедуре можно было задавать, например,
размер напечатанного квадрата.
Паскаль дает такую возможность задавать параметры, прини­мающие определенные значения в процедуре – «параметры-зна-
чения».
Когда в качестве параметров задаются переменные, которые должны подвергаться определенной обработке, тогда речь идет о
«параметрах-переменных» (или о параметрах, вызываемых по имени переменной).
Уточним еще раз, заголовок процедуры имеет вид:
procedure <имя >(<описание формальных параметров)>;
Формальные параметры – переменные, используемые внутри
процедуры и принимающие различные начальные и конечные значения для каждого вызова процедуры. Описание формальных
параметров имеет вид:
var <список_формальных_параметров>: <имя_типа>;
Список формальных параметров может состоять из одного параметра или нескольких параметров, отделенных друг от друга
запятой.
Поскольку внутри подпрограммы параметры рассматриваются
как переменные с начальным значением, то имена локальных
переменных, описываемые в разделе var (внутреннем для подпро­граммы), не могут совпадать с именами параметров этой же подпро­граммы.
Глобальные объекты - это типы данных, константы и пере-
менные, объявленные в начале программы до объявления любых подпрограмм. Эти объекты будут видны во всей программе, в том числе и во всех ее подпрограммах. Глобальные объекты существуют
на протяжении всего времени работы программы.
53
Локальные объекты объявляются внутри какой-нибудь подпро­граммы и "видны" только этой подпрограмме и тем подпрограммам, которые были объявлены как внутренние для нее. Локальные объек-
ты не существуют, пока не вызвана подпрограмма, в которой они
объявлены, а также после завершения ее работы.
Список параметров может и вовсе отсутствовать:
procedure proc1;
function func1: boolean;
В этом случае подпрограмма не получает никаких переменных
"извне". Упомянутый в начале лекции песенный припев как раз и является примером подпрограммы, в которую не передается никаких
данных при вызове.
Однако отсутствие параметров и, как следствие, передаваемых извне значений вовсе не означает, что при каждом вызове подпро­грамма будет выполнять абсолютно одинаковые действия. Поскольку глобальные переменные видны изнутри любой подпрограммы, их значения могут неявно изменять внутреннее состояние подпрограмм.
Если способ подстановки и тип нескольких параметров совпа­дают, описание этих параметров можно объединить:
[<способ_подстановки>]<имя1>,...,<имяN>: <тип>;
В заголовке подпрограммы можно указывать только простые (не составные) типы данных. Следовательно, попытка записать
procedure proc2(a: array[1..100]of char);
вызовет ошибку уже на этапе компиляции. Для того чтобы обойти это ограничение, составной тип данных нужно описать в
разделе type, а при объявлении подпрограммы воспользоваться именем этого типа:
type arr = array[1..100] of char;
procedure proc2(a: arr);
Параметр-переменная
Описание
В списке параметров подпрограммы перед параметром­переменной ставится служебное слово var. Например, процедура
proc3 имеет три параметра-переменные и один параметр-значение:
procedure proc3(var x,y:real; var k:integer; flag:boolean);
54
При вызове подпрограммы параметру-переменной может соот­ветствовать только аргумент-переменная; константы и выражения запрещены. Кроме того, тип аргумента и тип параметра-переменной должны быть эквивалентными.
Механизм передачи значения
В отличие от параметра-значения, для параметра-переменной не создается копии при вызове подпрограммы. Вместо этого в работе подпрограммы участвует та самая переменная, которая послужила
аргументом. Понятно, что если ее значение изменится в процессе работы подпрограммы, то это изменение сохранится и после того, как
будет уничтожен контекст подпрограммы. Понятно опять же и ограничение на аргументы, которые должны соответствовать пара­метрам-переменным: ни константа, ни выражение не смогут сохра­нить изменения, внесенные в процессе работы подпрограммы.
Итак, параметры-переменные и служат теми посредниками,
которые позволяют получать результаты работы процедур, а также
увеличивать количество результатов, возвращаемых функциями.
Замечание: Для экономии памяти в параметр-переменную мож-
но передавать и такую переменную, изменять значение которой не
требуется. Скажем, если нужно передать в качестве аргумента массив, то лучше не создавать его копию, как это будет сделано при исполь­зовании параметра-значения, а использовать параметр-переменную.
Параметр-константа
Описание
В списке параметров подпрограммы перед параметром-кон­стантой ставится служебное слово const. Например, процедура proc4 имеет один параметр-переменную и один параметр-константу:
procedure proc4(var k:integer; const flag:boolean);
При вызове подпрограммы параметру-константе может соответ­ствовать аргумент, являющийся выражением, переменной или кон­стантой. Во время выполнения подпрограммы соответствующая пере-
менная считается обычной константой. Ограничением является то,
что при вызове другой подпрограммы из тела текущего параметра­константе не может быть подставлен в качестве аргумента в пара­метр-переменную.
55
Для типов данных здесь не обязательно строгое совпадение
program prim1;
end.
program prim2;
end.
(эквивалентность), достаточно и совместимости по присваиванию.
Механизм передачи значения
В некоторых источниках можно встретить утверждение о том,
что для параметра-константы, как и для параметра-переменной, не создается копии в момент вызова подпрограммы. Однако выполнение
простейшей проверки доказывает обратное: физические адреса
переменной а и параметра с различаются. Следовательно, в памяти
эти переменные занимают разные позиции, а не одну, как было бы в
случае параметра-переменной. Вы можете убедиться в этом само-
стоятельно, запустив данную программу в трех разных вариантах
(для параметра-значения, параметра-переменной и параметра-кон­станты), а затем сравнить результаты.

Функции

Выше мы уже говорили о том, что функция подобно процедуре
может восприниматься как отдельная программа. Однако резуль-
татом выполнения функции всегда будет определенное число. Это
почти единственная разница между процедурой и функцией.
Чтобы выявить соответствие и различие, ниже приводятся два примера одного типа. В этих программах демонстрируется обычное сложение. В одной программе используется процедура, в другой
функция.
var a : integer; procedure sum(b,c: integer; var k:integer); begin
k:=b+c;
end;
var a : integer; function sum(b,c: integer):
integer;
begin
sum:=b+c;
end;
begin
sum(12,3, a); writeln(‘sum=’,a);
begin
a:=sum(12,3); writeln(‘sum=’,a);
56
Обратите внимание на то, что результат процедуры присваи­вается переменной.
Мы вызываем процедуру с помощью выражения sum(12,3,a).
Таким образом, результат выполнения процедуры присваивается
переменной а. Описанный способ всегда используется для при­своения результата глобальной переменной (переменная a объявлена вне процедуры).
В программе с функцией целой переменной a присваивается результат вычисления функции sum(12,3): a:=sum(12,3).
Сравните это выражение с выражениями, где используются
стандартные функции, например, a:=sqr(2).
Мы видим, что имя функции всегда стоит справа от знака равенства и непосредственно после имени записывается в скобках
значение аргумента функции. Слева от знака равенства стоит пере­менная, которой в конечном итоге присваивается значение функции.
Вам будет понятно, что с помощью выражения a:=sum(12,3) целой переменной a присваивается сумма целочисленных значений 12 и 3.
Обратите внимание на заголовок функции.
Сходство между процедурой и функцией заключается в том, что в обоих случаях используется блок структура, при которой могут
быть объявлены новые переменные, метки и т.д.
Различие состоит в том, что значение у функции всегда должно
рассчитываться. Тип этого значения должен объявляться в заголовке. Кроме того, у функции, по крайней мере, 1 раз должно встречаться
имя функции, стоящее слева от оператора присваивания и выра­жения, вычисляющего конечное значение.
Параметр-значение
Описание
В списке параметров подпрограммы перед параметром-значе­нием служебное слово отсутствует. Например, функция func3 имеет три параметра-значения:
function func3(x:real; k:integer; flag:boolean):real;
При вызове подпрограммы параметру-значению может соот-
ветствовать аргумент, являющийся выражением, переменной или
константой, например:
dlina:= func3(shirina/2, min(a shl 1,ord('y')), true)+0.5;
57
Для типов данных здесь не обязательно строгое совпадение
(эквивалентность), достаточно и совместимости по присваиванию.
Механизм передачи значения
В области памяти, выделяемой для работы вызываемой
подпрограммы, создается переменная с именем <имя_подпро- граммы>.<имя_параметра>, и в эту переменную записывается значение переданного в соответствующий параметр аргумента.
Дальнейшие действия, производимые подпрограммой, выполняются
именно над этой новой переменной. Значение же входного аргумента не затрагивается. Следовательно, после окончания работы подпро­граммы, когда весь ее временный контекст будет уничтожен, зна­чение аргумента останется точно таким же, каким оно было на момент вызова подпрограммы.
В качестве примера рассмотрим последовательность действий,
выполняемых при передаче аргументов 1+а/2, а и true в описанную выше функцию func3. Пусть а - переменная, имеющая тип byte, тогда значение выражения 1+a/2 будет иметь тип real, а true и вовсе является константой (неименованной).
Итак, при вызове func3(1+a/2,a,true) будут выполнены сле­дующие действия:
1) создать временные переменные func3.x, func3.k, func3.flag;
2) вычислить значение выражения 1+а/2 и записать его в
переменную func3.x;
3) записать в переменную func3.k значение переменной а;
4) записать в переменную func3.flag значение константы true;
5) произвести действия, описанные в теле функции;
6) уничтожить все временные переменные, в том числе func3.x,
func3.k, func3.flag.
Уже видно, что значения аргументов не изменятся.
Замечание: При использовании параметров-значений в кон­тексте подпрограммы создаются хотя и временные, но вполне
полноценные копии входных аргументов. Поэтому нежелательно
передавать в параметры-значения "большие" аргументы (например, массивы): они будут занимать много лишней памяти.
58

Тема 11. Множества (Set)

Еще один структурированный тип данных - это множество (set).
В нем может содержаться не более 256 элементов. Важное отличие множества от остальных структурированных типов состоит в том, что
его элементы не являются упорядоченными.
Описание множеств
В разделе var множества описываются следующим образом:
var <имя_множества>: set of <тип_элементов_множества>;
Элементы могут принадлежать к любому порядковому типу,
размер которого не превышает 1 байт (256 элементов). Например:
var s1: set of char; {множество из 256-ти элементов} s2: set of 'a'..'z','A'..'Z'; {множество из 52-х элементов} s3: set of 0..10; {множество из 11-ти элементов} s4: set of boolean; {множество из 2-х элементов}
Множество-константа
Неименованная константа
Множество можно задать неименованной константой прямо в тексте программы. Для этого необходимо заключить список
элементов создаваемого множества в квадратные скобки:
[<список_элементов>]
Список элементов может быть задан перечислением элемен­тов нового множества через запятую, интервалом или объедине­нием этих двух способов. Элементы и границы интервалов могут быть переменными, константами и выражениями. Если левая грани-
ца интервала окажется больше правой, результатом будет пустое
множество.
Примеры конструирования и использования различных мно­жеств:
Нетипизированная константа
if c in ['a','e','i','o','u'] then writeln('Гласная буква'); if set1 < [k*2+1..n,13] then set1:=[];
59
Множество - это структурированный тип данных, поэтому его
1) Пересечение двух множеств s1 и s2:
s:=s1*s2;
2) Объединение двух множеств s1 и s2:
s:=s1+s2;
3) Разность двух множеств s1 и s2 (все элементы, которые
множеству s2):
s:=s1-s2;
4) Проверка принадлежности элемента el множеству s (результат этой операции имеет тип boolean):
el in s
5) Обозначение для пустого множества:
[]
6) Создание множества из списка элементов:
s:=[e1,_,eN];
7) Проверка двух множеств на равенство или строгое
s1 = s2
s1 < s2
невозможно задать нетипизированной константой.
Типизированная константа
Задать множество как типизированную константу можно в
разделе const:
<имя_константы>:set of <тип_элементов> =[<список_элементов>];
Например:
type cipher = set of '0'..'9'; const odds: cipher = ['1','3','5','7','9']; vowels: set of 'a'..'z' = ['a','o','e','u','i'];
Операции с множествами
Все теоретико-множественные операции реализованы и в языке Pascal:
принадлежат множеству s1 и одновременно не принадлежат
включение (результат этих операций имеет тип boolean):
s1 > s2
Не существует никакой процедуры, позволяющей распечатать
содержимое множества. Это приходится делать следующим образом:
{s: set of type1; k: type1}
for k:= min_type1 to max_type1
do if k in s then write(k);
Представление множеств массивами
Одно из основных неудобств при работе с множествами - это ограничение размера всего лишь 256-ю элементами. Мы приведем
здесь два очень похожих способа представления больших множеств
массивами. Единственным условием является наличие некоторого
внутреннего порядка среди представляемых элементов: без этого
невозможно будет их перенумеровать.
60
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]