1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
program lalala; const n=5; Type mas = array[1..n,1..n] of real; vek = array[1..n] of real; const a:mas =( (1,2,0,0,0), (3,4,5,0,0), (0,6,7,8,0), (0,0,9,10,11), (0,0,0,12,13) ); b:vek = (6,13,19,25,31); Var x,k,m,t,p,q:vek; tmp,ev:real; Procedure InitMas(Var a:mas; Var b:vek); Var i,j:integer; begin write('b(',i,')='); readln(b[i]); end; Procedure Prog(Var a:mas; Var k,m,t:vek); Var i,j:integer; Begin for i:=1 to n do begin if i=1 then k[i]:=0 else k[i]:=a[i,i-1]; m[i]:=-a[i,i]; if i=n then t[i]:=0 else t[i]:=a[i,i+1]; end; end; Procedure Vec(Var a:mas; Var q,p,k,m,x:vek); Var i,j:integer; Begin p[1]:=t[1]/m[1]; q[1]:=-b[1]/m[1]; for i:=2 to n do begin p[i]:=-t[i]/(k[i]*p[i-1]-m[i]); q[i]:=(b[i]-k[i]*q[i-1])/(k[i]*p[i-1]-m[i]); end; x[n]:=(b[n]-k[n]*q[n-1])/(k[n]*p[n-1]-m[n]); for i:=n-1 downto 1 do x[i]:=p[i]*x[i+1]+q[i]; end; Procedure PrintB(Var a:mas; Var x:vek); Var i,j:integer; begin for i:=1 to n do writeln('x(',i,')=',x[i]); end; Procedure Evklid(Var a:mas); Var i,j:integer; Var ev:real; begin ev:=0; for i:=0 to n do begin for j:=0 to n do begin ev:=ev + sqrt(sqr(a[i,j])); end; end; writeln('ev=',ev); end; Procedure Proverka(Var a:mas); Var i,j:integer; f1:boolean; Begin for i:=2 to n do Begin for j:=0 to i-1 do Begin if ((a[i,j] <> 0) or (a[j,i] <> 0)) then Begin f1:= false; end; end; end; if (f1) then Begin writeln('Matrix nn'); Prog(a,k,m,t); end else Begin writeln('Error'); end; end; begin InitMas(a,b); Prog(a,k,m,t); Vec(a,p,q,k,b,x); PrintB(a,x); Evklid(a); readln(); end. |
Параметры-переменные
При
передаче параметров-переменных в
подпрограмму фактически через стек
передаются их адреса в порядке, объявленном
в заголовке подпрограммы. Следовательно,
подпрограмма имеет доступ к этим
параметрам и может их изменять.
Параметры-переменные
указываются в заголовке подпрограммы
аналогично параметру-значению, но только
перед именем параметра пишется
зарезервированное слово var.
Его действие распространяется на все
переменные, указанные до ближайшей
точки с запятой, то есть в пределах одной
группы.
Пример
procedure
maxmin(a:tArr; var max, min :real; n :word);
Тип
параметров-переменных может быть любым,
включая файловый.
При вызове
подпрограммы на месте параметра-переменной
в качестве фактического параметра
должна использоваться переменная
идентичного типа.
Пример
Функция вычисления максимального
элемента в массиве.
type tarr =
array [1..100] of integer;
{фактический
параметр должен быть переменной или
типизированной
константой типа
tarr}
function
max (var mas:tarr; n:byte):integer;
var
ma:integer;
i:byte;
begin
ma:=mas[1];
for
i:=2 to n do
if
ma<mas[i] then ma:=mas[i];
max:=ma;
end;
Этот вариант лучше предыдущего, так как в стеке не создается копия исходного массива, что улучшает быстродействие и экономит память.
Однако,
при такой передаче параметра возможно
его нежелательное
изменение.
Подпрограмма
по-прежнему может работать с одним типом
массивов.
Параметры-константы
Условие – параметр
передается в подпрограмму, но изменять
его подпрограмма не должна. Нежелательно
передавать параметр как
параметр-переменную.
Можно передать как параметр-значение,
но если этот параметр имеет большой
размер (массив, запись и т.д.), то копии
могут занять большую часть стека или
даже переполнить его. Это ведет к
уменьшению быстродействия программы.
В этой ситуации параметр лучше передать
как параметр-константу. Такой параметр,
если он структурного типа, передается
своим
адресом,
но предусмотрена его защита от изменений
(версия 7.0).
Параметр-константа
указывается в заголовке подпрограммы
аналогично параметру-значению, но перед
именем параметра записывается
зарезервированное слово const.
Действие слова const
распространяется до ближайшей точки с
запятой, т.е. в пределах одной группы.
Пример
function
NewString (const s :string) :string;
Тип
параметра-значения
может быть любым, кроме файлового.
При
вызове подпрограммы на месте
параметра-константы в качестве
фактического параметра можно использовать
любое выражение
совместимого для присваивания типа, не
содержащего файловую компоненту.
Параметр-константу
нельзя передавать в другую подпрограмму
в качестве фактического параметра.
Пример
Функция вычисления максимального
элемента в массиве.
function
max(const mas: tarr;n: byte): integer;
var
ma:integer;
i:byte;
begin
ma:=mas[1];
for i:=1
to n do
if
ma<mas[i] then ma:=mas[i];
max :=ma;
end;
Пример
const
a:
integer = 5;
b:
integer = 7;
procedure
inc(var c: integer; b: integer)
begin
c:=
c+c;
b:=
b+b;
writeln(‘удвоенные
: ’,c:
5, b:
5);
end;
begin
writeln(‘исходные
: ’,a: 5, b: 5);
inc(a,b);
writeln(‘результат
: ’,a: 5,b: 5);
end.
|
исходные |
5 |
7 |
|
удвоенные |
10 |
14 |
|
результат |
10 |
7 |
b
– параметр-значение
При
вызове вычисляется значение, полученный
результат копируется во временную
память и передается подпрограмме.
Любые
возможные изменения в подпрограмме
параметра-значения никак
не воспринимаются вызывающей программой,
т.к. в этом случае изменяется копия
фактического параметра.
а
– параметр-переменная
При
вызове подпрограмме передается сама
переменная (адрес переменной). Изменение
параметра-переменной приводит к изменению
фактического параметра в вызывающей
программе.
В
случае параметра-константы
в подпрограмму также передается адрес
области памяти, в которой располагается
переменная или вычисленное значение.
Компилятор блокирует любые присваивания
параметру-константе нового значения в
теле подпрограммы.
Пример
может служить иллюстрацией механизма
«закрывания» глобальной переменной
одноименной локальной: хотя b
объявлена как глобальная, в теле процедуры
её «закрывает» локальная, объявленная
как параметр-значение.
Параметры-переменные используются как
средство связи с внешним миром: с помощью
этих параметров подпрограмма может
передавать своей работы вызывающей
программе.
Всегда возможна
передача результатов и через глобальные
переменные.
Оценка
вариантов передачи результатов работы
подпрограммы вызывающей программе
-
злоупотребление
глобальными связями делает программу
запутанной, трудной в понимании и
сложной в отладке; -
рекомендуется,
где это возможно, использовать передачу
результатов через фактические
параметры-переменные; -
с
другой стороны, описание всех формальных
параметров, как параметров-переменных
нежелательно по двум причинам: во-первых,
это исключает возможность вызова
подпрограммы с фактическими параметрами
в виде выражений,
что делает программу менее компактной,
во-вторых, в подпрограмме возможно
случайное использование формального
параметра.
По этой
причине параметры – переменные следует
объявлять только те, через которые
подпрограмма в действительности передает
результаты вызывающей программы. Чем
меньше параметров объявлено параметрами
– переменными и чем меньше в подпрограмме
используется глобальных переменных,
тем меньше опасность получения
непредусмотренных решений и в программе
побочных эффектов, связанных с выводом
подпрограммы, тем проще программа в
понимании и отладке. По этой же причине
не рекомендуется использовать параметры
– переменные в заголовке функции: если
результатом работы функции не может
быть единственное значение, то логичнее
использовать процедуру или разбить
алгоритм на несколько подпрограмм.
Необходимо
отметить следующий момент при объявлении
параметра – значения осуществляется
копирование фактических параметров во
временную память. Если этим параметром
будет массив большой размерности, то
для сокращения затрат времени и памяти
можно осуществить, объявив этот параметр
параметром – константой. Он не копируется
во временную память, однако его любые
изменения в теле подпрограммы невозможны
– за этим следит компилятор.
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
- #
- #
- #
- #
- #
- #
- #
- #
- #
- #
- #
На занятии будет объяснен алгоритм работы с процедурами на Паскале. Будут разобраны примеры использования процедуры с параметрами и без параметров. Познакомитесь с понятиями: формальные и фактические параметры, параметр по значению и параметр по ссылкее
Содержание:
- Процедуры в Паскале
- Процедуры с параметрами. Фактические и формальные параметры
- Процедуры с параметрами. Параметр по ссылке (передача параметра по ссылке)
- Передача аргументов по значению и по ссылке
- Самостоятельная работа
Процедуры в Паскале
Подпрограмма — это фрагмент кода, который имеет свое имя и создается в случае необходимости выполнять этот код несколько (много) раз. Подпрограмма описывается единожды перед началом основной программы (до begin). Компилятор пропускает данный фрагмент кода, пока в основной программе не встретит «вызов» подпрограммы, который выглядит как обращение к ней по имени (возможно, имени с аргументами, указанными в скобках).
Во многих языках программирования подпрограммы существуют только в виде функций. Однако в Паскале подпрограмма — и функция и процедура. Разница между ними станет очевидна в данном уроке.
Итак, рассмотрим синтаксис объявления и описания процедуры в Паскале
var …;{область объявления глобальных переменных} procedure название (параметры); {начало процедуры} var …;{объявление локальных переменных} begin … {тело процедуры} end;{конец процедуры} begin … {основная программа} end.
Пример: Процедура без параметров, которая печатает 60 звездочек, каждую с новой строки
1 2 3 4 5 6 7 8 9 10 11 |
procedure pr; var i:integer; begin for i:=1 to 60 do begin {тело подпрограммы} write('*'); writeln; end; end; {конец подпрограммы} begin pr; {вызов процедуры} end. |
В данном примере работы с процедурой в Паскале очевидно, что компилятор пропустит блок описания процедуры и дойдет до основной программы (9 строка кода). И только после того, как встретится вызов процедуры (10 строка), компилятор перейдет к ее выполнению, вернувшись к строке 1.
Процедуры с параметрами. Фактические и формальные параметры
Рассмотрим пример необходимости использования процедуры.
Пример:
Построить фигуру

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

