Процедуры в Паскале
Министерство образования Российской Федерации.
Северо-Кавказский Горно-Металлургический Институт (СКГТУ)
кафедра промышленной
электроники .
факультет электронной
техники, ПЭ-04-1 .
К У Р С О В А Я Р А Б О Т А
«
»
(вариант №9)
Выполнил Дзотцоев Лев
Казгериевич
Преподаватель Яровой Иван
Федорович
«___» «______________»
200__
Г. Владикавказ 2004 год
Задание
1.
Приведите синтаксис
описания и вызова процедуры. Опишите виды, назначение формальных и фактических
параметров. Приведите пример описания процедуры, её вызова и поясните его.
2.
Даны целые m
и n. Составить программу вычисления
x = (m! +n!)/(m+n)!, где k=1x2x3x4x..xK
В программе предусмотреть:
·
Ввод m и
n
·
Описание
процедуры-функции для вычисления значения факториала : f(k)
= k! =
1x2x3x..xK
·
Отображение на экране
дисплея значения Х
·
Комментарии в основных
местах программы
2.1 Отладить и провести счет по программе.
2.2 Привести в пояснительной записке:
·
Текст программы с
пояснениями
·
Исходные данные и
результаты счета
СОДЕРЖАНИЕ
Задание
1
Содержание
2
Синтаксис описания
и вызова процедуры 3
Параметры 4
Пример описания и
вызова процедуры 5
Виды параметров
6
Программа
12
Заключение
15
Литература 16
Приложение
17
Синтаксис описания и вызова процедуры.
Программа объемом до 10000 операторов считается малой, до 100000
операторов – средней. Понятно, что строить такие программы непосредственно из
элементарных операции практически невозможно. Для упрощения разработки программ
в Pascal-е можно использовать подпрограммы - процедуры и
функции. Они представляют собой инструмент, с помощью которого любая программа
может быть разбита на ряд в известной степени независимых друг от друга частей.
Такое разбиение необходимо по двум причинам.
Во-первых, это средство экономии памяти: каждая подпрограмма
существует в программе в единственном экземпляре, в то время как обращаться к
ней можно многократно из разных точек программы. При вызове подпрограммы
активизируется последовательность образующих ее операторов, а с помощью
передаваемых подпрограмме параметров нужным образом модифицируется реализуемый
в ней алгоритм.
Вторая причина заключается в применении современных методов
нисходящего проектирования программ. В результате применение этих методов
алгоритм представляется в виде последовательности относительно крупных
подпрограмм, реализующих более или менее самостоятельные смысловые части
алгоритма. Подпрограммы в свою очередь могут разбиваться на менее крупные
подпрограммы, те - на подпрограммы нижнего уровня и т.д. Последовательное
структурирование программы продолжается до тех пор, пока реализуемые
подпрограммами алгоритмы не станут настолько простыми, чтобы их можно было
легко запрограммировать.
Pascal даже в сравнении с промышленными системами
программирования обладает очень мощными средствами работы с подпрограммами.
Процедуры и функции, как уже отмечалось, представляют собой
относительно самостоятельные фрагменты программы, оформленные особым образом и
снабженные именем. Упоминание этого имени в тексте программы называется вызовом
процедуры (функции). Отличие функции от процедуры заключается в том, что
результатом исполнения операторов, образующих тело функции, всегда является
некоторое единственное значение простого, строкового типа или указателя,
поэтому обращение к функции можно использовать в соответствующих выражениях
наряду с переменными и константами.
В структуре Pascal программ существует специальный раздел для
описания процедур и функций. Как известно, любое имя в программе должно быть
обязательно описано перед тем, как оно появится среди исполняемых операторов. Не
делается исключения и в отношении процедур: каждую необходимо описать в разделе
описаний.
Описать подпрограмму - это значит указать ее заголовок и тело. В заголовке
объявляются имя процедуры и формальные параметры, если они есть. За заголовком
следует тело подпрограммы, которое состоит из раздела описаний и раздела
исполняемых операторов. В разделе описаний процедур могут встретиться описания процедур
низшего уровня, в тех - описания других подпрограмм и т.д.
Синтаксис и вызов (в общем) процедур:
Procedure <имя процедуры>
Uses <имена модулей>
Label <имена меток>
Const <имена констант>
Type <имена типов>
Var <имена локальных переменных>
<раздел объявления подпрограмм>
Begin
<операторы>
End;
Для выполнения процедуры необходим её вызов. Вызов осуществляется по
имени данной процедуры в теле программы. Имя процедуры воспринимается как
оператор. При его выполнении выполняется вся подпрограмма.
Описание подпрограммы состоит из заголовка и тела подпрограммы.
Заголовок
Заголовок процедуры имеет вид:
PROCEDURE <имя> (<сп.ф.п.>);
Здесь <имя> - имя подпрограммы <сп.ф.п.> - список
формальных параметров;
{Сразу за заголовком подпрограммы может следовать одна из
стандартных директив ASSEMBLER, EXTERNAL, FAR, FORWARD, INLINE, INTERRUPT, NEAR}
Параметры
Параметры бывают формальные и фактические. Параметры, которые
записываются в скобках после имени процедуры, называются формальными
параметрами. Они указывают на то, что для выполнения данной процедуры
необходимы дополнительные данные – фактические параметры.
Список формальных параметров необязателен и может отсутствовать. {Использование процедур без параметров оправданно только в
том случае, если в них не используется обращение к глобальным переменным.
Использование таких процедур ограниченно той программой, для которой они
написаны и затруднено для других программ}.
Если же он есть, то в нем должны быть перечислены имена формальных
параметров и их тип, например:
Procedure YZ (a : real; b : integer: с : char)
Как видно из примера, параметры в
списке отделяются друг от друга точками с запятой. Несколько следующих подряд
однотипных параметров можно объединять в подсписки, например, вместо
Procedure Z (а : integer; b
: integer)
можно написать проще:
Procedure Z (a, b : integer)
Операторы тела подпрограммы рассматривают список формальных
параметров как своеобразное расширение раздела описаний: все переменные из
этого списка могут использоваться в любых выражениях внутри подпрограммы. Таким
способом осуществляется настройка алгоритма подпрограммы на конкретную задачу.
Первый формальный параметр заменяется первым фактическим, второй-вторым
и т. д.
Механизм замены формальных параметров на фактические позволяет
нужным образом настроить алгоритм, реализованный в подпрограмме. Турбо Паскаль
следит за тем, чтобы количество и тип формальны параметров строго
соответствовали количеству и типам фактических параметров в момент обращения к
подпрограмме. Напомним: смысл используемых фактических параметров зависит от
того, в каком порядке они перечислены при вызове подпрограммы. Пользователь
должен сам следить за правильным порядком перечисления фактических параметров
при обращении к подпрограмме. Приведем пример. рассмотрим интересующую нас
часть программы (не самой удачной, но это пока неважно) для вычисления x = (5!
+ 2!)/(5+2)!
Program factorial(input,output);
……
{далее нас интересует описание процедуры:}
Procedure FL(L:integer, var z: integer); {объявление процедуры, её имя , список формальных
параметров}
Begin
Z:=1;
While L>1 do
Begin
Z:=ZxL;{тело
процедуры, которая также предусматривает, что 0! и 1! =1}
L:=l-1;
end;
end;
……..
begin
……..
{теперь рассмотрим вызов процедуры}
FL(5,a);
FL(2,b);
FL(2+5,c);
..........
end.
В данном случае l, z формальные параметры. К слову, их не надо
описывать в разделе глобальных переменных.
При первом вызове процедуры фактический параметр 5 заменит формальный L,
фактический a заменит формальный z, во втором 2 заменит L, b
заменит z.
В третьем соответственно 2+5 заменит L, c заменит
z. Для того, чтобы окончательно разобраться в
программе, необходимо пояснить, какими бывают виды формальных и фактических
параметров, их назначение.
Виды параметров.
По способу передачи данных параметры можно разделить на несколько
категорий.
Любой из формальных параметров подпрограммы может быть либо
параметром-значением, либо параметром-переменной, либо параметром-константой.
Если параметры определяются как параметры-переменные,
перед ними необходимо ставить зарезервированное слово VAR, например:
Procedure tide (var a : real) Здесь параметр А - параметр-переменная. Заголовок
процедуры может быть устроен так, что некоторые группы формальных параметров не
содержат слова VAR. Например:
Procedure qwerty(a,b,c:real; var s:real);
Формальные параметры, которые входят в группы, не содержащие слова VAR, называются
формальными параметрами-значениями.
Определение формального параметра тем или иным способом существенно
только для вызывающей программы: если формальный параметр объявлен как
параметр-переменная, то при вызове подпрограммы ему должен соответствовать
фактический параметр в виде переменной определенного типа; если формальный
параметр объявлен как параметр-значение, то при вызове ему может соответствовать
произвольное выражение. Контроль за неукоснительным соблюдением этого правила
осуществляет компилятором Турбо Паскаля.
Для того чтобы понять, в каких случаях использовать параметры значения,
а в каких - параметры-переменные, рассмотрим, как осуществляется замена
формальных параметров на фактические в момент обращения к подпрограмме.
Если параметр определен как параметр-значение, то перед вызовом
подпрограммы это значение вычисляется, полученный результат копируется во
временную память и передается подпрограмме. Важно учесть, что даже если в
качестве фактического параметра указано простейшее выражение в виде переменной
или константы, все равно подпрограмме будет передана лишь копия переменной
(константы). Таким образом, назначение
параметра-значения – передача данных из программы в подпрограмму. Если
же параметр определен как параметр-переменная, то при вызове подпрограммы передается
сама переменная, а не ее копия. Любые возможные изменения в подпрограмме
параметра-значения никак не воспринимаются вызывающей программой, так как в
этом случае изменяется копия фактического параметра, в то время как изменение
параметра-переменной приводит к изменению самого фактического параметра в
вызывающей программе. Параметр-константа схож с
параметром-переменной: в подпрограмму передается сама константа, но изменение её невозможно. Назначение
такого параметра совпадает с назначением параметра-значения . Формальные
параметры-константы указываются в заголовке программы после служебного слова const.
Его действие распространяется до ближайшей точки с запятой.
Поясним изложенное.
.....
var
a, b: integer;
......
procedure squar(a: integer; var b: integer);
begin
a:=sqr(a);
b:=sqr(b);
writeln(‘в
квадрате они выглядят так: ’,a,’, ’,b);
end;
........
begin
a:=4; b:=6;
writeln(‘внимательно
посмотрите на эти числа: ’, a,’, ’, b);
squar(a,b);
writeln(‘а
так а не в квадрате: ’,a, ’, ’,b);
end.
Результаты выглядят так: внимательно посмотрите на эти числа: 4, 6
в квадрате они выглядят
так: 16, 36
а так а не в квадрате: 4,
36
Этот пример может служить еще и иллюстрацией механизма «закрывания»
глобальной переменной а одноименной локальной: хотя переменная объявлена как
глобальная (она описана в вызывающей программе перед описанием процедуры), в
теле процедуры ее «закрыла» локальная переменная а, объявленная как
параметр-значение.
Итак, параметры-переменные используются
как средство связи алгоритма, реализованного в подпрограмме, с «внешним миром»:
с помощью этих параметров подпрограмма может передавать результаты своей работы
вызывающей программе. Разумеется, в распоряжении программиста всегда
есть и другой способ передачи результатов - через глобальные переменные. Однако
злоупотребление глобальными связями делает программу , как правило, запутанной,
трудной в понимании и сложной в отладке. В соответствии с требованиями хорошего
стиля программирования рекомендуется там, где это возможно, использовать
передачу результатов через фактические параметры-переменные.
С другой стороны, описание всех формальных параметров как параметров-переменных
нежелательно по двум причинам. Во-первых, это исключает возможность вызова
подпрограммы с фактическими параметрами в виде выражений, что делает программу
менее компактной. Во-вторых, и главных, в подпрограмме возможно случайное
использование формального параметра, например, для временного хранения
промежуточного результата, т.е. всегда существует опасность непреднамеренно
«испортить» фактическую переменную. Вот почему параметры-переменные следует
объявлять только те, через которые подпрограмма в действительности передает
результаты вызывающей программе. Чем меньше параметров объявлено параметрами-переменными
и чем меньше в подпрограмме используется глобальных переменных, тем меньше
опасность получения непредусмотренных программистом побочных эффектов,
связанных с вызовом подпрограммы, тем проще программа в понимании и отладке.
Существует одно обстоятельство, которое следует учитывать при
выборе вида формальных параметров. Как уже говорилось, при объявлении
параметра-значения осуществляется копирование фактического параметра во
временную память. Если этим параметром будет массив большой размерности, то
существенные затраты времени и памяти на копирование при многократных
обращениях к подпрограмме могут стать peшающим доводом в пользу объявления
такого параметра параметром-переменной или передачи его в качестве глобальной
переменной.
Параметры массивы и параметры строки
Может сложиться впечатление, что объявление переменных в списке
формальных параметров подпрограммы ничем не отличается от объявления их в
разделе описания переменных. Действительно, в обоих случаях много общего, но
есть одно существенное различие: типом любого параметра в списке формальных
параметров может быть только стандартный или ранее объявленный тип. Поэтому
нельзя, например, объявить следующую процедуру:
Procedure S (а : array (1..10] of real);
так как в списке формальных параметров фактически объявляется тип -
диапазон, указывающий границы индексов массива.
Если мы хотим передать какой-то элемент массива, то проблем, как
правило, не возникает, но если в подпрограмму передается весь массив, то
следует первоначально описать его тип. Например:
…...
type
mas = array [1..10] of real;
.......
PROCEDURE S (a : mas);
…...
Поскольку строка является фактически своеобразным массивом, ее передача
в
подпрограмму осуществляется аналогичным образом:
.......
type
intype =string[15];
outype = string[30];
FUNCTION St (i : intype) : outype:
Требование описать любой
тип-массив или тип-строку перед объявлением подпрограммы на первый взгляд
кажется несущественным. Действительно, в рамках простейших вычислительных задач
обычно заранее известна структура всех используемых в программе данных, поэтому
статическое описание массивов не вызывает проблем. Однако разработка
программных средств универсального назначения связана со значительными
трудностями. По существу, речь идет о том, что в Турбо Паскале невозможно
использовать в подпрограммах массивы с «плавающими» границами изменения
индексов. Например, если разработана программа, обрабатывающая матрицу из 10 х
10 элементов, то для обработки матрицы из 9 х 11 элементов необходимо переопределить
тип, т.е. перекомпилировать всю программу. Этот недостаток, как и отсутствие в
языке средств обработки исключительных ситуаций (прерываний), унаследован из
стандартного Паскаля и представляет собой объект постоянной и вполне
заслуженной его критики. Разработчики Турбо Паскаля не рискнули кардинально
изменить свойства базового языка, но, тем не менее, включили в него некоторые
средства, позволяющие в известной степени смягчить отмеченные недостатки.
Прежде всего, в среде Турбо Паскаля можно установить режим
компиляции, при котором отключается контроль над совпадением длины фактического
и формального параметра-строки. Это позволяет легко решить вопрос о передаче
подпрограмме строки произвольной длины. При передаче строки меньшего размера
формальный параметр будет иметь ту же длину, что и параметр обращения; передача
строки большего размера приведет к ее усечению до максимального размера
формального параметра. Следует сказать, что контроль включается только при
передаче строки, объявленной как формальный параметр-переменная. Если
соответствующий параметр объявлен параметром-значением, эта опция игнорируется
и длина не контролируется.
Значительно сложнее обстоит дело с передачей массивов произвольной
длины. Решить эту проблему при помощи не типизированных параметров
Процедурные типы
Процедурные типы - это нововведение фирмы Borland (в стандартном
Паскале таких типов нет). Основное назначение этих типов - дать программисту
гибкие средства передачи функций и процедур в качестве фактических параметров
обращения к другим процедурам и функциям.
Для объявления процедурного типа используется заголовок процедур, в
котором опускается ее имя, например:
type
Proc = Procedure (a, b, с :
real; Var d : real);
Proc2 = Procedure (var a, b);
РгосЗ = Procedure;
В программе могут быть объявлены переменные процедурных типов,
например, так:
var
р1 : Proc;
ар : array [1..N] of Proc2;
Переменным процедурных типов допускается присваивать в качестве
значений имена соответствующих подпрограмм. После такого присваивания имя
переменной становится синонимом имени подпрограммы.
Нетипизированные параметры-переменные
Еще одно и очень полезное нововведение фирмы Borland - возможность
использования нетипизированных параметров. Параметр считается нетипизированным,
если тип формального параметра-переменной в заголовке подпрограммы не указан,
при этом соответствующий ему фактический параметр может быть переменной любого
типа. Заметим, нетипизированными могут быть только параметры-переменные.
Нетипизированные параметры обычно используются в случае, когда тип
данных несущественен. Такие ситуации чаще всего возникают разного рода
копированиях одной области памяти в другую. Нетипизированные параметры очень
удобно использовать для передачи подпрограмме одномерных массивов переменной
длины.
Параметры- сложные типы данных
Рассмотрены прежде
категории параметров не исчерпывают всех вопросов передачи информации в Pascal-e.
Использование в качестве параметров сложных типов данных имеет свои
особенности.
Рассмотрим массивы и
строки открытого типа. Открытый массив (строка) – массив (строка) без указания
типа индекса (размера массива(строки)).
Пример:
Procedure
getfive(var massiv: array of real);
В данном случае
вместо формального параметра может использоваться любой массив с элементами
типа real. Индексация элементов открытого массива всегда
начинается с нуля. Такие массивы введены для того, чтобы подпрограмма могла
обрабатывать массивы любого размера.
Программа вычисления x=(m!+n!)/(m+n)!, где m, n целые (неотрицательные)
program factorial_(input,output);
{название
программы}
label 0; {описываем метку}
var
rez:real;
m,n:longint; {описали глобальные переменные, используемые в программе}
function fact(z: longint):
real; {заголовок функции с
формальным параметром-значением, типом}
var
y: real; {описали
локальную переменную}
begin
y:=1; {для
получения результата необходимо присвоить у значение 1. также при помощи этого
реализуется вычисление 0! и 1!}
while z>1 do {запускаем
цикл в обратную сторону, для упрощения опустим множитель 1}
begin
y:=y*z;
z:=z-1
end;
fact:=y{вычисляем факториал,
присваиваем его значение функции}
end;
{конец функции}
begin{начало
тела программы}
writeln('введите неотрицательные
числа'); {для удобства пользователя просим ввести
числа}
0:readln(m,n); {в память
вводятся числа}
if m or n <0 then
begin
writeln(‘вы
ошиблись, вводите неотрицательные числа’);
goto 0 {при ошибке пользователя предотвращаем выдачу неверного
результата}
end;
rez:=(fact(m)+fact(n))/fact(m+n); {вычисляется
значение данного выражения}
writeln('результат: ',rez) {выводим
на экран результаты счета}
end.
Исходные данные и результаты счета:
m=0, n=0, x=2.0000000000E+00 (2)
m=3, n=5, x=3.1250000000E-03 (0,003125)
m=7, n=-3, вы ошиблись, вводите неотрицательные
числа
Пояснительная записка
Теперь поясним нашу программу. program factorial_(input,output)
– с этим затруднений не возникает, factorial – имя программы, input-файл,
откуда происходит считывание данных, output-файл, куда происходит вывод данных. В нашем
случае (input,output) показывает, что программа требует ввода данных
и производит их вывод.
Label 0; описываем метку, которая нам пригодиться
позже
var
rez:real;
m,n:longint; - описываем глобальные переменные.
function fact(z: longint):
real; объявляем функцию, даем ей имя fl,
указываем формальные параметры. В данном случае это параметр-значение z.
var
y: real; описываем локальную переменную, т.е. она
будет использоваться только в теле функции. Real использован потому, что уже 13! Выходит
за рамки longint
begin
y:=1; необходимо присвоить переменной значение,
равное единице, по крайней мере по двум причинам:
1)
при умножении числа на 1
получается это же число, поэтому при у=1 исключены ошибки в начале вычисления
факториала.
2)
известно, что 0!=1,
поэтому при m или n = 0
цикл не запускается, а значение 0! Оказывается равным 1.
while z>1 do запускаем цикл в
обратную сторону, т. к. результат получается один и тот же, но при этом не
приходится описывать дополнительную локальную переменную для запуска цикла с
параметром. 1 исключаем из вычисления факториала по вышеуказанным причинам.
begin
y:=y*z;
z:=z-1
end;
fact:=y этим оператором присваиваем функции значение
факториала.
Точку с запятой перед end можно не ставить.
end;
конец функции
begin начало тела
программы
writeln('введите
неотрицательные числа'); данный оператор выводит на экран текст, заключенный
между ‘’, помогает понять, чего же требует программа.
0:readln(m,n); при помощи этого оператора ввода информации
исходные данные заносятся в ячейки памяти.
if m or n <0 then
begin writeln(‘вы ошиблись,
вводите неотрицательные числа’);
goto 0
end; если пользователь все же ввел отрицательные
числа, то программа выдаст неверный результат, данная последовательность
операторов выводит на экран сообщение об ошибке пользователя и возвращает к
вводу чисел
rez:=(fact(m)+fact(n))/fact(m+n);
вычисляем значение (m!+n!)/(m+n)!
end. конец
программы
Приведем для пущей надежности еще несколько результатов счета
M=2 N=8 X=1.1111662257Е-02
M=4 N=4 X=1.1904761905Е-03
M=0 N=3 X=1.1666666667Е+00
M=3 N=15 X=2.0424836601Е-04
ЗАКЛЮЧЕНИЕ
Система программирования Турбо Паскаль содержит мощный инструмент
разработки программ – подпрограммы. В данной курсовой приведены синтаксис
процедур, виды и назначение параметров. Как мы увидели, программа вычисления
факториала с использованием функции гораздо более компактна, чем та же
программа без процедур-функций. Использование процедур-функций отнюдь не
является дурным тоном в программировании, поэтому каждый изучающий язык
программирования Паскаль должен обязательно иметь представление о
процедурах-функциях и уметь ими пользоваться.
Литература
А. Масюков. Краткий конспект
лекций по информатике.
Интерактивный
учебник Turbo Pascal 7.0
С. А. Абрамов. Начала
программирования на языке паскаль
Приложение
ASSEMBLER - эта
директива отменяет стандартную последовательность машинных инструкций,
вырабатываемых при входе в процедуру и перед выходом из нее.
EXTERNAL - с
помощью этой директивы объявляется внешняя подпрограмма.
FAR - компилятор
должен создавать код подпрограммы, рассчитанный на дальнюю модель вызова.
Директива NEAR заставит компилятор создать код, рассчитанный на ближнюю модель
памяти. По умолчанию все стандартные подпрограммы генерируются с расчетом на
дальнюю модель вызова, а все остальные подпрограммы - на ближнюю модель.
В соответствии с
архитектурой микропроцессора ПК, в программах могут использоваться две модели
памяти: ближняя и дальняя. Модель памяти определяет возможность вызова
процедуры из различных частей программы: если используется ближняя модель,
вызов возможен только в пределах 64 Кбайт (в пределах одного сегмента кода,
который выделяется основной программе и каждому используемому в ней модулю);
при дальней модели вызов возможен из любого сегмента. Ближняя модель экономит
один байт и несколько микросекунд на каждом вызове подпрограммы, поэтому стандартный
режим компиляции предполагает эту модель памяти. Однако при передаче
процедурных параметров соответствующие подпрограммы должны компилироваться с
расчетом на универсальную - дальнюю модель памяти, одинаково пригодную при
любом расположении процедуры и вызывающей ее программы в памяти.
Явное объявление
модели памяти стандартными директивами имеет более высокий приоритет по
сравнению с настройкой среды.
FORWARD -
используется при опережающем описании для сообщения компилятору, что описание
подпрограммы следует где-то дальше по тексту программы (но в пределах текущего
программного модуля).
INLINE - указывает на
то, что тело подпрограммы реализуется с помощью встроенных машинных инструкций.
INTERRUPT -
используется при создании процедур обработки прерываний
опережающее описание:
Procedure В (j : byte);
forward;
Procedure A (i : byte);
begin
B(i);
End;
Procedure B;
Begin
…………….
A(j);
End;
Как видим, опережающее описание заключается в том, что объявляется
лишь заголовок процедуры В, а ее тело заменяется стандартной директивой
FORWARD. Теперь в процедуре А можно использовать обращение к процедуре В - ведь
она уже описана, точнее, известны ее формальные параметры, и компилятор может
правильным образом организовать ее вызов. Обратите внимание: тело процедуры В
начинается заголовком, в котором уже не указываются описанные ранее формальные
параметры.
Модуль –
самостоятельная программная единица, ресурсы которой могут быть использованы
другими программами (фактически та же самая программа, но с другим типом - .tpu);