Содержание:
Процедуры в Паскале
Подпрограмма — это фрагмент кода, который имеет свое имя и создается в случае необходимости выполнять этот код несколько (много) раз. Подпрограмма описывается единожды перед началом основной программы (до begin
). Компилятор пропускает данный фрагмент кода, пока в основной программе не встретит «вызов» подпрограммы, который выглядит как обращение к ней по имени (возможно, имени с аргументами, указанными в скобках).
Во многих языках программирования подпрограммы существуют только в виде функций. Однако в Паскале подпрограмма — и функция и процедура. Разница между ними станет очевидна в данном уроке.
Итак, рассмотрим синтаксис объявления и описания процедуры в Паскале
var …;{область объявления глобальных переменных} procedure название (параметры); {начало процедуры} var …;{объявление локальных переменных} begin … {тело процедуры} end;{конец процедуры} begin … {основная программа} end.
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.
Параметры процедуры (в некоторых языках они называются аргументами) указываются в скобках после ее имени (в объявлении).
В данном примере в качестве введенного символа будем использовать параметр процедуры. Формальный параметр процедуры указывается в скобках при ее описании. Обязательно необходимо указать тип формального параметра через двоеточие.
Фактический параметр — это то значение, которое указывается в скобках при вызове процедуры. Фактическим параметром может быть конкретное значение (литерал: число, символ, строка…) либо переменная, которые компилятор подставит вместо формального параметра. Поэтому тип данных у формального и фактического параметра процедуры должен быть одинаковым.
Pascal | PascalABC.NET | ||||
|
|
В данном примере при вызове процедуры компилятор заменит формальный параметр a
фактическим параметром s
, т.е. тем символом, который будет введен с клавиатуры. Оба параметра имеют тип данных char
.
- число фактических параметров должно быть равно числу формальных параметров;
- соответствующие фактические и формальные параметры должны совпадать по порядку следования и по типу данных.
Процедуры с параметрами. Параметр по ссылке
(передача параметра по ссылке)
- способ:
- способ:
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
.
- Необходимо определить наибольший общий делитель двух введенных чисел, используя цикл.
- Необходимо определить наибольший общий делитель двух введенных чисел, используя процедуру (два параметра по значению, один параметр по ссылке).
- Вводятся 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 |
Для формирования элементов массива и подсчета суммы и среднего арифметического использовать одну процедуру (среднее арифметическое и сумму оформить как параметры-переменные).
В задачах на Паскале часто встречается необходимость заполнить массив данными и затем вывести значения на экран. Почему бы не автоматизировать данную задачу заполнения и вывода массива — т.е. оформить при помощи процедур, а в дальнейшем использовать данные процедуры при надобности.
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. |
Передача аргументов по значению и по ссылке
-
Рассмотрим более подробно два этих понятия:
- Передача по значению: Значение фактического параметра копируется в соответствующий формальный параметр. Изменение формального параметра не ведет к изменению фактического параметра
- Передача по ссылке: Оба параметра и формальный и фактический ссылаются на одно и то же расположение в памяти, поэтому все изменения в теле процедуры отражаются и на фактическом параметре.
- Изменение формального параметра изменяет и фактический параметр тоже:
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; |
Самостоятельная работа
Общее задание 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). Вызывать процедуру до тех пор, пока среди значений не появится ноль.
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.
На этот код, программа пишет: «Тип параметра или возвращаемого значения не может быть описанием записи или описанием массива с границами»
Да, массив передавать в процедуру параметром только через новый тип данных нужно:
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.
Подскажите как реализовать данную программу в Паскаль?
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.
Что мы пишем в результате?
Спасибо