Л а б о р а т о р н а р о б о т а N 7
Процедури та функцiї Турбо Паскаля
Метою роботи є здобуття навикiв побудови структурованих прог-
рам, що базуються на розбиттi програми на пiдпрограми - процедури та
функцiї.
1. Теоретичний вступ
Пiдпрограми-процедури та функцiї призначенi для багаторазового
використання у програмi оформленої по певних правилах синтаксису
групи операторiв. Для цього групу операторiв, якi необхiдно викорис-
тати у рiзних частинах програми, оформляють у виглядi окремої
пiдпрограми i розмiщують в описовiй частинi основної програми. В не-
обхiдних мiсцях операторної частини програми розмiщують звертання до
пiдпрограми.
Основна вiдмiннiсть процедури вiд функцiї полягає в тому, що
процедура може повертати у викликаючу програму декiлька значень
рiзних типiв, а функцiя - тiльки одне значення неструктурованого ти-
пу.
Звертання до процедури здiйснюється за допомогою оператора про-
цедури, а звертання до функцiї - тiльки у виразi.
Процедури та функцiї мають структуру, подiбну до структури ос-
новної програми, тобто складаються з описової та операторної части-
ни. Процедури та функцiї можуть бути вкладеними одна в одну. Для ць-
ого оголошення процедур та функцiй розмiщуються в описовiй частинi
охоплюючої процедури чи функцiї.
Структура процедури
Procedure iм'я_процедури(список формальних параметрiв);
Блоки оголошень label, const, type, var;
Описи вкладених пiдпрограм;
Begin
Операторна частина процедури
End;
Оголошення процедури починається iз заголовка процедури. Заго-
ловок включає зарезервоване слово Procedure, пiсля якого вказується
iм'я процедури, а в круглих дужках список формальних параметрiв.
Список формальних параметрiв не є обов'язковим i може бути опущений
разом з круглими дужками. Заголовок процедури завершується символом
"крапка з комою".
Далi в описовiй частинi процедури оголошуються локальнi для да-
ної процедури мiтки, константи, типи, змiннi та вкладенi пiдпрогра-
ми.
Звертання до вкладених пiдпрограм здiйснюється з блоку опера-
торної частини процедури. Крiм того допускається звертання однiєї
пiдпрограми до iншої, розмiщеної вище неї по тексту програми на од-
ному або вищому рiвнi вкладеностi.
Структура функцiї
Function iм'я_функцiї(список формальних параметрiв):тип_функцiї;
Блоки оголошень label, const, type, var;
Описи вкладених пiдпрограм;
Begin
Операторна частина функцiї;
iм'я_функцiї:=вираз;
End;
Заголовок функцiї починається iз зарезервованого слова Functi-
on, пiсля якого задається iм'я функцiї i в круглих дужках - нео-
бов'язковий список формальних параметрiв. Список формальних пара-
метрiв може бути опущений разом з круглими дужками. Пiсля списку
формальних параметрiв (або пiсля iменi функцiї, якщо список
вiдсутнiй) через символ "двокрапка" вказується iдентифiкатор типу
функцiї - будь-який простий тип, стрiнг або вказiвник.
Описова частина функцiї мiстить оголошення локальних мiток,
констант, типiв даних та вкладених пiдпрограм, звертання до яких мо-
же бути розмiщене в операторнiй частинi основної програми.
При роботi функцiї хоча б один раз має виконатися оператор,
який iменi функцiї присвоює сумiсний з типом функцiї результуючий
вираз.
Досяжнiсть пiдпрограм
У Турбо Паскалi визначенi тiльки вкладенi пiдпрограми. Це озна-
чає, що внутрiшнi пiдпрограми розмiщуються в описовiй частинi охоп-
люючої пiдпрограми. Рiвень вкладеностi пiдпрограм не обмежений, але
загальна довжина програми не повинна перевищувати 64 Кбайт. Крiм то-
го загальний об'єм даних, оголошених всерединi пiдпрограм, не пови-
нен пеpевищувати 64 Кбайт.
В загальному випадку схема вкладеностi пiдпрограм є деревовид-
ною, тобто основна програма може мати декiлька вкладених пiдпрограм,
кожна з яких в свою чергу може мати вкладенi пiдпрограми.
Кожна пiдпрограма може звернутися до iншої пiдпрограми, заголо-
вок якої розмiщений вище по тексту програми на одному з нею або ви-
щому рiвнi вкладеностi. Кожна пiдпрограма (крiм основної програми)
може звернутися також сама до себе. Таке звертання називається пря-
мим рекурсивним.
В наступному прикладi допускається звертання процедури W до
процедури C, розмiщеної вище по тексту програми, а також процедур C
та W до себе.
Procedure C(x,y:real);
begin
{...}
end;
Procedure W;
Begin
{...}
C(2.5,3.4);
{...}
End;
Iнодi iснує необхiднiсть звернутися до пiдпрограми, розмiщеної
нижче по тексту на одному рiвнi вкладеностi. Цього можна досягти
шляхом випереджаючого опису пiдпрограми за допомогою ключового слова
forward, яке записується пiсля заголовку пiдпрограми i замiняє її
тiло. Нижче по тексту розмiщується опис пiдпрограми, яка звертається
до forward-пiдпрограми, а ще далi - тiло самої пiдпрограми, оголоше-
ної ранiше як forward. В повторному заголовку пiдпрограми, оголоше-
ної як forward, достатньо вказати тiльки її iм'я.
Procedure W(m,n:integer); forward;
Procedure C(x,y:real);
begin
{...}
W(2,5); {звертання до процедури, розмiщеної
нижче по тексту оголошення}
end;
Procedure W;
Begin
{...}
C(2.5,3.4);
{...}
End;
Випереджаючий опис може бути застосований як для процедур так i
для функцiй.
Передача даних мiж пiдпрограмами
Обмiн даними мiж пiдпрограмами може здiйснюватися або за допо-
могою глобальних параметрiв, або за допомогою списку фактичних i
формальних параметрiв.
Глобальнi, локальнi та статичнi данi
Глобальними називаються данi, оголошення яких розмiщенi в опи-
совiй частинi основної програми. Глобальнi данi зберiгаються в сег-
ментi даних та iснують на протязi всього часу виконання програми.
Глобальнi данi доступнi як в основнiй програмi, так i в усiх
пiдпрограмах будь-якого рiвня вкладеностi, розмiщених нижче по текс-
ту в описовiй частинi основної програми.
Локальними називаються данi, розмiщенi всерединi пiдпрограми.
Локальнi данi зберiгаються в сегментi стеку i iснують вiд моменту
входу у пiдпрограму до моменту завершення її роботи.
Локальнi данi доступнi з мiсця їх оголошення в усiх вкладених
пiдпрограмах, розмiщених нижче по тексту охоплюючої пiдпрограми. Як-
що iм'я локальної змiнної, оголошеної в пiдпрограмi, спiвпадає з
iменем глобальної змiнної основної програми, або з iменем локальної
змiнної, розмiщеної в однiй iз охоплюючих пiдпрограм, то воно перек-
риває область дiї цiєї змiнної.
Для доступу до глобальних змiнних у пiдпрограмах, перекритих
областю дiї одноiменних локальних змiнних, можна використати пункту-
ацiю main.iдентифiкатор_змiнної, де main - iм'я основної програми.
Якщо у пiдпрограмi необхiднi використати значення перекритої змiнної
охоплюючої пiдпрограми, то його необхiдно передати через список па-
раметрiв.
Program main;
var {опис змiнних в основнiй програмi}
x: integer;
{пiдпрограма роботи з глобальними змiнними}
Procedure glob;
begin {змiнна x не описана в пiдпрограмi - це
є змiнна основної програми (глобальна)}
x:=1
end;
{пiдпрограма роботи з локальними змiнними}
Procedure loc;
var {змiнна x описана в пiдпрограмi - це
є локальна змiнна, вона не впливає
на x в основнiй програмi}
x:integer;
begin
x:=1;
writeln('main.x=',main.x) { main.x=0 }
end;
{операторна частина основної програми}
begin
x:=0;
glob;
writeln('x1=',x); { x1=1 }
x:=0;
loc;
writeln('x2=',x); { x2=0 }
end.
Типованi константи, розмiщенi всерединi пiдпрограми, зберiга-
ються у сегментi даних, iснують на протязi всього часу роботи прог-
рами i називаються статичними даними. Статичнi данi iнiцiалiзуються
тiльки один раз при першому входi у пiдпрограму, а далi зберiгають
промiжнi значення при кожному наступному входi у пiдпрограму.
var i:byte;
Procedure PROC;
Const x:byte=0;
Begin
Inc(x);
write(x:2); { 1 2 3 4 5}
End;
Begin
for i:=1 to 5 do PROC;
writeln
End.
Передача даних через список параметрiв
Фактичними називаються параметри, заданi при звертаннi до
пiдпрограми. Формальними називаються параметри, записанi в заголовку
пiдпрограми у круглих дужках пiсля її iменi.
Формальнi параметри задаються у виглядi списку змiнних, пiсля
якого через двокрапку вказується їх тип. Тип формальних параметрiв
задається за допомогою iдентифiкатора, визначеного у блоцi type
охоплюючої пiдпрограми.
Фактичнi параметри розмiщуються у стек даних в порядку їх
слiдування у списку i присвоюються вiдповiдним формальним парамет-
рам. Списки фактичних та формальних параметрiв мають вiдповiдати по
кiлькостi, порядку слiдування та типах вiдповiдних параметрiв.
Формальнi параметри є чотирьох видiв:
- параметри-значення;
- параметри-змiннi;
- нетипованi параметри-змiннi;
- параметри-константи.
Параметри-значення оголошуються наступним чином:
список iдентифiкаторiв: iдентифiкатор_типу;
Вiдповiднi фактичнi параметри можуть бути виразами, сумiсними з
типом формальних параметрiв. При входi у пiдпрограму значення фак-
тичних параметрiв присвоюється вiдповiдним формальним параметрам.
Формальнi парметри-значення мають властивостi локальних змiнних.
Змiна формальних параметрiв-значень у пiдпрограмi не впливає на зна-
чення фактичних параметрiв. За допомогою параметрiв-значень не можна
передати данi з пiдпрограми у викликаючу програму.
Параметри-змiннi оголошуються за допомогою ключового слова var:
var список iдентифiкаторiв: iдентифiкатор_типу;
Вiдповiднi фактичнi параметри повиннi задаватися iдентифiкато-
рами змiнних. Фактичнi та формальнi var-параметри повиннi мати то-
тожний тип. При входi у пiдпрограму значення формального параметру
присвоюється вiдповiдному формальному параметру. Формальнi парамет-
ри-змiннi мають властивостi глобальних змiнних. Змiна їх значення у
пiдпрограмi впливає на значення вiдповiдних фактичних параметрiв. За
допомогою параметрiв-змiнних можна повертати данi у викликаючу
пiдпрограму. При виходi з пiдпрограми значення формального параметра
присвоюється вiдповiдному фактичному параметру.
var {опис змiнних в основнiй програмi}
x: integer;
{пiдпрограма роботи з параметрами-змiнними}
Procedure par_var(var y:integer);{при такому описi 'y' є
тотожним з 'x' основної
програми }
begin
y:=1
end;
{пiдпрограма роботи з параметрами-значеннями}
Procedure par_val(y: integer); {при такому описi 'y' не
впливае на 'x' в основнiй
програмi }
begin
y:=1;
end;
{операторна частина основної програми}
begin
x=0;
par_var(x);
writeln('x1=',x); { x1=1 }
x:=0;
par_val(x);
writeln('x2=',x); { x2=0 }
end.
Нетипованi параметри-змiннi теж оголошуються за допомогою слова
var, але їх тип не вказується:
var список iдентифiкаторiв;
Вiдповiднi фактичнi параметри можуть змiнними будь-якого типу.
Для роботи у пiдпрограмi формальним параметрам необхiдно присвоїти
тип за допомогою явного перетворення типу, або використання абсолют-
них змiнних. Змiна формального параметра у пiдпрограмi впливає на
значення фактичного параметра у викликаючiй програмi.
var x1:real;
y1:string;
Procedure PROC(var x2,y2); { тип параметрiв вiдсутнiй }
var z:real absolute x2; { z та x2 розмiщенi по однiй адресi }
Begin
z:=z+PI;
string(y2):=string(y2)+'ef' { явне перетворення типу }
End;
Begin
x1:=0;
y1:='abcd';
PROC(x1,y1);
writeln(x1:5:2,'':2,y1) { 3.14 abcdef}
End.
Починаючи з версiї Турбо Паскаль 7.0, вводяться формальнi пара-
метри-константи, якi оголошуються за допомогою слова const:
const список iдентифiкаторiв:iдентифiкатор_типу;
Вiдповiднi фактичнi параметри задаються у виглядi виразу
сумiсного типу. Формальнi параметри-константи не можуть бути змiненi
всерединi пiдпрограми, тобто вони не мають зустрiчатися злiва вiд
операцiї присвоєння.
Function FUNC(const x:integer):integer;
Begin
FUNC:=x+1;
End;
Begin
writeln(FUNC(1)) { 2 }
End.
Параметри-константи можуть задаватися без оголошення типу. В
цьому випадку необхiдне явне приведення типу константи всерединi
пiдпрограми. Вiдповiдний фактичний параметр повинен бути iдентифiка-
тором змiнної будь-якого типу.
var x,y:integer;
Function FUNC(const x,y):integer;
var z:integer absolute y;
Begin
FUNC:=integer(x)+z;
End;
Begin
x:=1;
y:=1;
writeln(FUNC(x,y)) { 2 }
End.
Передача масивiв
Тип формального параметру пiдпрограми повинен задаватися за до-
помогою наперед визначеного iдентифiкатора типу. Для параметрiв-ма-
сивiв це означає, що їх iндексний тип, i вiдповiдно максимальна
розмiрнiсть, не можуть бути змiненi при виклику пiдпрограми. Часто
буває необхiдно передавати у пiдпрограму масиви рiзної розмiрностi
для визначеного базового типу. Цього можна досягти одним iз наступ-
них способiв:
1) використання при оголошеннi формальних параметрiв - масивiв з
iндексним типом максимально необхiдної потужностi i передача кiль-
костi використовуваних елементiв за допомогою додаткових параметрiв;
2) використання формальних параметрiв-вказiвникiв на масив та додат-
кових параметрiв, що визначають його розмiрнiсть;
3) використання нетипованих параметрiв-змiнних;
4) використання оголошення вiдкритих масивiв (починаючи з версiї
Турбо Паскаль 7.0).
Наступнi приклади демонструють використання кожного з пере-
рахованих способiв.
1) Оголошення масиву з максимальною кiлькiстю елементiв.
Const m=100;
Type basetype=real;
arr=array[1..m] of basetype;
var a:arr;
i:integer;
Function MinElem(b:arr;n:integer):basetype;
var min:basetype;
i:integer;
Begin
min:=b[1];
for i:=2 to n do
if b[i]<min then min:=b[i];
MinElem:=min
End;
Begin
Randomize;
for i:=1 to 5 do a[i]:=Random;
writeln('Мiнiмальний елемент= ',MinElem(a,5):8:4)
End.
2) Використання вказiвника на масив.
const n=4;
var i,j:integer;
var a,b,c:array[1..n,1..n] of real;
Procedure SumMatr(pa,pb,pc:pointer;n:integer);
var i,j,size:integer;
a,b,c:^real;
Begin
size:=sizeof(real);
for i:=0 to n-1 do
for j:=0 to n-1 do
begin
a:=PTR(SEG(pa^),OFS(pa^)+(i*n+j)*size);
b:=PTR(SEG(pb^),OFS(pb^)+(i*n+j)*size);
c:=PTR(SEG(pc^),OFS(pc^)+(i*n+j)*size);
c^:=a^+b^
end
End;
Begin
Randomize;
for i:=1 to n do
for j:=1 to n do
begin
a[i,j]:=Random;
b[i,j]:=Random
end;
SumMatr(@a,@b,@c,n);
for i:=1 to n do
begin
for j:=1 to n do
write(c[i,j]:5:2);
writeln
end
End.
3) Використання нетипованих формальних параметрiв.
Program MasVarLong;
Var a:array[1..10] of real;
b:array[1..20] of real;
i:integer;
{$R-}
Function Norma(var x; N:integer):real;
Type arr=array[1..1] of real;
Var i:integer;
s:real;
Begin
s:=0;
for i:=1 to N do s:=s+SQR(arr(x)[i]);
Norma:=SQRT(s)
End;
{$R+}
BEGIN
RANDOMIZE;
for i:=1 to 10 do
a[i]:=Random;
for i:=1 to 20 do
b[i]:=Random;
writeln(' норма a =',Norma(a,10):10:7);
writeln(' норма b =',Norma(b,20):10:7)
END.
4) Використання вiдкритих масивiв.
Оголошення вiдкритих масивiв здiйснюється в списку формальних
параметрiв пiдпрограми наступним чином:
iдентифiкатор:array of базовий тип;
Вiдповiдний фактичний параметр задається у виглядi iдентифiка-
тора масиву або посилання на нього. Фактичний параметр може мати
рiзну кiлькiсть елементiв визначеного базового типу. Кiлькiсть еле-
ментiв масиву-формального параметра буде визначатися кiлькiстю еле-
ментiв масиву-фактичного параметра.
Вiдкритий масив може бути оголошений як параметр-значення або
параметрзмiнна. Вiдкритим можна оголосити тiльки одномiрний масив.
Iндексацiя вiдкритого масиву починається з нуля.
const n=5;
m=10;
var x:array[1..n] of real;
y:array[1..m] of real;
i:integer;
Function SUMA(a:array of real):real;
var i,k:integer;
s:real;
Begin
s:=0;
k:=Trunc(sizeof(a)/sizeof(real));
for i:=0 to k-1 do
s:=s+a[i];
SUMA:=s
End;
Begin
Randomize;
for i:=1 to n do x[i]:=Random;
writeln(SUMA(x):5:2);
for i:=1 to m do y[i]:=Random;
writeln(SUMA(y):5:2)
End.
Передача рядкiв символiв
Якщо рядок символiв передається за допомогою параметрiв-зна-
чень, то вiдповiднiсть по довжинi рядкiв не контролюється, а вима-
гається тiльки сумiснiсть типiв формального та фактичного пара-
метрiв, аналогiчна сумiсностi по присвоєнню: формальний пара-
метр:=фактичний параметр. Якщо довжина фактичного параметра бiльша
вiд визначеної довжини формального параметра, то вiдбувається вiдки-
дання символiв фактичного параметра, розмiщених зправа. Якщо довжина
фактичного параметра менша або рiвна оголошеної довжини формального
параметра, то у пiдпрограму передаються всi символи рядка.
type tstr=string[5];
var s1:string[10];
Procedure PROC(s:tstr);
Begin
writeln(s) {12345}
End;
Begin
s1:='1234567890';
writeln(s1); {1234567890}
PROC(s1)
End.
Передачу рядка у пiдпрограму та його повернення iз пiдпрограми
можна здiйснити за допомогою параметра-значення, який є вказiвником
на рядок символiв, або за допомогою параметра-змiнної.
При передачi рядка у пiдпрограму через вказiвник вiн автоматич-
но перетворюється до типу string. Таким чином, з викликаючої програ-
ми у пiдпрограму передається повна довжина рядка.
Type tstr=string[5];
ptrstr=^tstr;
var s1:string[10];
Procedure PROC(p:ptrstr);
Begin
writeln(p^) {1234567890}
End;
Begin
s1:='1234567890';
writeln(s1); {1234567890}
PROC(@s1)
End.
При передачi рядка за допомогою параметру-змiнної вимагається
тотожнiсть типiв формального та фактичного параметрiв. З цього вип-
ливає, що вимагається точна вiдповiднiсть довжини формального та
фактичного параметрiв.
type tstr=string[5]; var s1:tstr;
PROC(var s:tstr);
Begin
writeln(s) {12345}
End;
Begin
s1:='12345';
writeln(s1); {12345}
PROC(s1)
End.
При необхiдностi контроль за спiвпаданням довжини формального
та фактичного параметрiв-змiнних можна вiдключити за допомогою ди-
рективи компiлятора {$V-} (для версiй Турбо Паскаль 6,0, 7.0). По
змовчуванню дiє директива {$V+}. В режимi {$V-} довжина формального
параметра-змiнної доповнюється до максимально можливої для рядкiв
(255), iгноруючи виконане оголошення. Таким чином, в цьому режимi
фактичний параметр-рядок повнiстю передається у пiдпрограму.
Type tstr=string[5];
var s1:string[10];
{$V-}
Procedure PROC(var s:tstr);
Begin
writeln(s) {1234567890}
End;
Begin
s1:='1234567890';
writeln(s1); {1234567890}
PROC(s1)
End.
Якщо формальний параметр рядка задається у виглядi парамет-
ра-змiнної без типу, то вiдповiднiсть його довжини та довжини фак-
тичного параметра не вимагається. Всерединi пiдпрограми необхiдно
лише виконати явне перетворення типу формального параметра до типу
рядка символiв. Довжина рядка, до якого перетворюється формальний
параметр без типу, автоматично доповнюється до 255 (довжини типу
string), тому рядок-фактичний параметр передається у пiдпрограму
повнiстю.
Type tstr=string[5];
var s1:string[10];
Procedure PROC(var s);
Begin
writeln(tstr(s)) {1234567890}
End;
Begin
s1:='1234567890';
writeln(s1); {1234567890}
PROC(s1)
End.
У Турбо Паскаль 7.0 для var-параметрiв типу string введене по-
няття вiдкритого рядка. Вiдкритий рядок встановлюється за допомогою
директиви {$P+} або типу openstring.
Директива $P дiє незалежно вiд встановленої директиви $V. В ре-
жимi {$P+} вимагається тiльки сумiснiсть типiв формального та фак-
тичного параметрiв. Оголошенi довжини взаємновiдповiдних пара-
метрiв-рядкiв можуть не спiвпадати. В цьому випадку довжина формаль-
ного параметра визначається кiлькiстю символiв рядка, що є фактичним
параметром. Наприклад:
var str:string[10];
{$P+}
Procedure PROC(var s:string);
Begin
writeln(s); {123}
s:=s+'4567';
End;
Begin
str:='123';
PROC(str);
writeln(str); {1234567}
End.
Новий тип openstring визначає вiдкритий рядок незалежно вiд ус-
тановок директиви $P, наприклад: Procedure PROC(var s:openstring);
Тип openstring можна використовувати тiльки для оголошення фор-
мальнмих параметрiв-змiнних. Кiлькiсть символiв, переданих у
пiдпрограму, визначається довжиною фактичного параметра.
var str:string[10];
Procedure PROC(var s:openstring);
Begin
writeln(s); {123}
s:=s+'4567';
End;
Begin
str:='123';
PROC(str);
writeln(str); {1234567}
End.
Повернення значень iз пiдпрограми
Результати роботи пiдпрограми-процедури можна повернути у вик-
ликаючу програму через список var-параметрiв. Значення пара-
метрiв-змiнних повертаються через стек програми.
Type complex=record
re,im:real
end;
var a,b,c:complex;
Procedure ADD(x,y:complex; var z:complex);
Begin
z.re:=x.re+y.re;
z.im:=x.im+y.im
End;
Begin
write('Введiть дiйсну та уявну частину комплексного числа a ->');
with a do readln(re,im);
write('Введiть дiйсну та уявну частину комплексного числа b ->');
with b do readln(re,im);
ADD(a,b,c);
write('Сума двох комплексних чисел ->');
with c do writeln(re:8:4,im:8:4)
End.
Результатом роботи функцiї є скалярне значення одного iз прос-
тих типiв, рядок символiв або вказiвник. Значення цих типiв переда-
ються через регiстри процесора або через додаткову пам'ять.
var n:integer;
Function FACTORIAL(m:integer):longint;
var i:integer;
f:longint;
Begin
f:=1;
for i:=1 to m do
f:=f*i;
FACTORIAL:=f
End;
Begin
write('Введiть цiле число ->');
readln(n);
writeln('Факторiал числа ',n:2,' дорiвнює ',FACTORIAL(n))
End.
У Турбо Паскалi в якостi формальних параметрiв функцiї можна
задавати параметри-змiннi. За їх допомогою теж можна впливати на
значення вiдповiдних фактичних параметрiв у викликаючiй програмi,
але для функцiй так робити не рекомендується. Для повернення декiль-
кох значень iз пiдпрограми її потрiбно оформити у виглядi процедури.
Процедурнi типи даних
Процедурнi типи даних використовуються для оголошення змiнних,
яким можна присвоїти iм'я процедури або функцiї, а також для оголо-
шення формальних параметрiв пiдпрограми.
Для оголошення процедурних типiв використовується заголовок
процедури або функцiї з опущеним iменем пiдпрограми, наприклад:
Type
tproc=Procedure(var x,y:integer);
tfunc=Function(z:real):integer;
Тепер можна оголосити змiннi процедурних типiв:
Var p:tproc;
q:Procedure; {процедура без параметрiв}
a:array[1..10] of tproc;
f:tfun;
g:Function:real; {функцiя без параметрiв, що повертає значення типу real}
Iнiцiалiзацiя процедурних змiнних здiйснюється шляхом прис-
воєння їм iменi пiдпрограми. При присвоєннi необхiдна сумiснiсть по
типу (функцiя чи процедура), кiлькостi формальних параметрiв, поряд-
ку їх слiдування та типах. Крiм того, пiдпрограми повиннi бути до-
сяжними у мiсцi виконання присвоєння, а також вiдкомпiльованими в
режимi далекого виклику {$F+}.
Якщо змiннiй процедурного типу присвоєно iм'я пiдпрограми, то
звертання до пiдпрограми може бути здiйснене за допомогою цiєї
змiнної. Для цього записується iдентифiкатор змiнної процедурного
типу, пiсля якого у круглих дужках вказується список фактичних пара-
метрiв, наприклад: p(x,y), a[i](x,y) .
Приклад оголошення та використання процедурних типiв:
Type tfunc=Function(z:integer);
Var f:tfunc;
{$F+}
Function FUNC(z:real):integer;
Begin
{...}
End;
{$F-}
Begin
f:=FUNC; {або f:=@FUNC;} ??????????????
writeln(f(3.5));
End.
Процедурнi змiннi приймають значення адреси пiдпрограми проце-
дури або функцiї i займають у пам'ятi 4 байти: старшi 2 байти - сег-
ментна частина адреси, молодшi 2 байти - змiщення.
Адресу пiдпрограми можна визначити також за допомогою операцiї
@, яка повертає результат типу pointer. Для запуску пiдпрограми по
вiдомiй адресi необхiдно використати явне перетворення типу pointer
до вiдповiдного процедурного типу, наприклад:
var p:pointer; { оголошення iз попереднього прикладу}
Begin
p:=@FUNC;
writeln(tfunc(p)(3.5))
End.
Параметри типу "процедура"
Процедурнi типи даних можуть бути використанi для оголошення
формальних параметрiв пiдпрограм. За допомогою таких параметрiв мож-
на передавати у пiдпрограму iмена процедур та функцiй.
Пiдпрограми, що передаються через параметри типу "процедура",
повиннi вiдповiдати наступним вимогам:
1) повиннi бути вiдкомпiльованi в режимi {$F+};
2) не можуть бути вкладеними;
3) не можуть входити у стандартнi бiблiотеки;
4) не можуть мати атрибути inline та interrupt.
Процедурнi типи не можуть бути використанi для оголошення типу
функцiї.
Для прикладу розглянемо програму обчислення iнтегралу функцiї
y=cos(exp(x)) методом трапецiй на iнтервалi [-1,1]. Суть методу тра-
пецiй полягає у розбиттi iнтервалу iнтегрування на парну кiлькiсть
частин, апроксимацiї функцiї на кожному пiдiнтервалi прямою лiнiєю
та знаходженнi суми площ трапецiй, що утворюються при цьому. Обчис-
лення можна вести при фiксованiй кiлькостi розбиттiв iнтервалу
iнтегрування, або до моменту досягнення заданої точностi при зрос-
таннi кiлькостi розбиттiв.
Передача iменi пiдiнтегральної функцiї в якостi параметру у
функцiю обчислення iнтегралу методом трапецiй дає можливiсть обчис-
лювати iнтеграли для рiзних функцiй без змiни функцiї, що реалiзує
метод трапецiй.
Program trapintegral;
Const eps=1.0E-4;
Type tfun=Function(x:real):real;
Var n:integer;
I1n,I2n:real;
{$F+}
Function fun1(x:real):real;
Begin
fun1:=cos(exp(x));
End;
Function integral(fun:tfun; a,b:real; n:integer):real;
Var x,s,h:real;
Begin
h:=(b-a)/n;
s:=(fun(a)-fun(b))/2;
x:=a;
While x<b do
begin
x:=x+h;
s:=s+fun(x);
end;
integral:=h*s;
End;
Begin
n:=10;
I2n:=integral(fun1,-1,1,n);
Repeat
I1n:=I2n;
n:=2*n;
I2n:=integral(fun1,-1,1,n);
Until abs(I1n-I2n)/I1n<=eps;
writeln(I2n);
End.
Iтеративнi та рекурсивнi пiдпрограми
В задачах обчислювальної математики широко використовуються ал-
горитми наближення, в яких кожне наступне значення обчислюється че-
рез модифiковане попереднє значення. Такi алгоритми називаються iте-
рацiйними. В залежностi вiд виду модифiкацiї значення виразу
розрiзняють мультиплiкативнi, аддитивнi або комбiнованi iтерацiйнi
алгоритми.
Для програмування iтерацiйних алгоритмiв використовуються рiзнi
види операторiв циклу. Iншим способом запису iтерацiйних алгоритмiв
є використання рекурсiї.
У Турбо Паскалi в операторнiй частинi допускається звертання
пiдпрограми до самої себе. Пiдпрограми, побудованi таким чином, на-
зиваються рекурсивними. Рекурсивнi пiдпрограми обчислюються у два
етапи: прямий та зворотнiй хiд. Пiд час прямого ходу результати
промiжних обчислень при рекурсивних викликах пiдпрограм записуються
у стек. Кiлькiсть iтерацiй рекурсивного алгоритму повинна бути обме-
женою. Як вiдомо, загальний об'єм стеку не повинен перевищувати 64
Кбайт. Останнє значення рекурсiї повинно бути iнiцiалiзоване. При
зворотньому ходi цi результати читаються зi стеку i приймають участь
в обчисленнi iтерацiйного алгоритму.
Наступний приклад демонструє використання iтерацiй та рекурсiй
для обчислення суми n членiв ряду: s = 1 + 1/2 + 1/3 + ... + 1/n.
var sum1,sum2,sum3,sum4: real;
n:integer;
{пiдпрограма-процедура знаходження суми членiв ряду методом iтерацiй}
Procedure iter(var s:real; n: integer);
var i: integer;
begin
s:=0.;
for i:=1 to n do
s:=s+1/i;
end;
{пiдпрограма-функцiя знаходження суми членiв ряду методом iтерацiй}
Function f_iter(n: integer):real;
var i: integer;
s: real;
begin
s:=0;
for i:=1 to n do
s:=s+1/i;
f_iter:=s
end;
{пiдпрограма-процедура знаходження суми членiв ряду методом рекурсiї}
Procedure recurs(var s:real; n: integer);
begin
if n=1
then s:=1
else
begin
recurs(s,n-1);
s:=s+1/n;
end;
end;
{пiдпрограма-функцiя знаходження суми членiв ряду методом рекурсiї}
Function f_recurs(n:integer):real;
begin
if n=1
then f_recurs:=1
else
f_recurs:=f_recurs(n-1)+1/n
end;
{операторна частина основної програми}
begin
write('Введiть кiлькiсть членiв ряду n=');
readln(n);
iter(sum1,n);
recurs(sum2,n);
sum3:=f_iter(n);
sum4:=f_recurs(n);
writeln('sum1=',sum1:10:5,' sum2=',sum2:10:5,
' sum3=',sum3:10:5,' sum4=',sum4:10:5)
end.
Порядок роботи
1. Ознайомитися з правилами побудови та використання пiдпрограм
на мовi Турбо Паскаль.
2. По виданому завданню розробити алгоритм та програму розв'язку
задачi.
3. Оформити звiт по роботi по наступнiй схемi:
- назва роботи;
- мета роботи;
- теоретичнi вiдомостi;
- завдання для роботи;
- програма на мовi Турбо Паскаль;
- висновки
Iндивiдуальнi завдання
Написати програму з використанням процедури та функцiї для
розв'язку наступних задач:
1. Перевести дробову частину додатнього десяткового числа у
двiйкову систему числення, обмежившись 8 двiйковими розрядами.
Двiйкове число сформувати у виглядi рядка символiв.
2. Перевести n-розрядне цiле двiйкове число без знаку у десяткову
систему числення.
3. Перевести цiле додатнє десяткове число у шiстнадцяткову систему
числення. Шiстнадцяткове число сформувати у виглядi рядка
символiв.
4. Перевести n-розрядне цiле додатнє число з шiстнадцяткової
системи числення у десяткову.
5. Перевести цiле додатнє десяткове число у двiйкову систему
числення. Двiйкове число сформувати у виглядi рядка символiв.
6. Знайти максимальний вiд'ємний елемент одномiрного масиву цiлих
чисел.
7. Задана квадратна матриця дiйсних чисел n-го порядку. Знайти
мiнiмальний елемент серед елементiв, якi знаходяться нижче
головної дiагоналi.
8. Задана квадратна матриця дiйсних чисел n-го порядку. Знайти
максимальний елемент серед елементiв, якi знаходяться вище
побiчної дiагоналi.
9. var k: integer;
C: array [1..10,1..15] of char;
Визначити k - кiлькiсть рiзних елементiв масиву C (елементи, що
повторються, рахуються один раз).
10. Визначити, чи задана цiла квадратна матриця є симетрична вiдносно
головної дiагоналi.
11. Визначити чи задана цiла квадратна матриця є
ортонормованою, тобто такою, в якiй скалярний добуток кожної
пари рiзних рядкiв дорiвнює 0, а скалярний добуток кожного
рядка на себе дорiвнює 1.
12. Для заданих оголошень
type слово = array [1..5] of char;
список= array [1..60] of слово;
var C: список;
надрукувати слово iз списку С, яке по алфавiту передує всiм
iншим словам цього списку.
13. Задана змiнна рядкового типу m:string[100]. Замiнити групу
однакових символiв, що йдуть пiдряд, на один символ цiєї
групи.
14. Задана послiдовнiсть символiв. Роздрукувати цю послiдовнiсть,
витерши з неї всi цифри.
15. Задана послiдовнiсть символiв, що зображає запис виразу на
мовi Паскаль. Перевiрити вираз на вiдповiднiсть кiлькостi
вiдкритих та закритих круглих дужок.
16. Задана послiдовнiсть символiв. Перевiрити, чи ця послiдовнiсть
правильно зображає запис цiлого числа зi знаком.
17. Задана послiдовнiсть символiв. Перевiрити, чи ця послiдовнiсть
правильно зображає iдентифiкатор Паскаля.
18. Пiдрахувати кiлькiсть символiв рядка
Var s: string[100];
що входять в множину ['0'..'9', '+','-','*','/'].
19. Написати функцiю для пiдрахунку кiлькостi рiзних значимих цифр
в десятковому записi натурального числа n. Цифри iз числа
видiляти справа налiво i записувати їх у множину.
20. Заданий рядок, що складається iз слiв, роздiлених пропусками.
Використовуючи роботу iз множинами знайти слово з мiнiмальною
кiлькiстю приголосних букв.
21. Заданий масив записiв з iнформацiєю про успiшнiсть групи
студентiв по дисциплiнi програмування: прiзвище, iм'я,
по-батьковi, оцiнка. Знайти середнiй бал групи по цiй
дисциплiнi.
22. Заданий текстовий файл. Знайти та надрукувати його найдовший
рядок.
23. Заданий файл дiйсних чисел. Знайти мiнiмальний елемент цього
файлу.
24. Заданий файл дiйсних чисел. Пiдрахувати кiлькiсть елементiв,
що потрапляють в дiапазон [a,b].
25. Заданий файл цiлих чисел з iнтервалу 0..999. Перевiрити, чи
записи цього файлу впорядкованi по зростанню значень.
26. Заданий файл елементiв дiйсного типу. Пiдрахувати кiлькiсть
елементiв файлу, менших середнього арифметичного всiх його
елементiв.
27. Перевiрити, чи у файлi записiв (прiзвище, адреса, телефон,
номер автомобiля, дата технiчного контролю, штраф) для
вказаного клiєнта є вiдмiтка про технiчний контроль автомобiля
в бiжучому роцi.
28. Вiдомостi про автомобiль складаються iз його марки, номера, та
прiзвища власника. Заданий файл f, що мiстить вiдомостi про
декiлька автомобiлiв. Знайти кiлькiсть автомобiлiв заданої
марки.