Подпрограммы в Pascal
Выбери формат для чтения
Загружаем конспект в формате docx
Это займет всего пару минут! А пока ты можешь прочитать работу в формате Word 👇
Подпрограммы
Подпрограмма (англ. subroutine) — поименованная или иным образом идентифицированная часть компьютерной программы, содержащая описание определённого набора действий. Подпрограмма может быть многократно вызвана из разных частей программы. В языках программирования для оформления и использования подпрограмм существуют специальные синтаксические средства.
В Pascal существует два типа подпрограмм: процедуры (подпрограммы, в которых может изменяться несколько значений или ни одного значения) и функции (подпрограммы, которые возвращают только одно значение – саму себя).
Рассмотрим пример, чтобы понять, когда выгодно использовать подпрограммы.
Пример:
В том из двух векторов, в котором среднее геометрическое положительных элементов наибольшее, найти куб суммы ненулевых элементов данного вектора.
Класс
Имя
Тип
Структура
Смысл
Вход
A
вещ
вектор (одномерный массив)
первый вектор
Вход
B
вещ
вектор (одномерный массив)
второй вектор
Вход
na
цел
простая переменная
размер вектора A
Вход
nb
цел
простая переменная
размер вектора B
Промежут
finA
лит
текстовый файл
файл с вектором А
Промежут
finB
лит
текстовый файл
файл с вектором В
Промежут
fout
лит
текстовый файл
файл с результатом
Промежут
Sga
вещ
простая переменная
среднее геометрическое положительных элементов вектора А
Промежут
Sgb
вещ
простая переменная
среднее геометрическое положительных элементов вектора B
Выход
Suma
вещ
простая переменная
сумма ненулевых элементов вектора А и ее куб
Выход
Sumb
вещ
простая переменная
сумма ненулевых элементов вектора А и ее куб
Промежут
i
цел
простая переменная
бегунок
Задание по имеющемуся коду самим начертить блок-схему.
Код
type vector = array [1..100] of real;
var A, B: vector;
na, nb, i: integer;
sga, sgb: real;
sumA, sumB: real;
ka, kb: real;
finA, finB, fout: text;
begin
assign (finA, 'A.txt');
assign (finB, 'B.txt');
assign (fout, 'res.txt');
reset (finA);
reset (finB);
rewrite (fout);
write ('Введите размер первого вектора ');
readln (na);
write ('Введите размер второго вектора ');
readln (nb);
for i:=1 to na do
read (finA, A[i]);
for i:=1 to nb do
read (finB, B[i]);
writeln (fout, 'Исходный первый вектор');
for i:=1 to na do
write (fout, A[i], ' ');
writeln (fout);
writeln (fout, 'Исходный второй вектор');
for i:=1 to nb do
write (fout, B[i], ' ');
writeln (fout);
sga:=1;
ka:=0;
for i:=1 to na do
if A[i]>0 then
begin
sga:=sga*A[i];
ka:=ka+1;
end;
sga:=exp(ln(sga)*(1/ka));
sgb:=1;
kb:=0;
for i:=1 to nb do
if B[i]>0 then
begin
sgb:=sgb*B[i];
kb:=kb+1;
end;
sgb:=exp(ln(sgb)*(1/kb));
writeln (fout, 'Средние геометрические первого вектора = ', sga);
writeln (fout, 'Средние геометрические второго вектора = ', sgb);
if sgb=sga then writeln (fout, 'Средние геометрические первого и второго векторов равны между собой')
else if sga>sgb then
begin
writeln (fout, 'Средние геометрические первого вектора больше');
sumA:=0;
for i:=1 to na do
if A[i]<>0 then sumA:=sumA+A[i];
sumA:= sumA*sumA*sumA;
writeln (fout, 'Куб ненулевых элементо первого вектора равен ', sumA);
end
else
begin
writeln (fout, 'Средние геометрические второго вектора больше');
sumB:=0;
for i:=1 to nb do
if B[i]<>0 then sumB:=sumB+B[i];
sumB:= sumB*sumB*sumB;
writeln (fout, 'Куб ненулевых элементо второго вектора равен ', sumB);
end;
close(finA);
close(finB);
close(fout);
end.
Как видно из примера, код и блок-схема такой программы достаточно объемные, читать их не слишком удобно. Для того, чтобы повысить читабельность и сделать такой код более удобным и коротким, а так же ускорить обработку и уменьшить объем используемой памяти, используют подпрограммы. В нашем случае понадобится четыре подпрограммы: для ввода (Vvod), для вывод (Vivod), для поиска среднего геометрического (SG) и поиска куба суммы неотрицательных (KubSum).
По общей договоренности, имена подпрограмм должны бить говорящими, то есть такими, чтобы пользователь, взглянув на заголовок, понял, что делает данная подпрограмма. В русскоязычном сегменте договорились использовать транслит, сокращая слова по три-четыре буквы. В некоторых языках использует написание наименований действий без пробела (к примеру, SumOfElements).
Функция описывается в следующем виде:
Function <имя функции> (<формальных список параметров>): <тип>;
Var <список локальных параметров>;
Begin
<тело подпрограммы>
<имя функции>:=<результат работы функции>;
End;
Процедура описывается следующим образом:
Procedure <имя процедуры> (<формальных список параметров>);
Var <список локальных параметров>;
Begin
<тело подпрограммы>
End;
Формальные параметры соотвествуют фактическим по порядку и по типу. Передаваться параметры могут по ссылке или по значению. В случае передачи по ссылке используется ключевое слово var, в случае передачи по значению никаких дополнительных ключей перед переменной не ставится.
Рассмотрим на примере. Сначала просто приведен текст подпрограммы, а затем даны более подробные комментарии.
procedure Vvod (var x:vector; nx: integer; var fx: text);
var i: integer;
begin
for i:=1 to nx do
read (fx, x[i]);
end;
procedure {ключевое слово, обозначающее процедуру} Vvod { имя процедуры для ввода вектора}
var x:vector {некий вектор, который будет заполняться информацией в процессе выполнения подпрограммы}
nx: integer {переменная, обозначающая размер вектора, изменяться в процессе программы не будет}
var fx: text {некий текстовый файл, но даже чтение файла - это его изменение}
var i: integer; {дополнительная переменная-бегунок, для хождения по массиву}
begin {начало тела подпрограммы}
for i:=1 to nx do {цикл для прохода по всем nx элементам вектора х}
read (fx, x[i]); {поэлемнтно читаем элементы вектора х из файла fx}
end; {конец тела подпрограммы, подпрограмма завершена}
Вызов функции осуществляется следующим образом:
<переменная>:=<имя функции>(<список фактических параметров>);
Возможен следующий вызов функции, то есть результат функции не обязательно хранить, его можно сразу выводить или использовать как условие для анализа или для арифметических или логических действий:
Writeln (<имя функции>(<список фактических параметров>));
Вызов процедуры осуществляется следующим образом:
<имя процедуры>(<список фактических параметров>);
Результат будет записан в те переменные, которые были для этого предназначены в списке формальных параметров.
Рассмотрим пример вызова подпрограммы и то, как она работает. Заголовок нашей подпрограммы ввода был следующим:
procedure Vvod (var x:vector; nx: integer; var fx: text);
При вызове же мы видим следующие две строки:
Vvod (A, na, finA);
Vvod (B, nb, finB);
В первом случае на место некоторого массива х в процессе выполнения программы подставляется массив А, при выполнении подпрограммы массив А и будет изменяться, то есть заполняться информацией. На место неизменяющейся переменной nx, обозначающей размер, подставляется na, то есть фактический размер массива А, а на место некоторого файла, открытого на чтение, fx подставляется finA. Аналогичным образом происходит подстановка и во втром вызове, только для массива В. Таким образом, формальные параметры, это некоторые «формочки» или «образцы», над которыми совершаются действия, а фактические – это реальные данные, обрабатываемые по алгоритму, заданному в подпрограмме.
Теперь о блок-схеме и спецификации. Для каждой подпрограммы делается отдельная таблица данных и блок-схема. В первом блоке, вместо привычного «начало» пишутся входные данные, тело подпрограммы раскрывается точно так же, а в последнем блоке, вместо «конец» указываются передаваемые выходные данные. Блок-схема и таблица данных для этой подпрограммы выглядит следующим образом:
Класс
Имя
Тип
Структура
Смысл
Выход
x
вещ
одномерный массив
Вектор, который мы заполняем данными в этой подпрограмме
Вход
nx
цел
простая переменная
Количество элементов вектора
Вход
fx
лит
текстовый файл
Файл, из которого мы читаем данные
Промежу-точный
i
цел
простая переменная
Бегунок для перебора элементов вектора
Если же говорить о том, насколько использование подпрограмм полезно, то посмотрите, насколько сократился код, который был написан для решения задачи в начале лекции.
type vector = array [1..100] of real;
procedure Vvod (var x:vector; nx: integer; var fx: text);
var i: integer;
begin
for i:=1 to nx do
read (fx, x[i]);
end;
procedure Vivod (x:vector; nx: integer; var fx: text);
var i: integer;
begin
for i:=1 to nx do
write (fx, x[i], ' ');
writeln (fx);
end;
function SG (x:vector; nx:integer):real;
var i, k: integer;
s: real;
begin
s:=1;
k:=0;
for i:=1 to nx do
if x[i]>0 then
begin
s:=s*x[i];
k:=k+1;
end;
SG:=exp(ln(s)*(1/k));
end;
function KubSum (x:vector; nx:integer):real;
var i: integer;
s: real;
begin
s:=0;
for i:=1 to nx do
if x[i]<>0 then
begin
s:=s+x[i];
end;
KubSum:=s*s*s;
end;
var A, B: vector;
na, nb, i: integer;
sga, sgb: real;
sumA, sumB: real;
ka, kb: real;
finA, finB, fout: text;
begin
assign (finA, 'A.txt');
assign (finB, 'B.txt');
assign (fout, 'res.txt');
reset (finA);
reset (finB);
rewrite (fout);
write ('Введите размер первого вектора ');
readln (na);
write ('Введите размер второго вектора ');
readln (nb);
Vvod (A, na, finA);
Vvod (B, nb, finB);
writeln (fout, 'Исходный первый вектор');
Vivod (A, na, fout);
writeln (fout, 'Исходный второй вектор');
Vivod (B, nb, fout);
sga:=SG(A,na);
sgb:=SG(B,nb);
writeln (fout, 'Средние геометрические первого вектора = ', sga);
writeln (fout, 'Средние геометрические второго вектора = ', sgb);
if sgb=sga then writeln (fout, 'Средние геометрические первого и второго векторов равны между собой')
else if sga>sgb then
begin
writeln (fout, 'Средние геометрические первого вектора больше');
SumA:=KubSum(A, na);
writeln (fout, 'Куб ненулевых элементо первого вектора равен ', sumA);
end
else
begin
writeln (fout, 'Средние геометрические второго вектора больше');
SumB:=KubSum(B, nb);
writeln (fout, 'Куб ненулевых элементо второго вектора равен ', sumB);
end;
close(finA);
close(finB);
close(fout);
end.
Так же обращаю Ваше внимание, что в таблице данных для главного кода надо указывать только те переменные, что используются в главном коде, к примеру, в нашем случае бегунок i не используется в основной программе, так что его указывать в составе данных для решения задач с помощью подпрограмм не нужно.
Блок-схема же тоже изменится. Все алгоритмы решения переносятся в подпрограммы и для них отдельными блок-схемами указывается алгоритм, в главном же коде указывается как и в какой последовательности будут вызываться подпрограммы, а так же некоторые дополнительные действия. Вызов подпрограммы обозначается через прямоугольник с двумя полосами по бокам. В верхнем левом углу пишут входные фактические данные для подпрограммы, в нижнем правом – выходные данные. В середине пишут ил имя подпрограммы, или, если на момент проектирования имени подпрограммы еще не существует, то те действия, что подпрограмма будет совершать. Блок-схема для нашего коды будет выглядеть так:
Задание: сделать таблицы и построить блок-схемы к остальным подпрограммам.
Матрицы
Матрица – это двумерные массивы.
Матрицы бывают прямоугольными (nxm) и квадратными (nxn), в наших задачах мы рассмотрим и первые и вторые.
Необходимо для работы с матрицей создать тип матрицы. Мы продолжаем работать со статическими массивами.
type mas=array[1..100,1..100] of real;
var a:mas;
Для заполнения матрицы информацией нужно использовать кратный цикл (внешний цикл пойдет по строкам, а внутренний по столбцам),
for i:=1 to n do
begin
for j:=1 to m do
read(fa, a[i,j]);
readln(fa);
end
Обращение к элементу матрицы A[i,j], где А – имя матрицы, i – номер строки, j – номер столбца.
Особые области для квадратной матрицы и поиск сумм всех элементов в этих областях.
Главная диагональ
Побочная диагональ
for i:=1 to n do
s:=s+a[i,i]
for i:=1 to n do
s:=s + x[i][n-i]
Над главной диагональю
Над побочной диагональю
for i:=1 to n-1 do
for j:=i+1 to n do
s:=s+a[i,j];
for i:=1 to n-1 do
for j:=1 to n-i-1 do
s:=s+a[i,j];
Под главной диагональю
Под побочной диагональю
for i:=2 to n do
for j:=1 to i-1 do
s:=s+a[i,j];
for i:=2 to n do
for j:=n-i+1 to n do
s:=s+a[i,j];
Особые области матрицы и поиск сумм всех элементов в этих областях.
Левая половина
Левая половина
for i:=1 to n do
for j:=1 to n div 2 do
s:=s+a[i,j];
for i:=1 to n do
for j:=n div 2 +1 to n do
s:=s+a[i,j];
Верхняя половина
Нижняя половина
for i:=1 to n div 2 do
for j:= 1 to n do
s:=s+a[i,j];
for i:= n div 2 +1 to n do
for j:= 1 to n do
s:=s+a[i,j];
Задача: Транспонировать матрицу.
Транспонирование матрицы это:
Код данной программы выглядит так:
type mas=array[1..100,1..100] of real;
procedure Vvod (var x:mas; nx: integer; var fx: text);
var i, j: integer;
begin
for i:=1 to nx do
begin
for j:=1 to nx do
read (fx, x[i, j]);
readln (fx);
end;
end;
procedure Vivod (x:mas; nx: integer; var fx: text);
var i, j: integer;
begin
for i:=1 to nx do
begin
for j:=1 to nx do
write (fx, x[i,j]:5:2, ' ');
writeln (fx);
end;
end;
procedure Transpon (var x:mas; nx: integer);
var i, j: integer;
buf: real;
begin
for i:=1 to nx do
for j:=1 to i-1 do
Begin
buf:=x[i,j];
x[i,j]:=x[j,i];
x[j,i]:=buf;
end;
end;
var a: mas;
n: integer;
fin, fout: text;
begin
assign (fin, '1.txt');
assign (fout, 'out.txt');
reset (fin);
rewrite(fout);
write (fout, 'Исходная матрица');
readln (n);
Vvod (a, n, fin);
writeln(fout, '');
Vivod(a,n,fout);
Transpon(a,n);
writeln(fout, 'Матрица после транспонирования');
Vivod(a,n, fout);
close(fin);
close(fout);
end.
Попробуйте сами составить спецификацию и блок-схемы данной программы.