программирование на паскале2. Учебное пособие по курсу Высокоуровневые методы информатики и программирования для студентов Гуманитарноприкладного института
Скачать 0.89 Mb.
|
Часть . Подпрограммы2.1. Общие сведения о подпрограммахПодпрограмма - автономно оформленный алгоритм, который может быть использован другим алгоритмом. Подпрограммы (или аналогичные им конструкции) имеются во всех алгоритмических языках. Их использование позволяет избежать повторного программирования одинаковых (с точностью до обозначений и констант) частей алгоритма, увеличивает наглядность программ (за счет укрупнения операторов), упрощает разделение труда между несколькими программистами, делает возможным создание библиотек типовых алгоритмов, упрощает отладку программ. Использование подпрограмм естественно при разработке алгоритмов методом нисходящего проектирования: алгоритм порождает подалгоритмы, которые удобно оформить как подпрограммы. Главным вопросом, который следует решить при проектировании подпрограмм, является вопрос о способе передачи данных между подпрограммой и программой. В любом алгоритмическом языке существует два основных способа передачи данных: через список параметров подпрограммы и через глобальные переменные (общие области, внешние имена). Первый способ дает возможность подстановки, т. е. передачи в подпрограмму при каждом обращении к ней новых данных программы. В список параметров подпрограммы включаются переменные, значения которых должны быть переданы из программы в подпрограмму и из подпрограммы в программу (т.е. "вход" и "выход"15 подпрограммы). Во всех алгоритмических языках при использовании подпрограмм выделяются два момента: описание подпрограмм и обращение к ним (вызов). Под описанием подпрограммы понимается оформление её алгоритма особым образом, так чтобы любая программа (или подпрограмма) могла его активизировать и выполнить над своими данными. Под обращением к подпрограмме понимается активизация подпрограммы; программа передает управление подпрограмме и пересылает ей данные, подпрограмма выполняет свой алгоритм и возвращает управление программе. При описании подпрограммы в списке параметров записываются формальные параметры, которые используются только в подпрограмме и при обращении к ней заменяются фактическими параметрами, т. е. соответствующими данными программы16. Фактические параметры должны соответствовать формальным по количеству, порядку перечисления и типу. Существует два способа замены формальных параметров на фактические:" по ссылке"17 (call-by-reference) и "по значению" (call-by-value). Передача параметра "по ссылке" означает передачу в подпрограмму адреса фактического параметра. При этом любое изменение формального параметра внутри подпрограммы есть изменение соответствующего фактического параметра. Поэтому константы и выражения нельзя передавать "по ссылке" - они могут измениться, «испортиться». Передача параметров "по значению" означает пересылку значения фактического параметра в ячейку, соответствующую формальному параметру, при обращении к подпрограмме. Это обеспечивает сохранность величины фактического параметра. Изменение формального параметра внутри подпрограммы никак не отражается на значении фактического. Вывод: "по значению" нельзя передавать переменные-результаты подпрограммы; их следует передавать "по ссылке ". Если фактическое значение может быть константой или выражением, то следует использовать замену "по значению". Заметим, что при передаче "по ссылке", как правило, экономится память, так как формальные параметры не копируют фактические; по этой причине массивы обычно передаются "по ссылке". При передаче "по значению" обычно экономится время работы подпрограммы (за счет отсутствия переадресации при обращении к формальным параметрам). В большинстве алгоритмических языков имеется два вида подпрограмм: подпрограммы общего назначения (в паскале они называются процедурами) и функции. Функции следует использовать, если подпрограмма имеет одно выходное значение (или одно основное выходное значение); классическими примерами функций во всех алгоритмических языках являются стандартные математические функции: синус, косинус, абсолютная величина и т. д. Имя функции является не только именем ее алгоритма, но и именем результата; это имя можно использовать в выражениях (как sin, cos, abs, и т. д.) Говорят, что функция через свое имя возвращает единственный (или основной) результат. 2.2. Процедуры в ПаскалеКак всегда при изучении подпрограмм, рассмотрим два вопроса: описание процедур и обращение к ним. 2.2.1.Описание процедурОписание процедуры состоит из заголовка и блока (тела) процедуры: Заголовок; Блок Заголовок процедуры имеет вид: procedure ИмяПроцедуры [(CписокФормальныхПараметров)] Здесь и далее в выделенные квадратные скобки заключены необязательные элементы операторов. В качестве имени процедуры используется идентификатор (разумеется, не совпадающий с другими идентификаторами, используемыми в данном программном блоке). Как уже говорилось в §2.1, формальные параметры - это параметры, которые используются при описании процедуры и при обращении к процедуре должны быть заменены на фактические параметры, описанные в вызывающей программе (или вызывающем блоке). В Паскале формальным параметром может быть имя переменной или процедуры; пока не будем рассматривать формальные параметры-процедуры. В список формальных параметров включаются переменные, которые должны быть переданы из вызывающего блока в процедуру и из процедуры в вызывающий блок (т.е. "вход" и "выход" процедуры). Изучим структуру списка формальных параметров. Список формальных параметров - это секции формальных параметров, перечисленные через символы ";": Секция1; Секция2;...;СекцияN Секция формальных параметров имеет вид: [VAR] CписокПеременных :Тип; Указывается стандартный тип или имя нестандартного типа (можно использовать только имя типа, но не его описание!). Имя типа должно быть объявлено во внешнем блоке. В дальнейшем мы увидим, что запрет использования описания типа формального параметра влечет за собой весьма существенные ограничения (см. §2.2.2). Если перед списком параметров стоит ключевое слово VAR, то эти параметры заменяются на фактические "по ссылке" (в терминах Паскаля такие параметры называются параметрами-переменными). Если перед списком не стоит VAR, то замена на фактические происходит "по значению" (это параметры-значения). После заголовка процедуры записывается блок процедуры со всеми разделами, что и в программе; в них описываются внутренние для данной процедуры имена (метки, константы, переменные, процедуры, функции). При выходе из процедуры эти имена перестают существовать. 2.2.2. Обращение к процедуреОбращение к процедуре осуществляется в разделе действий программы или подпрограммы с помощью оператора процедуры, имеющего вид: ИмяПроцедуры [(CписокФактическихПараметров)] Фактические параметры описываются в вызывающем блоке и должны соответствовать формальным по числу, порядку перечисления и типу. Заметим, что требование полного совпадения типов формальных и фактических параметров влечет за собой, в частности, совпадение размеров параметров-массивов. Пример. Даны две матрицы: а из 3-х строк и 5 столбцов и b из 7 строк и 3 столбцов. Вычислить минимальные значения элементов для каждой строки каждой из этих матриц. Естественно, вычисление минимальных значений строк произвольной матрицы следует оформить как подпрограмму (назовем ее minstr), а затем применить ее два раза к конкретным (фактическим) матрицам а и b. Алгоритм ввода одинаков для матриц а и b, поэтому ввод также оформим как подпрограмму (назовем ее matrin). Вывод массива результатов будет осуществлять подпрограмма masout. Таблица 9. Состав данных программы
Обратите внимание на размеры массивов в таблице 9. Типы фактических и формальных параметров подпрограмм должны совпадать, поэтому размеры формальных массивов должны подходить и для матрицы а, и для матрицы b. Чтобы удовлетворить этому требованию, используем максимальные размеры, подходящие и для а, и для b, т. е. память под массивы отводится с избытком. Тип массивов-параметров процедур (и функций) должен быть объявлен в разделе Type программы (в нашем примере это matrдля матриц и mas для одномерных массивов – см. текст программы). Заметим, что в программе не будет промежуточных переменных. Программа будет состоять из вызовов подпрограмм (крупных операторов), а промежуточные переменные (с точки зрения пользователя детали, мелочи) будут «спрятаны» в подпрограммы. Поясним, как составлен заголовок подпрограммы minstr. Подпрограмма имеет столько результатов, сколько строк у матрицы, все они равноправны, поэтому нет причины передавать один из них через имя функции, и, следовательно, minstr должна быть процедурой (не функцией). В список формальных параметров включаются "входные" данные для процедуры: матрица а и ее размеры (n - число строк, m - число столбцов), и "выходные" данные: min - массив минимальных значений строк. Заметим, что обозначения, принятые в одной подпрограмме (a, n, m, min) никоим образом не связаны с обозначениями в других подпрограммах и программе, т. е. подпрограммы разрабатываются автономно друг от друга. Переменная min - результат работы функции, поэтому ее надо объявить как параметр-переменную (перед описанием поставить ключевое слово Var). Так как фактическими значениями n и m будут константы (для фактической матрицы a, например, 3 и 5), n и m должны быть параметрами-значениями (перед их описанием Var не следует ставить). a лучше объявить как параметр-переменную (так как это массив) с целью экономии памяти. Получаем заголовок: procedure minstr(Var a:matr; n,m:integer; Var min:mas). Промежуточные переменные процедуры (счетчики строк и столбцов i и j) должны быть описаны в разделе переменных блока процедуры. Рассмотрим заголовок процедуры ввода матрицы matrin (предлагается читателю пояснить самостоятельно, почему это процедура, а не функция). На входе matrin – размеры матрицы n и m и имя матрицы, которое будет выводиться в приглашении к вводу символьная переменная с; эти данные должны быть параметрами-значениями (объясните, почему). На выходе процедуры – введенная матрица, для разнообразия обозначим ее р; это обязательно параметр-переменная. Получили заголовок: procedure matrin(n,m:integer; c: char;Var p:matr). Обратите внимание, что отсутствие ключевого слова Var перед описанием a в этом заголовке приведет к неработоспособности программы, в то время как в заголовке процедуры minstr отсутствие Var, вообще говоря, допустимо (объясните, почему). Дальнейшие комментарии к программе приведены в ее тексте. Б лок-схема программы приведена на рис. 13, блоки вызова подпрограмм имеют двойные линии по боковым сторонам. Блок-схема процедуры minmatr приведена на рис. 14. program primer2_2; Type matr=array[1..7,1..5] of real; mas= array[1..7] of real; Var a,b:matr; mina,minb:mas; {далее-раздел процедур и функций} Procedure minstr(Var a:matr; n,m:integer; Var min:mas); Var i,j:integer; Begin for i:=1 to n do begin min[i]:=a[i,1]; for j:=2 to m do if min[i]>a[i,j] then min[i]:=a[i,j]; end End{minstr}; Procedure matrin(n,m:integer; c:char; Var p:matr); Var i,j:integer; Begin Writeln('Введите матрицу ',c,' размером ',n,'*',m); for i:=1 to n do for j:=1 to m do read(p[i,j]); readln; End{matrin}; Procedure masout(n:integer;c:char;Var min:mas); Var i:integer; Begin Writeln('Минимальные значения строк матрицы ',c); for i:=1 to n do writeln(' ',min[i]); End{masout}; Begin {начинается раздел действий программы} matrin(3,5,'a',a); matrin(7,3,'b',b); minstr( a,3,5,mina); minstr( b,7,3,minb); masout(3,'a', mina); masout(7,'b', minb); readln End. 2.3. Функции Паскаля2.3.1. Описание функцийОписание функций дается в разделе процедур и, также как описание процедур общего вида, состоит из заголовка и блока. Заголовок функции имеет вид: function ИмяФункции [(СписокФормалПараметров)]:ТипФункции; Если имя процедуры общего вида обозначает описываемый ей алгоритм, то имя функции, кроме того, служит для обозначения выходного параметра (единственного или основного). Под типом функции подразумевается тип выходного параметра. Этот тип обязательно простой. В разделе действий функции обязательно должен иметься оператор присваивания, в левой части которого стоит имя функции, так как выходное значение должно быть определено. B правой части оператора присваивания имя функции воспринимается только как обращение18 к функции. Tак, например, в функции SUM, вычисляющей сумму элементов массива А, оператор SUM:=SUM+A[i]; неприменим, а для накопления суммы в разделе действий вместо SUM надо использовать другое обозначение (см.также пример из §2.3.2): S:=0; ... S:=S+A[i]; ... SUM:=S; 2.3.2. Обращение к функцииОбращение к функции производится в выражениях посредством использования указателя фукции: ИмяФункции[(Список фактических параметров)]; Указатель функции может стоять только в правой части оператора присваивания. П ример. Вычислить значение У: где a=(a1,…,a10), b=(b1,…,b5) - заданные последовательности. Вычисление суммы и произведения и ввод элементов массива требуется производить 2 раза (для a и b), поэтому эти алгоритмы стоит оформить как подпрограммы. Каждая из подпрограмм вычисления суммы и произведения имеют одно выходное значение, поэтому это будут функции. Подпрограммы рассчитаны на массивы с размером, не превыщающим 10. Текст программы приведен ниже. program primer_2_3; type mas=array[1..10] of real; var a,b:mas; y:real; pra:real; function sum(var v:mas; n:integer):real; {функция вычисляет сумму первых n (n<=10) элементов массива v} var s:real; i:integer; begin s:=0; for i:=1 to n do s:=s+v[i]; sum:=s; end;{конец функции sum} function pr(var v:mas; n:integer):real; {функция вычисляет произведение первых n(n<=10) массива v} var p:real; i:integer; begin p:=1; for i:=1 to n do p:=p*v[i]; pr:=p; end; {конец функции pr} procedure masin(var v:mas; n:integer); {процедура осуществляет ввод массива v размером n (n<=10), приглашение к вводу не включено в процедуру, поэтому в списке параметров нет символьной переменной –имени массива – ср. с примером п.2.2} var i:integer; begin for i:=1 to n do read(v[i]); readln; end; {конец процедуры masin} BEGIN writeln(' BBEДИТЕ МАССИВ А ИЗ 10 ЭЛЕМЕНТОВ'); masin(a,10); writeln(' ВВЕДИТЕ МАССИВ В ИЗ 5 ЭЛЕМЕНТОВ'); masin(b,5); pra:=pr(a,10); if pra =0 then writeln(' ЗНАМЕНАТЕЛЬ РАВЕН НУЛЮ') else begin y:=(sum(a,10)*(pr(b,5)+5)-sum(b,5))/pra; writeln(' ЗНАЧЕНИЕ ВЫРАЖЕНИЯ; y=',y:9:3); end; readln; END. 2.4. Глобальные и локальные именаКаждая процедура (функция) может иметь свой раздел процедур, а описанные в нем процедуры также могут иметь внутренние процедуры. Таким образом, может иметь место последовательность вложенных блоков. Понятие глобальных и локальных имен имеет смысл только относительно некоторого блока. Глобальные имена - это имена, которые действуют на протяжении всей программы (или внешнего блока), они объявляются в соответствуюших разделах программы (или внешнего блока). Локальные имена - это имена, которые действуют в пределах блока подпрограммы, это внутренние имена подпрограммы. К локальным именам относятся формальные параметры и все имена, описанные в блоке подпрограммы. Вне блока подпрограммы локальные имена неопределены. Локальное имя может использоваться в одном блоке, глобальные имена могут являться общими для нескольких блоков и использоваться для передачи данных между блоками. В Паскале данные, описанные в блоке программы, хранятся в так называемом статическом сегменте памяти; память под них распределяется при компиляции. Локальные данные подпрограммы хранятся в специальной области оперативной памяти – стеке; память под эти данные распределяется каждый раз при вызове подпрограммы и освобождается при завершении работы подпрограммы. Если имеется цепочка вложенных обращений к подпрограммам, например, программа вызывает подпрограмму Р1, Р1 вызывает подпрограмму Р2, а Р2 – Р3, то схема заполнения стека будет соответствовать рис. 15; порядок освобождения стека: сначала уходит Р3, затем Р2, затем Р1. Важными являются понятия области действия имени и времени жизни данных. Область действия имени - это часть программы, в которой имя может быть доступно. Таким образом, область действия локального имени - блок подпрограммы, в которой оно объявлено; глобального – весь текст программы от места объявления до последнего слова End (с точкой). Глобальное имя доступно в подпрограмме только в том случае, если в подпрограмме оно не объявлено еще раз. Понятиевремени жизни (существования) данных является близким к области действия, но не совпадает с ним. По времени жизни данные делятся на статические (существуют все время выполнения программы), автоматические (существуют во время выполнения функции, в которой описаны), динамические (получают место в памяти с помощью операторов динамического распределения памяти). В Паскале статические данные - это глобальные данные, автоматические – локальные, динамические данные рассматриваются в части IV. Д алее определим область действия, время жизни и место в памяти для переменных следующей схематичной программы (в правой колонке даны пояснения)
В данной программе область действия переменной а – вся программа, включая процедуры, время ее жизни – все время работы программы. Область действия глобальной переменной i – текст программы, за исключением процедур; время ее жизни – все время работы программы. Область действия локальной i – текст процедуры, в которой она объявлена, время ее жизни – время работы соотвествующей процедуры. Рекомендации
program primer2_4; {вычисление минимальных значений элементов строк матрицы a[3*5]} Type matr=array[1..3,1..5] of real; mas= array[1..3] of real; Var a:matr; min:mas; {далее-раздел процедур и функций} Procedure minstr; Var i,j:integer; Begin for i:=1 to 3 do begin min[i]:=a[i,1]; for j:=1 to 5 do if min[i]>a[i,j] then min[i]:=a[i,j]; end End{minstr}; Procedure matrin; Var i,j:integer; Begin Writeln('Введите матрицу размером 3*5'); for i:=1 to 3 do for j:=1 to 5 do read(a[i,j]); readln; End{matrin}; Procedure masout; Var i:integer; Begin Writeln('Минимальные значения строк матрицы '); for i:=1 to 3 do writeln(' ',min[i]); End{masout}; {далее - раздел действий программы} Begin matrin; minstr; masout; readln End. Основное назначение подпрограмм в такой программе – упростить программу и сделать ее более наглядной за счет укрупнения операторов. Заметим, однако, что использование глобальных переменных для передачи данных между процедурами имеет существенные недостатки, а именно:
Процедуры, в разделе действий которой используются только ее формальные и локальные параметры, называются "чистыми". Именно "чистые" процедуры удобно использовать как библиотечные, так как они допускают подстановку вместо формальных параметров различных вариантов фактических. 2.5. Использование подпрограммы в качестве параметра другой подпрограммыИспользование параметра-подпрограммы необходимо, когда некоторый алгоритм, описанный как подпрограмма, применим к множеству алгоритмов, каждый из которых также задается подпрограммой. Классические примеры таких ситуаций дают численные методы. В подпрограммах численных методов (вычисления определенного интеграла, нахождения экстремумов и нулей функций, вывода графиков, линий уровня, таблиц функций) обрабатываемые функции задаются как параметры. Средства для использования параметров-подпрограмм имеются во всех алгоритмических языках, предназначенных для решения вычислительных задач (СИ, Фортран, ПЛ/1). В рассматриваемых версиях Паскаля процедура-формальный параметр должна быть описана с помощью ранее объявленного процедурного (функционального) типа. При объявлении этого типа описывается структура заголовка подпрограммы, т.е. дается заголовок без имени подпрограммы. Примеры процедурных типов: TYPE PROC1=PROCEDURE(a,b,c:real; var d:integer); FUNC1=FUNCTION : REAL; G=FUNCTION (x,y,z:real); Подпрограмма-фактический параметр должна соответствовать процедурному типу формального параметра, т.е. иметь такой же заголовок с точностью до обозначений. Замечания
Пример 1. Решение двух уравнений на отрезке [0,3] c погрешностью 0.0001. program primer2_5; Type fn=function(x:real):real;{функциональный тип, задающий вид уравнения} Var r1,r2:real; {коpни уpавнений} {$F+} {опция дальнего вызова, в Object Pascal не надо} function fx1(x:real):real; {fx1 задает первое уравнение} begin fx1:=1.0/(1.2*sin(x)/cos(x)+sqrt(x+1)); end; function fx2(x:real):real; {fx2 задает второе уравнение} begin fx2:=(exp(-x)-sqrt(exp(x))+3.7)/3.0; end; {$F-} { В Object Pascal не надо } {root – подпрограмма вычисления корня} {уравнения fx(x)=0 на [a,b] c погрешн.е методом простых итераций} function root(fx:fn; a,b,e:real):real; {fx - функция – формальный параметр} var x,x0:real; begin x0:=(a+b)/2; x:=fx(x0); while abs(x-x0)>e do begin x0:=x; x:=fx(x0); end; root:=x; end; begin r1:=root(fx1,0,3,1.0e-4);{fx1 - функция - факт. параметр} r2:=root(fx2,0,3,1.0e-4);{fx2 - функция - факт. параметр} writeln('Коpень пеpвого уpавнения r1=',r1:7:4); writeln('Коpень втоpого уpавнения r2=',r2:7:4); end. Пример 2. Предположим, что функция root решения уравнения из примера 1 является библиотечной подпрограммой и не подлежит изменению. Пусть надо решить уравнение, заданное с точностью до параметра p, например, p задается вводом: x – p cosx=0. В программе надо обратиться к root, подставив вместо формального параметра fx фактический g(x,p)= x – p cosx. Но gимеет два аргумента, а fxодин. Выход из этой ситуации состоит в том, чтобы параметр р считать глобальным. Программа решения уравнения приведена ниже; предполагается, что тип fn и функция root имеются в подключенной к программе библиотеке. Var p{глобальная переменная для функции g}, E{погрешность решения уравнения}, A,B{границы отрезка}:real; function g(x:real):real; begin g:=x-p*cos(x) end; begin writeln(‘Введите p,A,B,E’); readln (p,A,B,E ); writeln(‘ корень уравнения равен ‘, root(g,A,B,E)); readln end. 2.6. Модули2.6.1. Общие сведенияЕдинственно возможное положение подпрограмм в стандартном Паскале – это раздел процедур и функций программы. Отсюда следует один из основных недостатков стандартной версии - невозможность раздельной компиляции подпрограмм и программы. Этот недостаток делает невозможным создание библиотеки алгоритмов в кодах ЭВМ. Процедуры можно хранить только как тексты на алгоритмическом языке, включать их в текст программы-блока и компилировать блок как единое целое. Для обеспечения возможности компиляции программы по частям в реализациях Паскаля, начиная с Турбо Паскаля, введено новое средство языка - модули (Units). Модуль - это автономно компилируемая программная единица, включающая в себя различные разделы описаний (типов, констант, переменных, процедур и функций) и, возможно, некоторые исполняемые операторы (например, присваивание переменным начальных значений или установление связи между программными и физическими именами файлов). При рассмотрении модулей следует остановиться на двух вопросах: как создавать (программировать) модули и как использовать готовые модули. Этому посвящены следующие параграфы. 2.6.2. Структура модуляСхематично структуру модуля можно изобразить следующим образом: UNIT имя_модуля; INTERFACE интерфейсная_часть IMPLEMENTATION исполняемая_часть [BEGIN инициирующая_часть] END. Модуль начинается ключевым словом UNIT, после которого пишется имя модуля, и заканчивается словом ЕND, после которого ставится точка. Модуль состоит из трех частей19. Первая часть содержит описания, доступные другим программам или модулям. Часто ее называют видимой (ее как бы "видят" другие программы) или интерфейсной (она начинается с ключевого слова INTERFACE, что в переводе с английского означает "внешние связи"). От процедур и функций в первую часть включаются только заголовки. Вторая часть содержит описания подпрограмм, заголовки которых находятся в интерфейсной части. Она называется исполняемой, так как содержит исполняемые операторы подпрограмм, и начинается с ключевого слова IMPLEMENTATION, которое переводится с английского как "исполнение". Содержание второй части доступно только данному модулю и не может использоваться другими программными единицами, поэтому ее также называют невидимой (для других программных единиц). В части IMPLEMENTATION в заголовках подпрограмм могут отсутствовать списки формальных параметров, так как они имеются в части INTERFACE. Третья часть называется инициирующей. Она содержит операторы, выполняемые до передачи управления основной программе. Они подготавливают работу модуля. Обычно это операторы инициализации переменных, открытия файлов (см. §3.3) и т. д. Инициирующая часть начинается с ключевого слова BEGIN. Она может отсутствовать (вместе с открывающим ее словом BEGIN). Пример Ниже приведен модуль VECTOR, позволяющий осуществлять некоторые операции над векторами. Число компонент вектора не превышает 10. Смысл процедур поясняется в комментариях. Unit VECTOR; {операции над векторами} INTERFACE Type AR=Array[1..10] of real; Function Scpr(Var a,b:Ar;N:Integer):Real; {вычисление скалярного произведения двух векторов} Function Lngth(Var a:Ar; N:Integer):Real; {вычисление длины вектора} Function UngleRad(Var a,b:Ar; N:Integer):Real; {вычисление угла между двумя векторами в радианах} Function UngleGr(Var a,b:Ar;N:Integer):Real; {вычисление угла между двумя векторами в градусах} Procedure Sum(Var a,b,c:Ar;N:Integer); {вычисление суммы двух векторов} Procedure Inp(Var a:Ar; N:Integer); {ввод координат вектора} IMPLEMENTATION Function Scpr; Var I:Integer; S:Real; Begin S:=0; For i:=1 To N Do S:=S+a[i]*b[i]; Scpr:=S; End; Function Lngth; Begin Lngth:=Sqrt(Scpr(a,a,N)); End; Function UngleRad; Var x:Real; Begin x:=Scpr(a,b,N)/Lngth(a,N)/Lngth(B,N); If x=0 then UngleRad:=pi/2 Else UngleRad:=ArcTan(Sqrt(1-x*x)/x); End; Function UngleGr; Begin UngleGr:=UngleRad(a,b,3)/pi*180; End; Procedure Sum; Var i:Integer; Begin For i:=1 to N Do c[i]:=a[i]+b[i] End; Procedure Inp; Var I:Integer; Begin For i:=1 To N Do Read(a[i]); Readln End; End. В Объектном Паскале допустима рассмотренная структура модуля. Но можно также отмечать начало инициализирующей части ключевым словом INITIALIZATION (вместо BEGIN). Модуль Объекьного Паскаля может иметь завершающую часть, которая содержит операторы, выполняемые при завершении программы, и начинается со слова FINALIZATION. Имя файла, содержащего исходный текст модуля, должно совпадать с именем модуля и иметь расширение .PAS (для примера предыдущего раздела VECTOR.pas). Результатом компиляции будет файл с тем же именем. Расширение откомпилированного файла .TPU (например, VECTOR.tpu) для сред Turbo и Borland Pascal и .DCU для Delphi. 2.6.3. Использование модулейЕсли программа использует модули, то в ее начале, перед всеми разделами описаний, должно стоять ключевое слово USES, после которого через запятую перечисляются имена этих модулей. Например: Program ppp; Uses crt,graph; {программа ppp использует модули crt и graph} Если модуль использует другие модули, то предложение USES может стоять либо после слова INTERFACE, либо после слова IMPLEMENTATION. Модули, подключенные в интерфейсной части, доступны в любой точке рассматриваемого модуля; модули, подключенные в исполняемой части, доступны в любом месте модуля, за исключением интерфейной части. Чтобы файлы с расширением .TPU были доступны среде Turbo (Borland) Pascal, их следует поместить в текущий каталог или указать их содержащий каталог в диалоговом окне опции OPTIONS/DIRECTORIES/UNIT DIRECTORIES. В Delphi существуют специальные возможности для подключения модуля к проекту; кроме того, директория местоположения модуля может быть указана в предложении USES: Uses имя_модуля in имя директории Пример Ниже приведена программа, использующая модуль VECTOR из §2.6.2. Program Primunit; {Даны два вектора а и b в трехмерном пространстве;} {вычисляется длина вектора с (с=а+b) и угол между вектором с и плоскостью XOY} Uses VECTOR; {используется модуль VECTOR} Var a,b,c,cpr:Ar;{тип ar объявлен в модуле} Begin Writeln(' Введите координаты исходных векторов'); Inp(a,3);Inp(b,3); {ввод а и в} Sum(a,b,c,3); {c=a+b} Writeln(' Длина вектора-суммы:', Lngth(c,3):10:3); cpr[1]:=c[1]; cpr[2]:=c[2]; cpr[3]:=0; {cpr - проекция с на плоскость XOY} If Lngth(cpr,3)< 1.0e-6 then Writeln('вектор c ортогонален плоскости XOY') Else Begin Write( ' Угол между вектором с и плоскостью XOY:',UngleGr(c,cpr,3):6:1); Writeln(' градусов'); End; Readln; End. 2.6.4. Модули как средство программированияМодули, прежде всего, дают возможность компилировать программу по частям и создавать библиотеки откомпилированных подпрограмм. Однако этим не исчерпываются возможности, которые они дают программисту. Модули, кроме описания процедур и функций, могут содержать также описания констант, типов, переменных, что избавляет программиста от необходимости их повторного описания. Информация модуля разделена по уровням доступа. В модуле выделяются видимая, доступная другим программам и содержащая основную информацию для использующего модуль программиста, интерфейсная часть и невидимая исполняемая часть. В модуле могут присутствовать инициирующая и завершающая части, обеспечивающие грамотное использование модуля. |