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 111 112 113 114 115 116 117 118
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
Описание и вызов. В Паскале подпрограммы называются процедурами и функциями и описываются в разделе с тем же названием.
Процедура имеет такую же структуру, как и программа, но с двумя отличиями:
• заголовок процедуры имеет другой синтаксис и включает служебное слово procedure;
• описание процедуры заканчивается точкой с запятой (а не точкой). Все имена, описанные в программе до процедуры, действуют во всей программе и в любой ее подпрограмме (если они там не описаны заново). Они называются глобальными, в отличие от локальных имен, описанных в процедуре и действующих лишь в ней.
Данные для обработки могут передаваться процедуре через глобальные имена или через аргументы процедуры. В процедуре каждый аргумент имеет свое имя -формальный параметр, описываемый в заголовке процедуры по схеме
procedure <имя> (<список описаний формальных параметров>) Описание формальных параметров может иметь вид
<список имен>: <тип> или var <список имен>: <тип>
В первом случае говорят о параметрах-значениях, во втором - о параметрах-переменных. В простейшем случае заголовок процедуры может содержать только имя процедуры.
Оператор вызова процедуры имеет вид
<имя процедуры> (<список выражений>);
Указанные выражения называют фактическими параметрами. Их список должен точно соответствовать списку описаний формальных параметров процедуры. Во время вызова процедуры каждому параметру-значению присваивается значение соответствующего фактического параметра и поэтому их обычно используют для передачи входных данных.
Параметры-переменные следует использовать для представления результатов процедуры.
Пример: составим программу, которая с помощью строки символов разделит экран на части, где напечатает таблицу квадратных корней для чисел 1, 2,..., 10 и таблицу натуральных логарифмов для чисел 1, 2,..., 5.
Печать строки символов оформим как процедуру. Так как никакую информацию передавать из процедуры в программу не надо, то аргументы процедуры (вид и количество символов) будут описаны как параметры-значения.
Заметим, что процедура в программе выполняется пять раз.
Программа 18
program section;
var x:integer;
procedure line(a:integer;c:char) ;
var j:integer;
begin
for j:=l to a do write (c);
writeln
end;
begin
line(35,'-'); writeln('таблица квадратных корней');
line(35,'-');
for x:=l to 10 do writeln(x:8,sqrt(x):8,4);
line (35,'-'); writein('таблица натуральных логарифмов');
line(35,'-');
for x:=l to 5 do writein(x:8,In(x):8:4);
line(35,'*')
end.
Функция - это подпрограмма, определяющая единственное скалярное, вещественное или строковое значение. Отличия подпрограммы-функции от процедуры:
• заголовок функции начинается со служебного слова function и заканчивается указанием типа значения функции:
function <имя> (список описаний формальных параметров): <тип>;
•раздел операторов функции должен содержать хотя бы один оператор присваивания имени функции;
• обращение к функции - не оператор, а выражение вида
<имя функции> (<список фактических параметров>).
Функции (и процедуры) могут использовать свое имя в собственном описании, т.е. могут быть рекурсивными.
Пример: составим программу, которая для заданных четырех натуральных чисел а, b, с, d напечатает наибольшие общие делители первой и второй пар чисел и сравнит их по величине.
В программе определим рекурсивную функцию nod(x,y) по формулам
| x, если у = 0
nod(x,y) = | nod(y.x). если х < у
| nod(x mod у,у), если х > у
Применяя эти формулы к числам 21 и 15, последовательно находим nod(21,15) = nod(6,15) = nod(15,6) = nod(3,6) = nod(6,3) = nod(0,3) = nod(3,0) = 3.
Программа 19
program four;
var a,b,c,d,m,n:integer;
function nod(x,у:integer):integer;
var h:integer;
begin
if y=0 then h:=x
else if x<y then h:=nod(y,x)
else h:=nod(x mod у, у);
nod: =h end;
begin
writeln('введите 4 натуральных числа');
read(а,Ь,с,d); writeln;
m:=nod(a,b); n:=nod(c,d);
writeln('нод(',а,',',b,')=',m);
writeln('нод(',c,',',d,')=',n);
if m>n then writeln('первый > второго')
else if m<n then writeln ('первый < второго')
else writeln('нод пар равны') end.
Внешние библиотеки. Как известно, подпрограммы (процедуры и функции) используются в программах с целью их структурирования, а также при многократных повторениях некоторых частей программы. Процедуры и функции описываются в программных единицах в разделе описания подпрограмм. Они являются внутренними для этих программных единиц.
Бывают случаи, когда одни и те же подпрограммы могут использоваться в различных программах одного и даже нескольких пользователей. В подобных ситуациях целесообразно создавать внешние подпрограммы, которые можно в необходимый момент подключать в любые программы. Как правило, внешние подпрограммы объединяют в отдельные пакеты, так называемые, библиотеки внешних подпрограмм. Могут создаваться личные библиотеки, специализированные библиотеки коллективного пользования и др. С одной из таких библиотек - встроенной библиотекой стандартных подпрограмм - пользователи имеют дело практически всегда. В состав этой библиотеки входят процедуры и функции вычисления значений ряда элементарных функций: синуса, косинуса, экспоненты и т.д., процедуры и функции обработки символьных величин, процедуры ввода-вывода и др. (список их приведен в конце § 3). Встроенная библиотека подключается к любой программе автоматически при компиляции. Поэтому откомпилированный файл с расширением .corn (иногда называемый «комовским»), как правило, занимает в 8 -10 раз больше места в памяти, чем исходный текст.
Внешние подпрограммы создаются обычным образом в виде отдельного файла или файлов. Для подключения внешних подпрограмм в программе пользователя в разделе описания ставится директива $I имя файла. С этого момента все процедуры и функции внешнего файла становятся внутренними для программы, и на все входящие в него процедуры и функции распространяется правило локальных и глобальных переменных. В этой связи, директива подключения внешнего файла должна размещаться после описания всех ею используемых глобальных параметров, процедур и функций.
Пример. Создадим внешнюю библиотеку из двух процедур и одной функции. Первая процедура программы 20 очищает экран, выдает приветствие, затем после нажатия клавиши <Пробел> снова очищает экран. Вторая процедура возводит число а в степень b. Третья подпрограмма-функция вычисляет значение экспоненты с некоторым грубым приближением на основе ряда Тейлора.
Программа 20
procedure PRIVET;
var a: char;
begin
cirscr; gotoxy(20,10) ;
write('здравствуйте , желаю успехов !') ;
repeat (цикл позволяет)
gotoxy(35,50);write('пробел'); (сменить экран}
read(kbd,а); (по нажатию клавиши)
until а=' '; (* 'пробел' )
cirscr;
end;
procedure STEPEN(a,b:real;var y:real);
begin
y:=exp(b*ln(a)) ;
end;
function MEXP(x:real):real;
begin
mexp:=l+x+x*x/2+x*x*x/6+x*x*x*x/24;
end;
Пусть представленные три подпрограммы записаны в файл с именем lab.pas. А теперь составим программу, использующую созданную внешнюю библиотеку.
Программа 21
program primeri;
($i lab) (директива подключения библиотеки} var a,b : real;
begin
PRIVET;
STEPEN(2,4,a); writeln('2 в степени 4 =',a); b:=MEXP(l);
write('машинная exp(1)=',EXP(1):6:4,' моя exp(1)=',b:6:4);
end.
В программе используется стандартная функция - экспонента ЕХР(1) и наша подпрограмма МЕХР(1).
Модули используют в более поздних версиях Паскаля для создания библиотек и разделения больших программ на логически связанные независимые друг от друга составные части. В состав модуля входят следующие разделы: заголовок, интерфейс, реализация, инициализация. Заголовок необходим для ссылок на модуль. Интерфейс содержит объявления, включая процедуры и функции, представленные списком заголовков и доступные пользователям в теле основной программы. Раздел «реализация» содержит тела процедур и функций, перечисленных в интерфейсной части модуля. Раздел «инициализация» содержит операторы, необходимые для инициализации модуля. Таким образом модуль - это набор констант, типов данных, переменных, процедур и функций. Каждый модуль компилируется отдельно; результат компилляции - файл с расширением .tpu (Turbo Pascal Unit). Каждый элемент модуля можно использовать в программе пользователя без дополнительного объявления, для чего достаточно записать имя используемого модуля в директиве Uses в начале программы после его заголовка.
В Турбо-Паскале версии 5.0 и выше применяют стандартные модули CRT, GRAPH и др. В этих модулях содержатся сервисные процедуры и функции по работе с экраном дисплея, с клавиатурой, графическими примитивами и т.п. Модули подключаются к программе путем специальной команды, размещаемой сразу после заголовка:
uses <имя модуля>
Программист может сам создать модуль. Ниже приведен пример с соответствующими комментариями.
Пример. Создать модуль, дополняющий математические возможности Паскаля арифметическими действиями над комплексными числами.
Будем представлять комплексные числа парами действительных: (а, b). Как известно, действия над ними выполняются по правилам
(a,b) + (c.d) = (a+c,b+d),
(a,b)-(c,d)=(a-^,b-d),
(a,b) * (c,d) = (a*c-b*d , a*d+b*c),
(a,b) / (c,d) = ( (a*c+b*d)/(c*c+d*d), (b*c-a*d)/(c*c+d*d)).
Создаваемый модуль будет включать четыре процедуры: Sum - сумма, Raz -разность, Proiz - произведение, Chastn - частное.
Этот модуль может быть отдельно откомпилирован. После этого любая программа, написанная на Паскале, может получить доступ к интерфейсным объектам (в данном случае - процедурам) этого модуля с помощью директивы Uses CompChisla.
Обратим внимание, что в интерфейсной части модуля от процедур присутствуют лишь заголовки, а в части «реализация» от заголовков процедур остаются лишь их имена.
Программа 22
unit CompChisla;
interface
procedure Sum(a,b,c,d: real; var x,y: real);
procedure Raz(a,b,c,d: real; var x,y: real);
procedure Proiz (a,b,c,d: real; var x,y: real);
procedure Chstn(a,b,c,d: real; var x,y: real);
implementation
procedure Sum;
begin x:=a+c; y:=b+d end;
procedure Raz;
begin x:=a-c; y:=b-d end;
procedure Proiz;
begin x:=a*c-b*d; y:=a*d+b*c
end;
procedure Razn;
var z:real;
begin z:= c*c+d*d; x:=(a*c+b*d)/z; y:=(b*c-a*d)/z end;
end.
Контрольные вопросы
1. Какова структура процедуры? функции?
2. Какие параметры называют формальными и какие - фактическими?
3. В чем различие между локальными и глобальными переменными?
4. В чем сходство и различие между процедурой и модулем?
Описание и вызов. В Паскале подпрограммы называются процедурами и функциями и описываются в разделе с тем же названием.
Процедура имеет такую же структуру, как и программа, но с двумя отличиями:
• заголовок процедуры имеет другой синтаксис и включает служебное слово procedure;
• описание процедуры заканчивается точкой с запятой (а не точкой). Все имена, описанные в программе до процедуры, действуют во всей программе и в любой ее подпрограмме (если они там не описаны заново). Они называются глобальными, в отличие от локальных имен, описанных в процедуре и действующих лишь в ней.
Данные для обработки могут передаваться процедуре через глобальные имена или через аргументы процедуры. В процедуре каждый аргумент имеет свое имя -формальный параметр, описываемый в заголовке процедуры по схеме
procedure <имя> (<список описаний формальных параметров>) Описание формальных параметров может иметь вид
<список имен>: <тип> или var <список имен>: <тип>
В первом случае говорят о параметрах-значениях, во втором - о параметрах-переменных. В простейшем случае заголовок процедуры может содержать только имя процедуры.
Оператор вызова процедуры имеет вид
<имя процедуры> (<список выражений>);
Указанные выражения называют фактическими параметрами. Их список должен точно соответствовать списку описаний формальных параметров процедуры. Во время вызова процедуры каждому параметру-значению присваивается значение соответствующего фактического параметра и поэтому их обычно используют для передачи входных данных.
Параметры-переменные следует использовать для представления результатов процедуры.
Пример: составим программу, которая с помощью строки символов разделит экран на части, где напечатает таблицу квадратных корней для чисел 1, 2,..., 10 и таблицу натуральных логарифмов для чисел 1, 2,..., 5.
Печать строки символов оформим как процедуру. Так как никакую информацию передавать из процедуры в программу не надо, то аргументы процедуры (вид и количество символов) будут описаны как параметры-значения.
Заметим, что процедура в программе выполняется пять раз.
Программа 18
program section;
var x:integer;
procedure line(a:integer;c:char) ;
var j:integer;
begin
for j:=l to a do write (c);
writeln
end;
begin
line(35,'-'); writeln('таблица квадратных корней');
line(35,'-');
for x:=l to 10 do writeln(x:8,sqrt(x):8,4);
line (35,'-'); writein('таблица натуральных логарифмов');
line(35,'-');
for x:=l to 5 do writein(x:8,In(x):8:4);
line(35,'*')
end.
Функция - это подпрограмма, определяющая единственное скалярное, вещественное или строковое значение. Отличия подпрограммы-функции от процедуры:
• заголовок функции начинается со служебного слова function и заканчивается указанием типа значения функции:
function <имя> (список описаний формальных параметров): <тип>;
•раздел операторов функции должен содержать хотя бы один оператор присваивания имени функции;
• обращение к функции - не оператор, а выражение вида
<имя функции> (<список фактических параметров>).
Функции (и процедуры) могут использовать свое имя в собственном описании, т.е. могут быть рекурсивными.
Пример: составим программу, которая для заданных четырех натуральных чисел а, b, с, d напечатает наибольшие общие делители первой и второй пар чисел и сравнит их по величине.
В программе определим рекурсивную функцию nod(x,y) по формулам
| x, если у = 0
nod(x,y) = | nod(y.x). если х < у
| nod(x mod у,у), если х > у
Применяя эти формулы к числам 21 и 15, последовательно находим nod(21,15) = nod(6,15) = nod(15,6) = nod(3,6) = nod(6,3) = nod(0,3) = nod(3,0) = 3.
Программа 19
program four;
var a,b,c,d,m,n:integer;
function nod(x,у:integer):integer;
var h:integer;
begin
if y=0 then h:=x
else if x<y then h:=nod(y,x)
else h:=nod(x mod у, у);
nod: =h end;
begin
writeln('введите 4 натуральных числа');
read(а,Ь,с,d); writeln;
m:=nod(a,b); n:=nod(c,d);
writeln('нод(',а,',',b,')=',m);
writeln('нод(',c,',',d,')=',n);
if m>n then writeln('первый > второго')
else if m<n then writeln ('первый < второго')
else writeln('нод пар равны') end.
Внешние библиотеки. Как известно, подпрограммы (процедуры и функции) используются в программах с целью их структурирования, а также при многократных повторениях некоторых частей программы. Процедуры и функции описываются в программных единицах в разделе описания подпрограмм. Они являются внутренними для этих программных единиц.
Бывают случаи, когда одни и те же подпрограммы могут использоваться в различных программах одного и даже нескольких пользователей. В подобных ситуациях целесообразно создавать внешние подпрограммы, которые можно в необходимый момент подключать в любые программы. Как правило, внешние подпрограммы объединяют в отдельные пакеты, так называемые, библиотеки внешних подпрограмм. Могут создаваться личные библиотеки, специализированные библиотеки коллективного пользования и др. С одной из таких библиотек - встроенной библиотекой стандартных подпрограмм - пользователи имеют дело практически всегда. В состав этой библиотеки входят процедуры и функции вычисления значений ряда элементарных функций: синуса, косинуса, экспоненты и т.д., процедуры и функции обработки символьных величин, процедуры ввода-вывода и др. (список их приведен в конце § 3). Встроенная библиотека подключается к любой программе автоматически при компиляции. Поэтому откомпилированный файл с расширением .corn (иногда называемый «комовским»), как правило, занимает в 8 -10 раз больше места в памяти, чем исходный текст.
Внешние подпрограммы создаются обычным образом в виде отдельного файла или файлов. Для подключения внешних подпрограмм в программе пользователя в разделе описания ставится директива $I имя файла. С этого момента все процедуры и функции внешнего файла становятся внутренними для программы, и на все входящие в него процедуры и функции распространяется правило локальных и глобальных переменных. В этой связи, директива подключения внешнего файла должна размещаться после описания всех ею используемых глобальных параметров, процедур и функций.
Пример. Создадим внешнюю библиотеку из двух процедур и одной функции. Первая процедура программы 20 очищает экран, выдает приветствие, затем после нажатия клавиши <Пробел> снова очищает экран. Вторая процедура возводит число а в степень b. Третья подпрограмма-функция вычисляет значение экспоненты с некоторым грубым приближением на основе ряда Тейлора.
Программа 20
procedure PRIVET;
var a: char;
begin
cirscr; gotoxy(20,10) ;
write('здравствуйте , желаю успехов !') ;
repeat (цикл позволяет)
gotoxy(35,50);write('пробел'); (сменить экран}
read(kbd,а); (по нажатию клавиши)
until а=' '; (* 'пробел' )
cirscr;
end;
procedure STEPEN(a,b:real;var y:real);
begin
y:=exp(b*ln(a)) ;
end;
function MEXP(x:real):real;
begin
mexp:=l+x+x*x/2+x*x*x/6+x*x*x*x/24;
end;
Пусть представленные три подпрограммы записаны в файл с именем lab.pas. А теперь составим программу, использующую созданную внешнюю библиотеку.
Программа 21
program primeri;
($i lab) (директива подключения библиотеки} var a,b : real;
begin
PRIVET;
STEPEN(2,4,a); writeln('2 в степени 4 =',a); b:=MEXP(l);
write('машинная exp(1)=',EXP(1):6:4,' моя exp(1)=',b:6:4);
end.
В программе используется стандартная функция - экспонента ЕХР(1) и наша подпрограмма МЕХР(1).
Модули используют в более поздних версиях Паскаля для создания библиотек и разделения больших программ на логически связанные независимые друг от друга составные части. В состав модуля входят следующие разделы: заголовок, интерфейс, реализация, инициализация. Заголовок необходим для ссылок на модуль. Интерфейс содержит объявления, включая процедуры и функции, представленные списком заголовков и доступные пользователям в теле основной программы. Раздел «реализация» содержит тела процедур и функций, перечисленных в интерфейсной части модуля. Раздел «инициализация» содержит операторы, необходимые для инициализации модуля. Таким образом модуль - это набор констант, типов данных, переменных, процедур и функций. Каждый модуль компилируется отдельно; результат компилляции - файл с расширением .tpu (Turbo Pascal Unit). Каждый элемент модуля можно использовать в программе пользователя без дополнительного объявления, для чего достаточно записать имя используемого модуля в директиве Uses в начале программы после его заголовка.
В Турбо-Паскале версии 5.0 и выше применяют стандартные модули CRT, GRAPH и др. В этих модулях содержатся сервисные процедуры и функции по работе с экраном дисплея, с клавиатурой, графическими примитивами и т.п. Модули подключаются к программе путем специальной команды, размещаемой сразу после заголовка:
uses <имя модуля>
Программист может сам создать модуль. Ниже приведен пример с соответствующими комментариями.
Пример. Создать модуль, дополняющий математические возможности Паскаля арифметическими действиями над комплексными числами.
Будем представлять комплексные числа парами действительных: (а, b). Как известно, действия над ними выполняются по правилам
(a,b) + (c.d) = (a+c,b+d),
(a,b)-(c,d)=(a-^,b-d),
(a,b) * (c,d) = (a*c-b*d , a*d+b*c),
(a,b) / (c,d) = ( (a*c+b*d)/(c*c+d*d), (b*c-a*d)/(c*c+d*d)).
Создаваемый модуль будет включать четыре процедуры: Sum - сумма, Raz -разность, Proiz - произведение, Chastn - частное.
Этот модуль может быть отдельно откомпилирован. После этого любая программа, написанная на Паскале, может получить доступ к интерфейсным объектам (в данном случае - процедурам) этого модуля с помощью директивы Uses CompChisla.
Обратим внимание, что в интерфейсной части модуля от процедур присутствуют лишь заголовки, а в части «реализация» от заголовков процедур остаются лишь их имена.
Программа 22
unit CompChisla;
interface
procedure Sum(a,b,c,d: real; var x,y: real);
procedure Raz(a,b,c,d: real; var x,y: real);
procedure Proiz (a,b,c,d: real; var x,y: real);
procedure Chstn(a,b,c,d: real; var x,y: real);
implementation
procedure Sum;
begin x:=a+c; y:=b+d end;
procedure Raz;
begin x:=a-c; y:=b-d end;
procedure Proiz;
begin x:=a*c-b*d; y:=a*d+b*c
end;
procedure Razn;
var z:real;
begin z:= c*c+d*d; x:=(a*c+b*d)/z; y:=(b*c-a*d)/z end;
end.
Контрольные вопросы
1. Какова структура процедуры? функции?
2. Какие параметры называют формальными и какие - фактическими?
3. В чем различие между локальными и глобальными переменными?
4. В чем сходство и различие между процедурой и модулем?