Pascal: Занятие № 7. Подпрограммы: процедуры в Pascal

На занятии будет объяснен алгоритм работы с процедурами на Паскале. Будут разобраны примеры использования процедуры с параметрами и без параметров. Познакомитесь с понятиями: формальные и фактические параметры, параметр по значению и параметр по ссылкее

Процедуры в Паскале

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

    3 комментария для “Pascal: Занятие № 7. Подпрограммы: процедуры в Pascal”

    1. 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.
      На этот код, программа пишет: «Тип параметра или возвращаемого значения не может быть описанием записи или описанием массива с границами»

      1. Да, массив передавать в процедуру параметром только через новый тип данных нужно:

        const
        n = 10;
        type arrInt=array[1..n] of integer;
        var
        i:integer;
        a: arrInt;
        procedure arr_out (k:integer; arr: arrInt);
        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.

    2. Подскажите как реализовать данную программу в Паскаль?
      program podschet_chisel_1;
      var n, k1, k2: integer;
      begin
      k1:=0;
      k2:=0;
      repeat
      write (‘Введите целое число>>’);
      readln (n);
      if n>0 then k1:=k1+1;
      if n<0 then k2:=k2+1;
      until n=0;
      writeln (‘Введено:’) ;
      writeln (‘положительных чисел — ‘, k1);
      writeln (‘отрицательных чисел — ‘, k2)
      end.
      Что мы пишем в результате?
      Спасибо

    Обсуждение закрыто.