Решение на паскале:
Процедура:

Программа:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
uses GraphABC; procedure Tr( x, y: integer; color:system.Drawing.Color); begin MoveTo(x, y); LineTo(x, y-60); LineTo(x+100, y); LineTo(x, y); FloodFill(x+20, y-20,color); end; begin SetPenColor(clBlack); Tr(100, 100, clBlue); Tr(200, 100, clGreen); Tr(200, 160, clRed); end. |
Рассмотрим синтаксис объявления и описания процедуры с параметрами в Паскале.
var …;{область объявления глобальных переменных} procedure pr(параметр1, параметр2: integer; параметр3:char); {начало процедуры} var …;{объявление локальных переменных} begin … {тело процедуры} end;{конец процедуры} begin … {основная программа} pr (параметр1, параметр2, параметр3); {вызов процедуры} end.
Задание procedure 1: Написать процедуру рисования N вертикальных линий. N задается параметром процедуры.
Задание procedure 2: Написать процедуру рисования N окружностей, сдвинутых по горизонтали. N, радиус R и отступ O задаются параметрами процедуры (всего 3 параметра).
Пример: Написать процедуру, которая печатает 60 раз указанный символ (введенный с клавиатуры), каждый с новой строки
Параметры процедуры (в некоторых языках они называются аргументами) указываются в скобках после ее имени (в объявлении).
В данном примере в качестве введенного символа будем использовать параметр процедуры. Формальный параметр процедуры указывается в скобках при ее описании. Обязательно необходимо указать тип формального параметра через двоеточие.
Фактический параметр — это то значение, которое указывается в скобках при вызове процедуры. Фактическим параметром может быть конкретное значение (литерал: число, символ, строка…) либо переменная, которые компилятор подставит вместо формального параметра. Поэтому тип данных у формального и фактического параметра процедуры должен быть одинаковым.
| Pascal | PascalABC.NET | ||||
|
|
В данном примере при вызове процедуры компилятор заменит формальный параметр a фактическим параметром s, т.е. тем символом, который будет введен с клавиатуры. Оба параметра имеют тип данных char.
- число фактических параметров должно быть равно числу формальных параметров;
- соответствующие фактические и формальные параметры должны совпадать по порядку следования и по типу данных.
Задача procedure 3. Написать процедуру, которая складывает два любых числа (два параметра).
Процедуры с параметрами. Параметр по ссылке
(передача параметра по ссылке)
Пример: Программа поиска максимума из двух целых чисел при помощи процедуры
- способ:
- способ:
| Pascal | PascalABC.NET | ||||
|
|
В примере параметры a и b служат для хранения в них сравниваемых чисел, а параметр по ссылке max — для сохранения в ней максимального из двух чисел. Параметр по значению — параметр, принимаемый по значению, или выходной параметр передает свое значение в основную программу (фактическому параметру m), т.е. возвращает значение. Тогда как параметры по ссылке — параметры, принимаемые по ссылке, (входные параметры), наоборот, принимают значения из основной программы (из фактических параметров x и y). Для параметра по ссылке (max) используются те ячейки памяти, которые отведены под соответствующий параметр при вызове процедуры (ячейка m), именно поэтому такой параметр называется параметром, передаваемым по ссылке.
Таким образом, сформулируем понятия:
Если в качестве формального параметра указана обычная переменная с указанием ее типа, то такой параметр есть параметр, передаваемый по значению, или входной параметр (
aиbв примере). Тип данных формального параметра-значения должен соответствовать типу данных его фактического параметра (aиbдолжны попарно соответствовать типу данныхxиy).Если перед именем формального параметра в объявлении процедуры стоит служебное слово var, то такой параметр называется параметром, передаваемым по ссылке, или выходным параметром (
maxв примере). Для него используются те ячейки памяти, которые отведены под соответствующий параметр при вызове процедуры (m). А передача такого параметра называется передачей по ссылке (ссылка на ту же ячейку в памяти). Фактический параметр, соответствующий параметру-переменной, может быть только переменной (не константой, не литералом и не выражением).
Использование параметров-переменных позволяет тратить меньше памяти
| Pascal | PascalABC.NET | ||||
|
|
Используя данный способ решения задачи, мы обошлись без третьего параметра. Для этого в процедуре мы использовали еще одну локальную переменную c. Процедура меняет значения переменных a и b таким образом, чтобы b всегда была максимальной. Поэтому в 15 строке программы в качестве максимальной выводится второй параметр (y), соответствующий формальному параметру b.
Задача procedure 4.
- Необходимо определить наибольший общий делитель двух введенных чисел, используя цикл.
- Необходимо определить наибольший общий делитель двух введенных чисел, используя процедуру (два параметра по значению, один параметр по ссылке).

