Меню

Ошибка фактический параметр должен быть переменной

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_1

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

    Программа:
    1_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
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
    var s:char;
    procedure pr(a:char); {a - формальный параметр}
    var i:integer;
    begin
    for i:=1 to 60 do begin
      write(a);
      writeln;
    end;
    end;
    begin
    writeln('введите символ');
    readln(s);
      pr(s); {s - фактический параметр}
    end.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    procedure pr(a:char); {a - формальный параметр}
    begin
    loop 60 do begin
      println(a);
    end;
    end;
    begin
    writeln('введите символ:');
    var s:= readchar;
      pr(s); {s - фактический параметр}
    end.

    В данном примере при вызове процедуры компилятор заменит формальный параметр a фактическим параметром s, т.е. тем символом, который будет введен с клавиатуры. Оба параметра имеют тип данных char.

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

    Задача procedure 3. Написать процедуру, которая складывает два любых числа (два параметра).

    Процедуры с параметрами. Параметр по ссылке
    (передача параметра по ссылке)

    Пример: Программа поиска максимума из двух целых чисел при помощи процедуры

    1. способ:
    2. Pascal PascalABC.NET
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      
      var x,y,m,n:integer;
      {a и b - параметры по значению, max - параметр по ссылке}
      procedure MaxNumber(a,b:integer;var max:integer); 
      begin
      if a>b then
        max:=a
      else
        max:=b;
      end;
      begin
       write('vvedite x,y');
       readln(x,y);
       MaxNumber(x,y,m); {фактические параметры}
       writeln('max=',m)
      end.
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      
      {a и b - параметры по значению, max - параметр по ссылке}
      procedure MaxNumber(a,b:integer;var maximum:integer); 
      begin
        maximum:=max(a,b);
      end;
      begin
       var (x,y):=readInteger2('введите x,y');
       var m:integer;
       MaxNumber(x,y,m); {фактические параметры}
       writeln('max=',m)
      end.

      В примере параметры a и b служат для хранения в них сравниваемых чисел, а параметр по ссылке max — для сохранения в ней максимального из двух чисел. Параметр по значению — параметр, принимаемый по значению, или выходной параметр передает свое значение в основную программу (фактическому параметру m), т.е. возвращает значение. Тогда как параметры по ссылке — параметры, принимаемые по ссылке, (входные параметры), наоборот, принимают значения из основной программы (из фактических параметров x и y). Для параметра по ссылке (max) используются те ячейки памяти, которые отведены под соответствующий параметр при вызове процедуры (ячейка m), именно поэтому такой параметр называется параметром, передаваемым по ссылке.

      Таким образом, сформулируем понятия:

      Если в качестве формального параметра указана обычная переменная с указанием ее типа, то такой параметр есть параметр, передаваемый по значению, или входной параметр (a и b в примере). Тип данных формального параметра-значения должен соответствовать типу данных его фактического параметра (a и b должны попарно соответствовать типу данных x и y).

      Если перед именем формального параметра в объявлении процедуры стоит служебное слово var, то такой параметр называется параметром, передаваемым по ссылке, или выходным параметром (max в примере). Для него используются те ячейки памяти, которые отведены под соответствующий параметр при вызове процедуры (m). А передача такого параметра называется передачей по ссылке (ссылка на ту же ячейку в памяти). Фактический параметр, соответствующий параметру-переменной, может быть только переменной (не константой, не литералом и не выражением).

    3. способ:
    4. Использование параметров-переменных позволяет тратить меньше памяти

      Pascal PascalABC.NET
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      
      var x,y:integer;
      {b - параметр по ссылке или выходной параметр}
      procedure exchange(a: integer;var b:integer); 
      var c:integer;
      begin
      if a>b then begin 
        c:=a;
        a:=b;
        b:=c; {второй параметр процедуры - b - всегда будет максимальным}
      end;
      end;
      begin
       writeln('введите два числа');
       readln(x,y);
       exchange (x,y);
       writeln('max=',y) 
      end.
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      
      {b - параметр по сслыке или выходной параметр}
      procedure exchange(a: integer;var b:integer); 
      begin
        b:=max(a,b);
      end;
      begin
       var (x,y):=readInteger2('введите x,y');
       var m:integer;
       exchange (x,y);
       writeln('max=',y) 
      end.

      Используя данный способ решения задачи, мы обошлись без третьего параметра. Для этого в процедуре мы использовали еще одну локальную переменную c. Процедура меняет значения переменных a и b таким образом, чтобы b всегда была максимальной. Поэтому в 15 строке программы в качестве максимальной выводится второй параметр (y), соответствующий формальному параметру b.

    Задача procedure 4.

    1. Необходимо определить наибольший общий делитель двух введенных чисел, используя цикл.
    2. Необходимо определить наибольший общий делитель двух введенных чисел, используя процедуру (два параметра по значению, один параметр по ссылке).

    Поиск наибольшего общего делителя на паскале
    Словесный алгоритм:

    • Вводятся 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. Используя процедуры, построить фигуру:

    1_1

    Задача 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
    

    Передача параметров

    Формальные параметры

    1. входные, intent(in)
    2. выходные, intent(out)
    3. входные/выходные, 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([список параметров]);
    beginend;
    // Определение функции
    function MyFunc([список параметров]): [тип данных];
    beginend;

    Верхняя строка процедуры называется заголовком процедуры и состоит из служебного слова 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);
    beginend;
     
    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) doend;
     
    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.

    Сравнение процедур и функций

    Процедура

    Функция

    Вызывается
    в качестве целой команды PL/SQL

    Вызывается
    как часть выражения

    Может, но
    не обязана возвращать значение в вызывающую среду

    Обязана
    возвращать значение в вызывающую среду

    Не могут
    быть вызваны из предложений SQL

    Могут быть
    вызваны из предложений SQL

    Литература

    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.

    Следующий раздел:

    Предыдущий раздел:

    Добавить комментарий

    0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии

    А вот еще интересные материалы:

  • Яшка сломя голову остановился исправьте ошибки
  • Ясность цели позволяет целеустремленно добиваться намеченного исправьте ошибки
  • Ясность цели позволяет целеустремленно добиваться намеченного где ошибка
  • Ошибка фокусировки sumitomo type 39
  • Ошибка фокусировки fujifilm как починить