Словесный алгоритм:
- Вводятся a и b (например, 18 и 24)
- В цикле повторяем действия:
- Если а < b, то меняем переменные местами (1 шаг: a=24, b=18; 2 шаг: a=18, b=6)
- Переменной a присваиваем остаток от деления a на b (1 шаг: a=6, b=18; 2 шаг: a=0, b=6)
- Когда остаток равен 0, выводится результат (значения переменной b) (b=6)
Алгоритм решения поиска НОД:
| числа | a и b | остаток | результат | |
| 1 | a=18, b=24 24>18 |
если b>a → swap(a,b) a=24, b=18 |
24/18 = 1(6) | a=6, b=18 |
| 2 | a=6, b=18 18>6 |
если b>a → swap(a,b) a=18, b=6 |
18/6 =3(0) | a=0, b=6 6 |
| 128 и 56 | ||||
| 1 | a=128,b=56 a>b |
нет a=128,b=56 |
128/56=2(16) | a=16,b=56 |
| 2 | a=16,b=56 b>a |
если b>a → swap(a,b) a=56, b=16 |
56/16=3(8) | a=8,b=16 |
| 3 | a=8,b=16 b>a |
если b>a → swap(a,b) a=16,b=8 |
16/8=2(0) | a=0, b=8 8 |
Задача procedure 5. Используя процедуры, построить фигуру:
Задача procedure 6. Даны 3 различных массива целых чисел (размер каждого 15 элементов). В каждом массиве найти сумму элементов и среднее арифметическое значение.
Для формирования элементов массива и подсчета суммы и среднего арифметического использовать одну процедуру (среднее арифметическое и сумму оформить как параметры-переменные).
В задачах на Паскале часто встречается необходимость заполнить массив данными и затем вывести значения на экран. Почему бы не автоматизировать данную задачу заполнения и вывода массива — т.е. оформить при помощи процедур, а в дальнейшем использовать данные процедуры при надобности.
Пример: Создать процедуру для вывода десяти элементов массива (два параметра: количество элементов, массив)
Показать решение:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
const n = 10; var i:integer; a, b: array[1..n] of integer; procedure arr_out (k:integer; arr: array[1..n] of integer); var i: byte; begin write ('вывод массива: '); for i := 1 to k do write (arr[i]:4); writeln; end; begin for i:=1 to n do a[i]:=random(10); arr_out (n, a); end. |
Пояснение:
Тело основной программы:
— формирование элементов массива (с функцией random).
— вызов процедуры с двумя параметрами: количество элементов, массив.
Тело процедуры:
— вывод элементов массива с использованием параметров
Продолжим нашу задачу:
Пример: Создать процедуру для заполнения массива с использованием функции random
Показать решение:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
const n = 10; var a, b: array[1..n] of integer; procedure arr_rand (k:integer; var arr: array[1..n] of integer); var i: byte; begin write ('Заполнение массива случайными числами '); randomize; for i := 1 to k do arr[i]:=random(100); end; begin arr_rand (n, a); end. |
Задача procedure 7. Объедините обе решенные задачи (для заполнения и вывода массива).
Задача procedure 8. Добавьте в задачу процедуру для заполнения значений массива пользователем (ввод значений с клавиатуры). Оформите вывод двух разных массивов: один — со значениями, сформированными случайным образом, другой — со значениями, введенными пользователем.
Задача procedure 9. Составить программу с процедурой для вычисления степени числа (входные параметры: число и степень). Для вывода результата использовать параметр по ссылке.
Задача procedure 10. Составить программу на Паскале с процедурой для вычисления факториала числа. (0!=1, 1!=1, 2!=2, 3!=6 …)
Передача аргументов по значению и по ссылке
-
Рассмотрим более подробно два этих понятия:
- Передача по значению: Значение фактического параметра копируется в соответствующий формальный параметр. Изменение формального параметра не ведет к изменению фактического параметра
- Передача по ссылке: Оба параметра и формальный и фактический ссылаются на одно и то же расположение в памяти, поэтому все изменения в теле процедуры отражаются и на фактическом параметре.
- Изменение формального параметра изменяет и фактический параметр тоже:
1 2 3 4 5 6 7 8 9 10 |
procedure p(a: integer); begin a := 666; // изменяется только формальный параметр! end; begin var x := 555; p(x); Print(x); // 555 end. |
1 2 3 4 5 6 7 8 9 10 |
procedure p(var a: integer); begin a := 666; end; begin var x := 555; p(x); Print(x); // 666 – фактический параметр изменился тоже! end. |
Короткая запись
Если тело процедуры состоит только из одного оператора, PascalABC.NET позволяет использовать при описании сокращенный синтаксис, без ключевых слов begin и end:
1 2 3 4 5 6 |
## procedure SqrtX(x: real) := print(sqrt(x)); // основная программа begin SqrtX(9); //3 end; |
Самостоятельная работа
Общее задание 1: Написать процедуру рисования N прямоугольников сдвинутых по горизонтали. N, координаты точек x1, y1, x2, y2 и отступ O задаются параметрами процедуры (всего 6 параметров).
Общее задание 2: Описать процедуру Mean(X, Y, AMean, GMean), вычисляющую:
- среднее арифметическое
AMean = (X+Y)/2 - и среднее геометрическое
GMean = √X*Yдвух положительных вещественных чиселXиY.
X и Y — входные параметры, AMean и GMean — выходные параметры вещественного типа.
В основной программе: Для заданных A, B, C, D найти среднее арифметическое и среднее геометрическое для пар (A, B), (A, C), (A, D), используя созданную процедуру.
1 вариант: для 5 одномерных массивов определять произведение элементов каждого массива, используя процедуру с двумя параметрами — число элементов массива и параметр по ссылке — для вывода произведения.
2 вариант: для 5 одномерных массивов определять минимальный элемент каждого массива, используя процедуру с двумя параметрами — число элементов массива и параметр по ссылке — для вывода минимального элемента.
* сложное С помощью процедуры формировать случайным образом одномерные массивы из 10 элементов (значения от -20 до +20). Вызывать процедуру до тех пор, пока среди значений не появится ноль.
Внутренние переменные
Внутренние переменные
доступны и используются внутри процедур.
Внутренние
переменные получившие инициализацию
являются статическими,
т.е. память выделяется на этапе компиляции
(неявно обладают атрибутом static).
Атрибут automatic устанавливает
переменные автоматическими,
т.е. память выделяется во время работы программы.
program static_var call sub() ! M = 1 call sub() ! M = 2 call sub() ! M = 3 end subroutine sub() integer :: M = 0 M = M + 1 write(*,*) M end subroutine sub |
program static_var call sub() ! M = 1 call sub() ! M = 1 call sub() ! M = 1 end subroutine sub() integer , automatic :: M M = 0 M = M + 1 write(*,*) M end subroutine sub |
Передача параметров
Формальные параметры
- входные, intent(in)
- выходные, intent(out)
- входные/выходные, intent(inout)
subroutine sub(a,b,c) integer, intent(in) :: a real, intent(out) :: b character, intent(inout) :: c ... end subroutine sub
По умолчанию все параметры имеют атрибут inout, т.к. передаются по ссылке.
Вид связи intent(in)
Принимают значение от
соответствующего фактического параметра
и не могут изменяться при выполнении процедуры.
Соответствующими
фактическими параметрами могут быть
выражения, переменные, значения, константы.
program param_in call sub(100) end subroutine sub(a) integer, intent(in) :: a ! входной параметр ... end subroutine sub
Вид связи intent(out)
Параметры передают свое значение
соответствующему фактическому параметру и предназначены для вывода данных из процедуры.
Соответствующий фактический параметр
должен быть переменной.
program param_out call sub(100) ! ошибка, ожидалась переменная end subroutine sub(a) integer, intent(out) :: a ! выходной параметр ... end subroutine sub
Вид связи intent(inout)
Параметры могут как принимать
значения от фактического параметра,
так и передавать данные в фактический параметр.
Соответствующие фактические параметры должны быть переменными.
program param_inout integer :: q = 80 call sub(q) end subroutine sub(a) integer, intent(inout) :: a ! входной/выходной ... ! параметр end subroutine sub
Optional параметры
Атрибут optional устанавливает
формальные параметры необязательными.
Функция present проверяет присутствие необязательного параметра при вызове процедуры.
При отсутствии проверки функцией present возможны ошибки выполнения для параметров с
видом связи intent(out, inout).
Процедура должна иметь явный интерфейс.
Optional параметры
program param_in
real res
res = logarithm(144.0,base = 12.0)
write(*,*) res
CONTAINS
real function logarithm(a, base)
real, intent(in) :: a
real, intent(in), optional :: base
if (present(base)) then
logarithm = log(a)/log(base)
else
logarithm = log10(a)
end if
end function logarithm
END
Область видимости
Объекты1Объекты – переменные, типы данных, внутренние процедуры
(для головной программы или внешней процедуры)
описанные в головной программе доступны во внутренних процедурах, недоступны во внешних.
Объекты описанные во внутренней, внешней процедурах доступны только в них самих.
При совпадении имен объектов головной программы и внутренней или внешней процедур,
объекты являются разными.

program array
integer, parameter :: M = 10
integer :: A(M) = [2,4,6,8,9,1,1,1,1,1]
call PrintArray()
contains
subroutine PrintArray() ! нет формальных параметров
integer k ! доступ к массиву A
do k = 1,M ! из головной программы
write(*,"(i6,)") A(k)
end do
write(*,*)
end subroutine PrintArray
END
Оператор interface
Почему при компиляции выдаётся ошибка?
program question write(*,*) middle(3.0,2.0) END real function middle(a,b) real a,b middle = (a+b)/2 end function middle
По умолчанию тип функции middle – целый.
Функция объявлена как вещественная,
но головная программа об этом «не знает».
Как указать головной программе
про тип функции middle?
Определяет явно заданный интерфейс.
Используется для внешних процедур.
Внутренние процедуры обладают явно заданным интерфейсом.
interface тип имя_функции(формальные параметры) тип формальных параметров конец описания функции end interface
Исправленная версия программы
program question
interface
real function middle(a,b)
real a,b
end function middle
end interface
write(*,*) middle(3.0,2.0)
END
real function middle(a,b)
real a,b
middle = (a+b)/2
end function middle
Процедуры и функции представляют собой относительно самостоятельные фрагменты программы, оформленные особым образом и снабженные именем. Упоминание этого имени в тексте программы называется вызовом процедуры (функции). Отличие функции от процедуры заключается в том, что результатом исполнения операторов, образующих тело функции, всегда является некоторое значение, поэтому обращение к функции можно использовать в соответствующих выражениях наряду с переменными и константами. Обобщенно процедуры и функции будем называть подпрограммами.
Подпрограммы делятся на встроенные и пользовательские. Встроенные подпрограммы входят в состав API DataExpress, пользовательские определяются разработчиком в скрипте. Синтаксис определения процедуры и функции:
// Определение процедуры procedure MyProc([список параметров]); begin … end; // Определение функции function MyFunc([список параметров]): [тип данных]; begin … end;
Верхняя строка процедуры называется заголовком процедуры и состоит из служебного слова procedure, названия функции, списка параметров и точки с запятой. Следом идут операторные скобки begin-end, называемые телом процедуры. После end обязательно ставится точка с запятой. Процедура может не иметь параметров, в этом случае ставить скобки необязательно.
Заголовок функции отличается тем, что вместо слова procedure пишется function, а после списка параметров или имени (если нет параметров) идет двоеточие и тип результата, который возвращает функция.
Вызов встроенной или пользовательской подпрограммы имеет следующий синтаксис:
Proc([список параметров]); MyFunc([список параметров]); x := a + MyFunc([список параметров]) – b … y := MyFunc2 + 1000 - b;
Если подпрограмма не имеет параметров, то скобки необязательны.
Имя подпрограммы должно быть уникальным в пределах модуля и других подключаемых модулей и не должно совпадать с именами встроенных.
В подпрограмме могут быть объявлены локальные переменные, видимые только в теле подпрограммы. Раздел объявления переменных находится между заголовком и телом. Пример:
procedure MyProc(Param1: Integer); var i, j: Integer; begin i := 1; … end;
Имена локальных переменных могут совпадать с именами глобальных переменных. В этом случае использоваться будет локальная переменная.
Параметры процедур и функций
Синтаксис описания параметров разберем на примере:
function MyFunc(x, y: Integer; a: Double; const S, Str: String; var R: String): Boolean;
Параметры в заголовке подпрограммы называются формальными параметрами. Параметры, передаваемые при вызове подпрограммы, называются фактическими.
Параметры одного типа отделяются запятой, после двоеточия указывается тип параметра. Параметры разных типов отделяются точкой с запятой. Список и тип формальных и фактических параметров должен совпадать. За этим следит компилятор.
Параметры, передаваемые в подпрограмму, делятся на:
-
Параметры-значения. В примере это параметры x, y, a. В качестве фактических параметров могут передаваться константы, произвольные выражения, переменные. Результат вычисления параметра копируется в стек подпрограммы. Если в качестве параметра передается переменная, то изменения производятся над ее копией, а не оригиналом.
-
Параметры-переменные. В примере это параметр R. Перед параметрами указывается служебное слово var. В качестве параметра может передаваться только переменная. Тип фактического параметра должен строго соответствовать типу формального параметра. В процедуру или функцию передается ссылка на переменную. Все изменения производятся непосредственно над переменной.
-
Параметры-константы. В примере это параметры S, Str. Перед параметрами указывается служебное слово const. Параметры-константы похожи на параметры-значения, только в подпрограмму передается ссылка на адрес в памяти, где располагается результат вычисления параметра. Компилятор не позволяет изменять в подпрограмме параметр-константу. Таким образом, не тратится время на копирование параметра в стек подпрограммы, как в случае с параметром-значением.
Пример вызова функции:
var a: Word; MyStr, MyResult: String; b: Boolean; begin b := MyFunc(1, a, AnyFunc(20) + 30 / 0.5, MyStr, ‘Hello, World’, MyResult); end;
В случае с параметрами-значениями и параметрами-константами тип формального и фактического параметра может быть совместимым. Если формальный определен как целое число, то фактический параметр может быть любого целого типа. Только нужно следить, чтобы формальный параметр мог «вместить» фактический параметр. В данном примере тип формального параметра Y «вмещает» переменную a, т. к. область допустимых значений больше. Целый формальный параметр несовместим с другими типами, в том числе с вещественными. А вот вещественный формальный параметр, совместим с целыми и вещественными.
В случае с параметрами-переменными требуется строгое соответствие типов, даже если формальный и фактический параметры являются родственными, например целыми. Т. е. если формальный параметр имеет тип Integer, то фактический параметр тоже должен иметь тип Integer, а не Byte, Word и т. д. Это касается и классов, даже если фактический параметр является потомком класса формального параметра.
Передача массивов в качестве параметров
Для передачи массива в подпрограмму должен быть определен пользовательский тип:
type TMyArr = array [1..20] of Integer; TMyArr2d = array [1..10] of array [1..5] of Byte; TDynaArr = array of String; procedure MyProc(Arr: TMyArr; var Arr2d: TMyArr2d; DynaArr: TDynaArr); begin … end; procedure AnyProc; var A: TMyArr; A2d: TMyArr2d; DArr: TDynaArr; begin … MyProc(A, A2d, DArr); end;
Фактический параметр должен быть переменной массива.
Компилятор не сообщит об ошибке, если объявить параметр-массив таким образом:
procedure MyProc(arr: array [1..10] of String); begin end; procedure AnyProc; var A: array [1..10] of String; begin MyProc(a); // type mismatch end;
Однако во время выполнения вы получите ошибку «type mismatch».
В Паскале есть так называемые открытые массивы. Синтаксис формального параметра открытого массива следующий:
procedure MyProc(OpenArr: array of [тип]);
Открытый массив представляет собой одномерный массив. Нижняя граница массива всегда равна 0, даже если нижняя граница передаваемого массива отличается. Соответственно, верхняя граница равна длине массива минус 1. Для определения границ массива можно воспользоваться функциями Low и High. Пример:
procedure MyProc(Arr: array of Integer); begin // Low(открытый массив) = 0 for i := Low(Arr) to High(Arr) do … end; procedure AnyProc; var arr: array [1..10] of Integer; arr2: array [-2..5] of Integer; begin MyProc(arr); MyProc(arr2); MyProc([1,4,8,9,11,34,23]); end;
Как видно из примера фактическим параметром может быть не только переменная, но и конструктор массива, который представляет собой перечисление элементов через запятую, заключенных в квадратные скобки.
В движке не поддерживаются вариантные открытые массивы, хотя некоторые встроенные подпрограммы имеют параметры такого типа (например, Format).
procedure Proc(arr: array of const); // не поддерживается
Возврат значения функции
Функция имеет предопределенную переменную Result, в которую сохраняется возвращаемое значение. Пример:
function SumAB(A, B: Double): Double; begin Result := A + B; end;
Выход из подпрограммы
В любой момент можно выйти из подпрограммы. Для этого предусмотрен оператор Exit.
В движке не поддерживается передача в EXIT возвращаемого значения.
Exit(-1); // Компилятор сообщит “internal error(20)”
|
Хранимая подпрограмма |
Прикладная подпрограмма |
|
|
Хранится |
В базе данных |
В приложении |
|
Выполняется |
Из любого приложения или инструментального средства базы |
Только из данного приложения |
Подпрограмма может содержать до
четырех секций:
§
Обязательная секция заголовка – определяет имя, тип и аргументы
подпрограммы
§ Декларативная
необязательная секция – содержит объявление локальных переменных, констант,
курсоров, пользовательских исключений
§ Обязательная секция
выполняемого кода – содержит команды SQL для
манипулирования данными в базе и команды PL/SQL для манипулирования данными в блоке
§ Необязательная секция
обработки исключений – определяет действия, связанные с обработкой ошибок
сервера или пользовательских исключений, возникших в секции выполняемого кода
Любое инструментальное средство Oracle
позволяет создавать как хранимые, так и не хранимые программные единицы. Если
Вы хотите создать не хранимую подпрограмму, действующую в пределах блока PL/SQL, в SQL*Plus, опишите ее в декларативной секции анонимного блока, в
котором Вы будете ее использовать.
Процедура PL/SQL
Чтобы сохранить набор действий для последующего выполнения,
можно создать процедуру PL/SQL.
Процедура может иметь входные параметры, которые указываются при вызове
процедуры.
Процедура состоит из двух частей:
·
спецификации, которая начинается ключевым словом PROCEDURE и заканчивается именем процедуры или списком
параметров
·
тела, которое начинается ключевым словом IS
и заканчивается оператором END процедуры.
PROCEDURE имя_процедуры
[(имя_параметра [IN|OUT|IN OUT] тип_данных [:=|DEFAULT выражение], …) ]
IS
[список_переменных;]
BEGIN
тело_блока;
END;
имя_процедуры – имя процедуры, в соответствии со стандартными
правилами присвоения имен
имя_параметра – имя входного параметра процедуры
тип_данных – тип данных параметра, указывается без размера
выражение
– начальное значение параметра
список_переменных
– определения локальных переменных, используемых в процедуре
тело_блока – набор действий, выполняемых процедурой
Процедура вызывается как целая команда PL/SQL, аргументы указываются в скобках в том же порядке, в
котором были объявлены формальные параметры.
SQL> DECLARE
2 PROCEDURE emp_sal (v_job
IN VARCHAR2)
3 IS
4 v_error_code NUMBER;
5 v_error_text
VARCHAR2(100);
6 v_sal emp.sal%TYPE;
7 BEGIN
8 SELECT sal INTO v_sal
FROM emp WHERE LOWER(job)=LOWER(v_job);
9 DBMS_OUTPUT.put_line(‘Salary
of ‘ || v_job || ‘ is ‘ || TO_CHAR(v_sal));
10 EXCEPTION
11 WHEN OTHERS THEN
12 v_error_code :=
SQLCODE;
13 v_error_text :=
SQLERRM;
14
DBMS_OUTPUT.put_line(TO_CHAR(v_error_code) || ‘ — ‘ || v_error_text);
15 END emp_sal;
16 BEGIN
17 emp_sal(‘President’);
18 emp_sal(‘Engineer’);
19 emp_sal(‘Clerk’);
20 END;
21 /
Salary of President is 5000
100 — ORA-01403: no data found
-1422 —
ORA-01422: exact fetch returns more than requested number of rows
PL/SQL
procedure successfully completed.
Для передачи значений в процедуру и из нее используются
параметры. При объявлении процедуры указываются формальные параметры,
которые служат для определения значений в исполняемой части блока. Фактические
параметры или аргументы подставляются при вызове процедуры.
Виды параметров:
|
IN входной |
OUT выходной |
IN OUT входной/выходной |
|
Аргумент по умолчанию |
Должен быть задан |
Должен быть задан |
|
Передает значение из вызывающей среды в подпрограмму |
Возвращает значение из подпрограммы в вызывающую среду |
Передает значение из вызывающей среды в подпрограмму и |
|
Формальный параметр выступает в качестве константы, изменить |
Формальный параметр выступает в качестве |
Формальный параметр выступает в качестве инициализированной |
|
Фактический параметр может быть выражением, константой, |
Фактический параметр должен быть переменной, он не может |
Фактический параметр должен быть переменной, он не может |
Функция PL/SQL
Функции PL/SQL
используются для возврата значений в вызывающую среду. Тип возвращаемого
значения объявляется в секции заголовка функции с помощью ключевого слова RETURN. Само возвращаемое значение определяется в исполняемой
секции блока (т.е. необходимо описать локальную переменную соответствующего
типа для возвращаемого значения) и передается в вызывающую среду командой RETURN, которых может быть несколько в блоке. По крайней
мере, одна команда RETURN в блоке должна быть.
Функция состоит из двух частей:
·
спецификации, которая начинается ключевым словом FUNCTION и заканчивается ключевым словом RETURN
·
тела, которое начинается ключевым словом IS
и заканчивается оператором END функции.
FUNCTION имя_функции
[(имя_параметра [IN|OUT|INOUT] тип_данных_параметра [:=|DEFAULT выражение], …) ]
RETURN тип_данных
IS
[список_переменных;]
BEGIN
тело_блока;
END;
имя_функции
– имя функции, в соответствии со стандартными правилами присвоения имен
имя_параметра
– имя входного параметра процедуры
тип_данных_параметра
– тип данных параметра, указывается без размера
тип_данных
– тип данных возвращаемого значения, указывается без размера
выражение
– начальное значение параметра
список_переменных
– определения локальных переменных, используемых в процедуре
тело_блока – набор действий, выполняемых процедурой
Функция вызывается как часть предложения PL/SQL.
SQL> DECLARE
2 v_sal emp.sal%TYPE;
3 FUNCTION emp_sal (v_job IN
VARCHAR2)
4 RETURN NUMBER
5 IS
6 v_error_code NUMBER;
7 v_error_text
VARCHAR2(100);
8 v_sal_inner
emp.sal%TYPE;
9 BEGIN
10 SELECT sal INTO
v_sal_inner FROM emp WHERE LOWER(job)=LOWER(v_job);
11 RETURN v_sal_inner;
12 END emp_sal;
13 BEGIN
14
DBMS_OUTPUT.put_line(‘Salary of President is ‘ ||
TO_CHAR(emp_sal(‘President’)));
15 END;
16 /
Salary of
President is 5000
PL/SQL
procedure successfully completed.
Сравнение процедур и функций
|
Процедура |
Функция |
|
Вызывается |
Вызывается |
|
Может, но |
Обязана |
|
Не могут |
Могут быть |
Литература
1. Вильям
Дж. Пэйдж Использование Oracle8/8i:
пер. с англ. – М.: Издательский дом «Вильямс», 1999.
Предыдущий раздел:
Следующий раздел:
11.4. Параметры-значения и параметры-переменные
Существует два способа описывать параметры: как параметры-значения и как параметры-переменные. В предыдущем разделе использовались параметры-значения. Параметр-значение является просто локальной переменной, начальное значение которой задается при вызове процедуры.
Пример:
var
a, b: integer; {Глобальные переменные}
procedure P3(a, b: integer); {Внутри процедуры символами a и b
обозначаются формальные параметры. Действия с ними никак не
повлияют на значения глобальных переменных a и b}
begin
a:=a+1;
b:=b+1;
writeln(a+b);
end;
begin
a:=1;
b:=1;
P3(a, b);{Вызов процедуры, где в качестве фактических параметров
использованы значения глобальных переменных a и b}
writeln(a, b);
end.
Если в заголовке процедуры перед какими-либо из параметров поставить слово var, то это будут параметры-переменные. Например:
procedure P3(var a, b: integer; c: real);
Здесь a и b – параметры-переменные, c – параметр-значение. При вызове процедуры фактический параметр, задающий значения этих формальных параметров не может быть выражением или константой, а должен быть обязательно переменной. То есть, недопустимы следующие вызовы:
P3(x+y, y+1, z+2);
P3(x, 2, z);
где x, y, z – глобальные переменные. Такие инструкции вызовут синтаксическую ошибку. В то же время синтаксически правильными будут вызовы:
P3(x, y, z+1);
P3(x, y, 2);
При использовании параметров-значений во время вызова процедуры происходит присваивание значения формальному параметру, то есть значение записывается в выделенные под хранение параметра ячейки памяти. При использовании параметров-переменных память под них не выделяется. Вместо этого на время работы процедуры они становятся синонимами тех переменных, которые указываются в качестве фактических параметров. Так при вызове P3(x, y, 2) формальные параметры a и b будут работать с теми же ячейками памяти, что и переменные x, y. Соответственно, если формальному параметру в процедуре присваивается новое значение, то и значение фактического параметра изменится. Воспроизведем пример, заменив тип параметров (добавим var перед их описанием):
var
a, b: integer; {Глобальные переменные}
procedure P3(var a, b: integer); {Внутри процедуры символами a и b
обозначаются формальные параметры. Теперь это
параметры-переменные и действия с ними повлияют на значения
глобальных переменных a и b}
begin
a:=a+1;
b:=b+1;
writeln(a+b);
end;
begin
a:=1;
b:=1;
P3(a, b);{Вызов процедуры, где в качестве фактических параметров
использованы глобальные переменные a и b.
После вызова глобальные переменные увеличатся на 1}
writeln(a, b);
end.
Если без слова var программа выводила числа 4, 1, 1, то после его добавления получится 4, 2, 2.
Следующий раздел:
Предыдущий раздел:
Добавить комментарий