Sunteți pe pagina 1din 46

Funcţii şi proceduri în Pascal. Aspecte metodice.

Prof. informatică Grigore Vasilache


Colegiul Financiar-Bancar din Chişinău

Definiţiile de bază

 Definiţie a subprogramului este o descriere a acţiunilor de abstractizare a


subprogramului.
 Un apel subprogram este o cerere explicită ca subprogramul sa fie executat.
 Un subprogram se spune că este activ, dacă după ce a fost apelat, a început
execuţia dar încă nu s-a finisat.
 Există două tipuri fundamentale de subprograme:
o Proceduri
o Funcţii
 Un antet subprogram este prima linie a definiţiei, serveşte mai multe definiţii:
o Aceasta precizează că următoarea unitate sintactică este o definiţie a unui
subprogram aparte.
o Antetul prevede un nume pentru subprogram.
o Se poate de specificat opţional o listă de parametri.

 Consider următoarele exemple:


void f();
void h(int n, double x, ...);
int g();
double df(long a, int b, unsigned c);
 Profilul parametrului subprogramului este numărul, ordinea şi tipul
parametrului formal.
 Prototipul subprogramului, dacă este funcţie, returnează un tip.
 O declaraţie de subprogram prevede prototipul, dar nu corpul de
subprogramului.
 Un parametru formal este o variabilă dummy(marionetă) enumerată în antetul
de subprogram şi utilizată în subprogram.
 Un parametru actual reprezintă o valoare sau o adresă utilizat în declaraţia de
apel al subprogramului.

Referinţe locale

 Majoritatea limbajelor de programare permit subprogramelor să definească


propriile variabile locale, care pot fi statice sau dinamice.
 Variabilele alocate dinamic sunt deobicei implementate în stivă.
  Avantaje includ flexibilitate, utilizarea mai eficientă a memoriei şi fezabilitatea
recursivă.
 Dezavantajele includ costurile de alocare şi dealocare a variabilelor şi costul
indirect de adresare.

Metodele de transmitere a parametrilor

Transmiterea parametrilor include următoarele modele:


 transmitere prin valoare
 transmitere prin nume
 transmitere prin referinţă
 transmitere prin copiere-restaurare

Cu transmitere prin valoare, parametrii actuali sunt evaluaţi în timpul chemării, iar
valorile calculate sunt atribuite parametrilor formali locali corespunzători, înainte de
începerea execuţiei.
Ex:
void schimba(int a, int b)
{ int aux; aux=a; a=b; b=aux ; }
Acum putem vedea de ce procedura schimba nu va lucra când parametrii ei sunt
apelati prin valoare, analizăm mecanismul de functionare, a apelarii
procedurii schimba (j, k) pentru j= 1 si k=2 şi în rezultat a=1 iar b=2.
Ultimele doua atribuiri nu sunt prezentate explicit în programul sursa al
procedurii schimba; ele însă sunt executate automat. Acum, este clar ca
deşi j si k nu s-au schimbat, a şi b şi-au schimbat valorile. Acest lucru este inutil,
evident, deoarece a si b fiind locale, valorile acestora vor dispărea imediat după
execuţia procedurii (schimba). Chiar daca procedura schimba pare a fi ineficace, nu
există lacune referitoare la tehnica apelarii prin valoare, în general. Acest mecanism
a fost ales în mod deliberat (se refera la mecanismul transmiterii parametrilor) pentru
a furniza protecţie maxima împotriva modificarilor nechibzuite ale variabilelor actuale
(efective).

Cu transfer prin nume, expresia sub forma simbolică a fiecărui parametru actual este
substituită la fiecare apariţie a parametrului formal care îi corespunde, iar după
aceea, şi numai după aceea, procedura/funcţia în cauză este executată.

Cu un transfer prin referinţă, adresa (din memoria calculatorului) parametrului actual


este transmisa rutinei (procedurii) apelate. În (Borland) PASCAL, C++ parametrul
actual (efectiv) trebuie sa fie o variabila si nu o expresie generală. Parametrii ce
trebuie sa fie transmişi în acest mod trebuie să fie desemnaţi selectiv ca
parametri VAR(în Pascal) sau cu operatorul &(în C++) în header-ul functiei sau al
procedurii.
Ex:
void schimba_ref(int &a, int &b)
{ int aux; aux=a; a=b; b=aux ; }
Procedura schimba_ref este aceeaşi cu procedura schimba pe care am prezentat-o
anterior, cu singura deosebire că variabilele a si b sunt precedate de operatorul
& pentru a arăta că atât a cât si b sunt apelate prin referinţă.

Transmiterea prin copiere-restaurare încearcă să îmbunătăţească transferul prin


valoare, simulând comportarea unuia prin referintă. Acest transfer, ca si cel prin
nume, a fost abandonat în cadrul implementărilor curente ale limbajelor de
programare.
Transferul prin copiere si restaurare execută doua copieri succesive, una în
momentul lansării subprogramului si cealaltă în momentul terminării acestuia. În
prima faza, parametrii efectivi sunt copiaţi în cei formali, ca si cum ar fi transferaţi
prin valoare. Dupa executia corpului subprogramului, are loc o copiere "inversă",
adica parametrii formali sunt copiati în cei efectivi (actuali).
Dacă procedura schimba ar fi compilată sub o versiune de C/C++ ce suporta acest
transfer de parametri, atunci ea si-ar executa sarcina corect. Dupa inversarea
valorilor în interiorul procedurii, valorile (inversate, deci) ar fi fost copiate în
parametrii actuali. Ca si în cazul transferului prin referinţă, o condiţie a parametrilor
efectivi ar fi fost aceea de a fi variabile singulare, si nu expresii sau constante.
Abandonarea acestui tip de transfer s-a facut în favoarea celui prin referinţă, din
cauza exactităţii mai mari de prelucrare a parametrilor efectivi.
După ce elevii înţeleg noţiunile generale despre subprograme, cunosc ce este
parametru formal, parametru actual, variabile locale şi globale atunci eu le explic
schematic elevilor cum lucrează un program care foloseşte subprograme.
Ex: Ce o să afişeze următorul program?
#include<iostream.h> #include<conio.h> int a=2,b=2, c=3, d=3;
void p(int &, int); main()
{ clrscr();
p(a,b); cout<<a<<b<<c<<d<<endl;
p(c,d); cout<<a<<b<<c<<d<<endl;
}
void p(int &b, int c)
{ int d=0; a*=2;b*=2;c*=3; d*=2; cout<<a<<b<<c<<d<<endl;}

În segmentul de date se păstrează datele


variabilelor globale, iar în stivă valorile
variabilelor locale. La primul apel de
procedură p(a,b), parametrul formal &b
arată la adresa variabilei a, iar
parametrul formal c ia copia valorii
p(c,d)
Apelul doi

p(a,b)
Primul apel

variabilei b, iar d este locală şi


iniţializată cu 0. După efectuarea
instrucţiunilor de atribuire, se afişează
valorile lui a, b, c, d din procedură şi
apoi din programul principal. După
primul apel al procedurii se obţine
Segmentul de date
d

Segmentul de date

urătorul rezultat:
c

a
d
3

8860
16
6

4 8

8233
d

La apelul doi p(c,d), parametrul b arată


Stiva
Stiva

la adresa lui c din segmentul de date,


0

-
-

iar c din stivă ia copia lui d din


segmentul de date. În rezultatul apelului
9

doi obţinem:

16690

Vreau să zic, cu ajutorul acestei metode succesele mele la disciplinile de predare


unde utilizăm subprograme sunt mult mai mari, elevii sunt mai siguri de rezultatul pe
care îl obţin lucrând cu această metodă.
Caracteristicile generale ale unui subprogram

a) Un subprogram are un singur punct de intrare.


b) Apelantul este suspendat în timpul executării subprogramului numit. „Numai un
subprogram se execută într-un moment dat”.
c) Controlul întodeauna revine la apelant după ce execuţia subprogramului apelat
sa finisat.

Prin subprogram vom înţelege unansamblu alcătuit din tipuri de date,variabile şi


instrucţiuni scrise în vedereaunei anumite prelucrări (calcule, citiri,scrieri) şi care
poate fi utilizat (rulat)doar dacă este apelat de un programsau de alt subprogram.

AVANTAJELE UTILIZĂRIISUBPROGRAMELOR:

realizarea codului – o dată scris, un subprogram poate fi utilizat de mai multe programe;

elaborarea algoritmilor prin descompunerea problemei în altele mai simple. În acest fel,
rezolvăm cu mult mai uşor problema;

reducerea numărului de erori care pot apărea la scrierea programelor;

depistarea cu uşurinţă a erorilor – verificăm la început subprogramele, apoi modul în
care le-am apelat în cadrul programului.

Tipuri de parametri

Parametrii care se găsesc în apelul funcţiei se numesc parametri formali.
Atunci când scriem o funcţie nucunoaştem valoarea propriu-zisă aparametrilor. Funcţia
trebuie să întoarcărezultatul corect, oricare ar fi valoarea lor.Din acest punct de vedere
ei se numesc formali

Parametrii care se utilizează la apel senumesc parametri efectivi.


La apel, valorile sunt cunoscute. Deaceea se numesc efectivi.Pentru
apelulrez=subp(n);parametrulefectiv esten.

Structura funcţiilor şi apelul lor 


Stuctura antetului este:
tip nume(lista parametrilor formali)
Lista parametrilor formali este de forma: parametru 
1
,parametru 

,…parametru 
n
Există posibilitatea ca lista parametrilor formali să fie vidă.Fiecare parametru are
forma:tip nume
Declararea variabilelor 
Există posibilitatea ca variabilele să fie memorate într-unanumit registru al
microprocesorului. În acest caz timpul de acces la astfel de variabile este foarte
mic,deci se pot obţine programe optimizateO variabilă se caracterizează prin 4 atribute:
1. Clasa de memorare;
2. Vizibilitate
3. Durata de viaţă
4. Tipul variabilei 

Precizează locul unde estememorată variabila respectivă. Ovariabilă poate fi


memorată însegmentul de date, în cel destivă, în heap sau într-un registru al
microprocesorului 

2. Vizibilitate
Precizează liniile textului sursă din care variabilarespectivă poate fi accesată. Astfel avem:

Vizibilitate la nivel de bloc(instrucţiune compusă);

Vizibilitate la nivel de fişier – în cazul în care programul ocupă un singur fişier sursă;

Vizibilitate la nivel de clasă – este în legătură cu  programarea pe obiecte.

3. Durata de viaţă
Reprezintă timpul în care variabila respectivă arealocat spaţiul în memoria internă. Astfel avem:

Durata statică – variabila are alocat spaţiu în tot timpul execuţiei programului 

Durata locală – variabila are alocat spaţiu în timpul în care se execută instrucţiunile blocului
respectiv 

Durată dinamică – alocarea şi dezalocarea spaţiului necesar variabilei respective se face de
către programator prin operatori sau funcţii speciale.

Tipul parametrilor formalitrebuie să coincidă cu tipulparametrilor efectivi sautipul


parametrilor efectivi săpoată fi convertit implicitcătre tipul parametrilor formali la fel
ca în cazulatribuirii

FUNCTIA 

este un subprogram, care calculeaza si returneaza o singura valoare.Ea extinde
notiunea de expresie Pascal.
Prima linie esteantetul functiei,format din:
F- numele functiei;F(X1,X2,«.,Xn)- lista optionalade parametri formali, fiind argumentele
functiei;Tr ±tipul rezultatului, trebuiesa fie tip simplu saureferinta


unctie care returneaza media aritmetica a 5 numere intregi:
Function media (x,y,z,k,m:integer):real;BeginMedia := (x+y+z+k+m)/5End;

T
ype natural=0..MaxInt;Function pro(N:natural):natural;BeginP:=1;RepeatC:=N Mod 10;
P:=P*C; N:=N div 10Until N=0; pro:=PEnd;
PRO
CEDU


-
este un subprogram care prelucreaza datele transmise la apel.
Scrie o procedura care afiseaza la ecrans o l u t i a   e c u a t i e i A x + B = 0 :
Procedure ecuatie(a,b:real);BeginIf A<>0 then writeln (solutia=,b/a:7:2)ElseIf b=0 then writeln
(infinit)Else writeln (nu exista)End;
Subprograme (proceduri si functii)

Vi s-a intamplat sa aveti nevoie sa faceti un program si sa fie nevoie sa repetati o


secventa de cod in mai multe locuri din program ? Probabil ca da, posibil ca nu.
Vi s-a intamplat sa aveti nevoie sa va ordonati codul in alt fel decat insiruirea liniilor una
dupa alta, sa zicem ... dupa functionalitate ?

Pentru a usura aceste lucruri, Pascal ofera subprogramele: proceduri si functii. Pe


scurt, acestea sunt parti de program care pot fi folosite apeland numele lor.

Proceduri

Sa vedem cum arata o structura generala a unei proceduri:


LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL
1. procedure nume_procedura [(lista_parametri)];
2. CONST  (* declaratii de constante *)
3.  VAR  (* declaratii de variabile *)
4.  BEGIN  (* instructiuni *)END;

De remarcat ca, spre deosebire de structura unui program, end-ul de la sfarsit este


finalizat cu ; (punct si virgula), nu cu . (punct). Lista de parametri este optionala, motiv
pentru care este incadrata intre paranteze drepte. Ce inseamna parametri va fi explicat
putin mai tarziu.

Sa vedem un program obisnuit folosind proceduri. Programul original (fara proceduri) ar


fi urmatorul:
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL
1. var vector : array[1..200] of integer;
2.     i, n: integer;
3. begin
4.   Write('Dati N: '); ReadLn(n); {N = numarul de elemente}
5.  
6.   i := 1; {*}
7.   while (i <= N) do {citim elementele}
8.     begin
9.       Write('Dati elementul ', i, ': ');
10.      ReadLn(vector[i]);
11.      i := i + 1;
12.    end;
13. 
14.  i := 1; {*}
15.  while (i <= N) do {impartim fiecare element la 2 si salvam catul}
16.    begin
17.      vector[i] := vector[i] div 2;
18.      i := i + 1;
19.    end;
20. 
21.  Write('Vectorul modificat este : ');
22. 
23.  i := 1; {*}
24.  while (i <= N) do {afisam noile valori din vector}
25.    begin
26.      Write(vector[i] : 5);
27.      i := i + 1;
28.    end;
29. 
30.  ReadLn; {asteptam sa fie apasat Enter}
31.end.

Vedeti secventele marcate cu {*} ? Aceeasi instructiune, repetata de 3 ori... Bineinteles,


intr-un program mai mare si mai stufos, secventele care se repeta contin mai multe
instructiuni ... si probabil se repeta de mai multe ori.

Sa vedem cum rescriem programul folosind o procedura care sa faca acelasi lucru (sa
initializeze variabila i cu 1).
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL
1. var vector : array[1..200] of integer;
2.     i, n: integer;
3.  
4.   procedure Init;
5.   begin
6.     i := 1;
7.   end;
8.  
9. begin
10.  Write('Dati N: '); ReadLn(n); {N = numarul de elemente}
11. 
12.  Init; {*}
13.  while (i <= N) do {citim elementele}
14.    begin
15.      Write('Dati elementul ', i, ': ');
16.      ReadLn(vector[i]);
17.      i := i + 1;
18.    end;
19. 
20.  Init; {*}
21.  while (i <= N) do {impartim fiecare element la 2 si salvam catul}
22.    begin
23.      vector[i] := vector[i] div 2;
24.      i := i + 1;
25.    end;
26. 
27.  Write('Vectorul modificat este : ');
28. 
29.  Init; {*}
30.  while (i <= N) do {afisam noile valori din vector}
31.    begin
32.      Write(vector[i] : 5);
33.      i := i + 1;
34.    end;
35. 
36.  ReadLn; {asteptam sa fie apasat Enter}
37.end.

Probabil ca acum va ganditi "Ce mare branza a rezolvat ? Numarul de linii este acum
mai mare !". Da, asa e, dar asa cum am mentionat, acest program este doar un
exemplu simplist.

In acest caz, variabila i este o variabila globala. Nu e declarata in niciun subprogram, ci


direct in programul principal. Procedura Init o poate folosi fiindca variabila a fost
declarata inaintea procedurii (daca erau declarate invers, compilatorul ar fi dat eroare
spunand ca variabila folosita in procedura nu poate fi gasita).

Variabilele declarate in interiorul unui subprogram se numesc variabile locale.

Atentie: Variabilele globale si locale pot avea acelasi nume, lucru care poate duce la


probleme in program.

Sa vedem un alt program care foloseste o procedura pentru a calcula factorialul unui
numar (pentru cei care nu stiu, factorialul unui numar N este produsul lui 1 x 2 x ... x N).
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL
1. var i, n, f: integer;
2.  
3.   procedure Fact;
4.   begin
5.     f := 1;
6.  
7.     for i := 1 to n do
8.       f := f * i;
9.   end;
10. 
11.begin
12.  Write('Dati N: '); ReadLn(n);
13. 
14.  Fact;
15.  Write('Factorial de N este egal cu : ', f);
16. 
17.  ReadLn; {asteptam sa fie apasat Enter}
18.end.
Destul de clar, cred. Sa trecem la ...

Functii

Functiile sunt foarte asemanatoare procedurilor, singura diferenta fiind faptul ca


functiile pot intoarce un rezultat.

Sa vedem cum arata o structura generala a unei functii:


LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL
1. function nume_functie [(lista_parametri)] : tip_rezultat;
2.  
3. CONST
4.   (* declaratii de constante *)
5.  
6. VAR
7.   (* declaratii de variabile *)
8.  
9. BEGIN
10.  (* instructiuni *)
11.END;

Haideti sa vedem cum ar putea arata un program care calculeaza factorialul unui
numar, folosind o functie de data asta:
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL
1. var i, n, f: integer;
2.  
3.   function Fact: Longint;
4.   var lFact: Longint; {variabila locala}
5.   begin
6.     lFact := 1;
7.  
8.     for i := 1 to n do
9.       lFact := lFact * i;
10. 
11.    Fact := lFact; {am asignat rezultatul in numele functiei !}
12.  end;
13. 
14.begin
15.  Write('Dati N: '); ReadLn(n);
16. 
17.  F := Fact;
18.  Write('Factorial de N este egal cu : ', f);
19. 
20.  ReadLn; {asteptam sa fie apasat Enter}
21.end.

De data asta am asignat variabila F din afara subprogramului, si i-am dat valoarea


rezultata din functie. Rezultatul functiei a fost setat asignand valoarea respectiva
numelui functiei, in interiorul functiei.

Alta modificare este faptul ca folosim o variabila locala pentru a calcula factorialul. Acest
lucru nu este strict necesar, l-am facut doar pentru a exemplifica rolul variabilelor locale.

Parametri

Sa vedem ce sunt parametrii si cum ii folosim in subprograme.

Lista de parametri este scrisa, practic, ca o lista de variabile. Parametrii pot fi scrisi in
orice ordine sau pot fi grupati dupa tipul variabilelor.

Parametrii pot fi de doua tipuri, prin modul in care sunt folositi:


 parametri prin valoare - acesti parametri pot fi modificati in interiorul
subprogramului, dar modificarile nu sunt vizibile in exteriorul subprogramului.
 parametri prin adresa - acesti parametri sunt, de fapt, adresele de memorie ale
unor variabile deja declarate. Modificarile aduse unor astfel de parametri in
interiorul unui subprogram vor fi vizibile in exterior.

Teoria ca teoria, dar hai sa vedem niste exemple 


LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL
1. var i, n, f: integer;
2.  
3.   function Fact(X: Integer): Longint; {X este un parametru transmis prin valoare}
4.   var lFact: Longint; {variabila locala}
5.   begin
6.     lFact := 1;
7.  
8.     for i := 1 to X do
9.       lFact := lFact * i;
10. 
11.    X := -1;
12.    Fact := lFact; {am asignat rezultatul in numele functiei !}
13.  end;
14. 
15.begin
16.  Write('Dati N: '); ReadLn(n);
17. 
18.  F := Fact(N);
19.  WriteLn('Factorial de N este egal cu : ', f);
20.  WriteLn('Noua valoare a lui N este   : ', n);
21. 
22.  ReadLn; {asteptam sa fie apasat Enter}
23.end.

Bun. Am calculat din nou factorialul, dar, de data aceasta, functia noastra Fact a primit
un parametru prin valoare, pe care-l foloseste sa calculeze factorialul. Pe scurt, o data
intrati in corpul functiei (care este apelata ca Fact(N), X este egal cu N. Ce vreau sa
remarcati este faptul ca, desi am dat o noua valoare lui X in interiorul functiei, aceasta
nu este transmisa inapoi lui N, dovada fiind faptul ca noua valoare a lui N (care este
afisata) este aceeasi cu cea introdusa de la tastatura.

Din punctul de vedere al functiei si al metodei de lucru, admitand ca valoarea lui N era
egala cu 5, puteam apela Fact(5). Numele generic al parametrului ("prin valoare") este
dat tocmai din acest motiv: indiferent ca functia este apelata cu o constanta sau o
variabila, doar valoarea ei este transmisa.

Sa vedem acelasi cod, singura diferenta fiind ca acum folosim un parametru prin
adresa.
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL
1. var i, n, f: integer;
2.  
3.   function Fact(var X: Integer): Longint; {X este un parametru transmis prin
adresa}
4.   var lFact: Longint; {variabila locala}
5.   begin
6.     lFact := 1;
7.  
8.     for i := 1 to X do
9.       lFact := lFact * i;
10. 
11.    X := -1;
12.    Fact := lFact; {am asignat rezultatul in numele functiei !}
13.  end;
14. 
15.begin
16.  Write('Dati N: '); ReadLn(n);
17. 
18.  F := Fact(N);
19.  WriteLn('Factorial de N este egal cu : ', f);
20.  WriteLn('Noua valoare a lui N este   : ', n);
21. 
22.  ReadLn; {asteptam sa fie apasat Enter}
23.end.

Faptul ca parametrul este transmis prin adresa este simbolizat de cuvantul var care-l


precede. Programul afiseaza noua valoare a lui N, asa cum era de asteptat, egala cu
-1, dovada ca variabila N a fost modificata in functie.

Diferenta principala intre parametrii transmisi prin valoare si cei transmisi prin adresa
este faptul ca, in cazul celor transmisi prin valoare, variabila trimisa ca parametru
este copiata intr-o zona de memorie temporara si trimisa functiei, ca si copie, in timp
ce in cazul celor transmisi prin adresa variabila trimisa ajunge in functie neschimbata,
ca original. Din acest motiv, transmiterea parametrilor prin adresa poate rapidiza
executia programului (totusi, sa nu va asteptati la minuni - vorbim de milisecunde si
chiar mai putin).

Atentie: Un subprogram poate avea o lista de parametri micsti: o parte dintre ei sa fie
trimisi prin valoare, iar altii prin adresa. Tot ce conteaza este modul de declarare al
listei.
De remarcat ca parametrii listati in headerul subprogramului se numesc parametri
formali (X este un parametru formal in programul de mai sus), care sunt inlocuiti
de parametri efectivi, in momentul apelului subprogramului (N este un parametru
efectiv in programul de mai sus).

Atentie: Numarul, tipul si ordinea parametrilor efectivi trebuie sa corespunda cu


numarul, tipul si ordinea parametrilor formali !

Vizibilitatea variabilelor

Dupa cum am explicat mai sus, se pot declara variabile in interiorul subprogramelor,
chiar si cu nume de variabile care exista deja definite in programul principal. Problema
care se ridica este urmatoarea : de unde stie compilatorul (si implicit, programatorul)
care variabila va fi folosita in anumite zone ale programului ?

Nu trebuie sa va speriati, este foarte simplu si usor de inteles.

Variabilele globale ale programului sunt vizibile oriunde in program. Daca un


subprogram isi defineste o variabila cu acelasi nume, atunci
variabila locala e prioritara in acel subprogram (si in posibilele subprograme ale
subprogramului !).

Sa vedem un exemplu.
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL
1. var i, n, f, lFact: integer;
2.  
3.   function Fact(X: Integer): Longint; {X este un parametru, transmis prin valoare}
4.   var lFact: Longint; {variabila locala}
5.   begin
6.     lFact := 1;
7.     WriteLn('lFact local  = ', lFact);
8.  
9.     for i := 1 to X do
10.      lFact := lFact * i;
11. 
12.    X := -1;
13.    Fact := lFact; {am asignat rezultatul in numele functiei !}
14.  end;
15. 
16.begin
17.  Write('Dati N: '); ReadLn(n);
18. 
19.  lFact := 157;
20.  WriteLn('lFact global = ', lFact);
21. 
22.  F := Fact(N);
23.  WriteLn('Factorial de N este egal cu : ', f);
24. 
25.  ReadLn; {asteptam sa fie apasat Enter}
26.end.
Acest program va afisa urmatoarele linii (pentru N egal cu 5):
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL
1. Dati N: 5
2. lFact global = 157
3. lFact local  = 1
4. Factorial de N este egal cu : 120

Recursivitate

Un lucru important de stiut, legat de subprograme, este ca ele sunt necesare daca


vrem sa folosim recursivitate.

Un subprogram este recursiv daca in implementarea lui se apeleaza pe el insusi.

Recursivitatea poate fi un concept destul de greu de inteles, asa ca vom incepe cu un


exemplu. Sa vedem cum rescriem functia care calculeaza factorialul, folosind
recursivitatea.
LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL
1. function Fact(X: Integer): Longint;
2. begin
3.   if X > 1
4.     then Fact := Fact(X - 1) * X
5.     else Fact := 1
6. end;

Dupa se poate vedea, recursivitatea permite si formularea mai eleganta a solutiei.

Sa incercam sa intelegem ce se intampla. Factorial de N (notat si N!) este definit ca o


inmultire succesiva a numerelor de la 1 la N (1 x 2 x ... x N). Din asta putem vedea ca
N! este egal cu (N-1)! x N. La randul lui, (N-1)! = (N-2)! x (N-1) si asta poate continua,
pana cand N este egal cu 1. Daca incercam sa calculam 1! folosind aceeasi relatie
(adica 1! = 0! x 1) o sa cam dam gres, fiindca 0, inmultit cu orice numar, da 0.

Pe scurt, daca avem un caz initial caruia ii stim rezultatul, iar restul cazurilor se pot
rezolva in functie de cazul initial, problema poate fi rezolvata recursiv. Cazul initial, pe
functia de mai sus, este cazul in care X nu este mai mare decat 1 (adica este mai mic
sau egal !), acest caz avand rezultatul 1. Pentru orice alta valoare pozitiva a lui X,
rezolvarea se face in functie de X-1, pana cand X ajunge in cazul initial.

Ca urmare, aceste doua relatii de mai sus:


 N! = (N-1)! x N
 1! = 1
sunt tot ce ne trebuie pentru a ne defini functia recursiva de calculare a factorialului.

Sa vedem ce se intampla, pas cu pas, pentru N egal cu 3.


LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL
1. Fact(3)
2. X = 3 -> apelam Fact(2) si inmultim cu 3
3. X = 2 -> apelam Fact(1) si inmultim cu 2
4. X = 1 -> 1, se termina functia, revenim in apelul precedent
5. Fact = 1, care inmultit cu 2 este egal cu 2, revenim in apelul precedent
6. Fact = 2, care inmultit cu 3 este egal cu 6, se termina functia si revenim in locul
unde a fost initial apelata functia.

Deci, daca avem o problema care poate fi exprimata prin subprobleme ale ei si putem
gasi o conditie de terminare a apelurilor recursive (in acest caz, X = 1), problema poate
fi rezolvata printr-un subprogram recursiv.

Atentie: Apelurile recursive consuma relativ multa memorie. Daca o problema poate fi
rezolvata iterativ (fara apeluri recursive), e de preferat (in general) ca problema sa fie
rezolvata iterativ. O lista prea lunga de apeluri recursive poate genera "stack overflow"
si bloca programul / calculatorul.

Pentru edificare, atasez acelasi program care calculeaza factorialul, modificat pentru a
afisa ce se intampla. Sper sa va fie de ajutor, impreuna cu explicatiile de mai sus.

Codul sursa al programului:


LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL
1. uses crt;
2.  
3. const lin = 9;
4.       line = '-----------------------------------------------------------------';
5.       Wait = 1000;
6.  
7. var i, n, f, lFact, test: longint;
8.  
9.   function Fact(X: Integer): Longint; {X este un parametru, transmis prin valoare}
10.  begin
11.    if X > 1
12.      then
13.        begin
14.          WriteLn('Fact(', X, ') = Fact(', X - 1 ,') * ', X);
15.          WriteLn(line);
16.          Delay(Wait);
17. 
18.          Fact := Fact(X - 1) * X;
19.          Delay(Wait);
20. 
21.          TextColor(LightGreen);
22.          if Test > 0 then
23.            Test := Test * X;
24.          GotoXY(40, (N - X) * 2 + lin);
25.          Write('Fact(', X,') = ', Test);
26.        end
27.      else
28.        begin
29.          TextColor(LightRed);
30.          WriteLn('X = 1                                  ' +
31.                  'Fact(1) = 1, caz initial !');
32.          TextColor(LightGray);
33.          WriteLn(line);
34.          Delay(Wait);
35.          WriteLn('Functia s-a terminat, revenim din apel ^^^');
36.          Delay(Wait);
37.          Fact := 1;
38.          Test := 1;
39.        end;
40.  end;
41. 
42.begin
43.  test := 0;
44.  repeat {verificam daca 1 <= N <= 6}
45.    ClrScr;
46.    Write('Dati N (maxim 6): '); ReadLn(n);
47.  until (N > 0) and (N < 7);
48.  ClrScr;
49. 
50.  TextColor(LightRed);
51.  GotoXY(Length(line) div 2 - 16 ,2);
52.  WriteLn('Calculul factorialului - recursiv');
53.  WriteLn(line);
54.  WriteLn;
55.  TextColor(LightGray);
56.  WriteLn('Se apeleaza Fact(', N,') ...');
57.  Delay(Wait);
58. 
59.  TextColor(lightGray);
60.  GotoXY(1, lin);
61.  F := Fact(N);
62. 
63.  Delay(Wait);
64.  GotoXY(1, N * 2 + lin + 3);
65.  TextColor(LightGray);
66. 
67.  Write('Fact(', N, ') este egal cu : ');
68.  TextColor(LightGreen);
69.  WriteLn(f);
70.  TextColor(LightGray);
71.  Write('... apasa orice tasta pentru a termina programul ...');
72. 
73.  While Keypressed Do
74.    Readkey; {daca s-a apasat o tasta in timp ce programul rula,
75.              va astepta totusi apasarea urmatoarei taste}
76.  ReadKey;
77.end.
SUBPROGRAME
Un subprogram este un ansamblu ce poate conţine tipuri de date, variabile şi
instrucţiuni destinate unei anumite prelucrări (calcule, citiri, scrieri). Subprogramul
poate
fi executat doar dacă este apelat de către un program sau un alt subprogram.
În limbajul Pascal, subprogramele sunt de 2 tipuri: funcţii şi proceduri. În C/C++,
este utilizată doar noţiunea de funcţie, o procedură din Pascal fiind asimilată în C/C+
+
unei funcţii care returnează void.
O altă clasificare a subprogramelor le împarte pe acestea în următoarele categorii:
 predefinite
 definite de către utilizator.
Dintre subprogramele predefinite, amintim subprogramele:
 matematice: sin, cos, exp, log;
 de citire/scriere: read/write (Pascal), scanf/printf (C/C++)
 de prelucrare a şirurilor de caractere: substr, strlen, strcpy (C/C++).
Exemplu: Conjectura lui Goldbach afirmă că orice număr par > 2 este suma a două
numere prime. Să se scrie un subprogram care verifică acest lucru pentru toate
numerele
pare mai mici decât N dat.
Vom rezolva această problemă cu ajutorul subprogramelor. Astfel, programul va
conţine:
 un subprogram prim care determină dacă un număr furnizat ca parametru este
prim;
 un subprogram verifica prin care se obţine dacă un număr furnizat ca parametru
verifică proprietatea din enunţ;
 programul principal, care apelează subprogramul verifica pentru toate numerele
pare 2 < k< N.
Soluţia în C este următoarea:
#include "stdio.h"
#include "stdlib.h"
bool prim(int n)
{
int i; for (i = 2; i<= n/2; i++)
if(n%i==0) return false;
return true;
}
bool verifica(int n)
{
int i;
for (i = 2; i<= n/2; i++)
if (prim(i) && prim(n – i))
return true;
return false;
}
void main(void)
{
//declarare variabile
int n, k;
//citire valori de intrare
printf(„n=”);
scanf(„%d”, &n);
//prelucrare: verificare daca este indeplinita conditia
//pentru fiecare k par
for(k=4; k<=n; k+=2)
if(!verifica(k))
{
printf("%d nu verifica!\n", k);
//ieşire fara eroare
exit(0);
}
//afisare rezultat
printf("proprietatea este indeplinita pentru numere >2 si
<=%d\n", n);
}
Observaţie: Problema a fost descompusă în altele mai mici. Rezolvarea unei
probleme
complexe este mai uşoară dacă descompunem problema în altele mai simple.
Avantaje ale utilizării subprogramelor:
 reutilizarea codului (un subprogram poate fi utilizat de mai multe subprograme);
 rezolvarea mai simplă a problemei, prin descompunerea ei în probleme mai
simple, care conduc la elaborarea de algoritmi ce reprezintă soluţii ale problemei
iniţiale;
 reducerea numărului de erori care pot apărea la scrierea programelor şi
despistarea cu uşurinţă a acestora.
Elementele unui subprogram sunt prezentate în continuare, cu referire la noţiunea
de
funcţie din C/C++. Pentru funcţiile şi procedurile din Pascal, aceste elemente se pot
distinge în mod similar.  Antetul funcţiei prim este: bool prim(int n)
 Numele funcţiei este prim
 Funcţia prim are un parametru n.
 Funcţia are un tip, care reprezintă tipul de date al rezultatului său. Tipul funcţiei
prim este bool.
În cazul programelor C/C++, dacă tipul funcţiei este void înseamnă că funcţia nu
returnează un rezultat prin nume.
 Funcţia are variabila proprie (locală) i.
 Funcţia întoarce un anumit rezultat (în cazul funcţiei prim, o valoare booleană),
prin intermediul instrucţiunii return.
Parametrii unui subprogram sunt de două tipuri:
 Parametri formali – cei ce se găsesc în antetul subprogramului;
 Parametri actuali (efectivi) – cei care se utilizează la apel.
De exemplu, în linia:
if(!verifica(k))
parametrul k este un parametru efectiv.
Declararea variabilelor
 Sistemul de operare alocă fiecărui program trei zone distincte în memoria internă
în care se găsesc memorate variabilele programului:
o Segment de date
o Segment de stivă
o Heap.
Există şi posibilitatea ca variabilele să fie memorate într-un anumit registru al
microprocesorului, caz în care accesul la acestea este foarte rapid.
 O variabilă se caracterizează prin 4 atribute:
o Clasa de memorare – locul unde este memorată variabila respectivă; o
variabilă poate fi memorată în:
 segmentul de date (variabilele globale)
 segmentul de stivă (în mod implicit, variabilele locale)
 heap
 un registru al microprocesorului (în mod explicit, variabilele
locale).
o Vizibilitatea – precizează liniile textului sursă din care variabila respectivă
poate fi accesată. Există următoarele tipuri de vizibilitate:
 la nivel de bloc (instrucţiune compusă) (variabilele locale);
 la nivel de fişier (în cazul în care programul ocupă un singur fişier
sursă) (variabilele globale, dacă sunt declarate înaintea tuturor
funcţiilor);
 la nivel de clasă (în legătură cu programarea orientată pe obiecte).
o Durata de viaţă – timpul în care variabila respectivă are alocat spaţiu în
memoria internă. Avem:
 durată statică – variabila are alocat spaţiu în tot timpul execuţiei
programului (variabilele globale);  durată locală – variabila are alocat spaţiu în
timpul în care se
execută instrucţiunile blocului respectiv (variabilele locale);
 durată dinamică – alocarea şi dezalocarea spaţiului necesar
variabilei respective se face de către programator prin operatori şi
funcţii speciale.
o Tipul variabilei.
 În C++ variabilele pot fi împărţite în 3 mari categorii: locale, globale şi dinamice.
Transmiterea parametrilor
Parametrii actuali trebuie să corespundă celor formali, ca număr şi tip de date.
Tipul parametrilor actuali trebuie fie să coincidă cu tipul parametrilor formali, fie să
poată fi convertit implicit la tipul parametrilor formali.
 Pentru memorarea parametrilor, subprogramele folosesc segmentul de stivă, la fel
ca pentru variabilele locale.
 Memorarea se face în ordinea în care parametrii apar în antet.
 În cadrul subprogramului, parametrii transmişi şi memoraţi în stivă sunt variabile.
Numele lor este cel din lista parametrilor formali.
 Variabilele obţinute în urma memorării parametrilor transmişi sunt variabile
locale.
 La revenirea în blocul apelant, conţinutul variabilelor memorate în stivă se pierde.
Transmiterea parametrilor se poate realiza prin intermediul a două mecanisme:
 prin valoare
 prin referinţă.
Transmiterea prin valoare este utilizată atunci când dorim ca subprogramul să
lucreze cu
acea valoare, dar, în prelucrare, nu ne interesează ca parametrul actual (din blocul
apelant) să reţină valoarea modificată în subprogram.
În toate apelurile din exemplul precedent, transmiterea parametrilor se realizează
prin valoare.
Observaţie: Dacă nu ar exista decât acest tip de transmitere, ar fi totuşi posibil să
modificăm valoarea anumitor variabile care sunt declarate în blocul apelant. Acest
lucru
se realizează în situaţia în care am lucra cu variabile de tip pointer.
Exemplu: Să se scrie o funcţie care interschimbă valorile a două variabile.
Transmiterea
parametrilor se va face prin valoare.
#include <iostream.h>
void interschimba(int *a, int *b)
{
int aux = *a;
*a = *b;
*b = aux;
}
main() {
int x = 2, y = 3;
interschimba(&x, &y);
cout<< x << " " << y;
}
Observaţie: În limbajul C, acesta este singurul mijloc de transmitere a parametrilor.
Transmiterea prin valoare a tablourilor permite ca funcţiile să returneze noile
valori ale acestora (care au fost modificate în funcţii). Explicaţia este dată de faptul

numele tabloului este un pointer către componentele sale. Acest nume se transmite
prin
valoare, iar cu ajutorul său accesăm componentele tabloului.
Exemplu: Să se scrie o funcţie care iniţializează un vector transmis ca parametru.
#include <iostream.h>
void vector (int x[10])
{
for (int i = 0; i < 10; i++)
x[i] = i;
}
main()
{
int a[10];
vector(a);
for (int i=0; i < 10; i++)
cout << a[i] << " ";
}
Transmiterea prin referinţă este utilizată atunci când dorim ca la revenirea din
subprogram variabila transmisă să reţină valoarea stabilită în timpul execuţiei
programului.
În acest caz, parametrii actuali trebuie să fie referinţe la variabile. La transmitere,
subprogramul reţine în stivă adresa variabilei.
La compilare, orice referinţa la o variabilă este tradusă în subprogram ca adresare
indirectă. Acesta este motivul pentru care în subprogram putem adresa variabila
normal
(nu indirect), cu toate că, pentru o variabilă transmisă, se reţine adresa ei.
Exemplu: Să se scrie o funcţie care interschimbă valorile a două variabile.
Transmiterea
parametrilor se va face prin referinţă.
#include <iostream.h>
void interschimba(int &a, int &b)
{
int aux = a; a = b;
b = aux;
}
main()
{
int x = 2, y = 3;
interschimba(x, y);
cout<< x << " " << y;
}
Acest program, scris în limbajul Pascal, are următoarea formă:
program transm_referinta;
var x, y: integer;
procedure interschimba(var a,b: integer);
var aux: integer;
begin
aux := a;
a := b;
b := aux;
end;
procedure nu_interschimba(a,b: integer);
var aux: integer;
begin
aux := a;
a := b;
b := aux;
end;
begin
x := 31;
y := 21;
interschimba(x, y);
writeln(x, ' ', y);
writeln('---------');
nu_interschimba(x, y);
writeln(x, ' ', y);
end. Supraîncărcarea funcţiilor
În C++ există posibilitatea ca mai multe funcţii să poarte acelaşi nume. În această
situaţie, funcţiile trebuie să fie diferite fie ca număr de parametri, fie ca tip. În acest
din
urmă caz, este necesară o condiţie suplimentară: parametrii efectivi să nu poată fi
convertiţi implicit către cei formali.
Exemplu: Să se scrie o funcţie supraîncărcată care afişează aria pătratului, respectiv
a
dreptunghiului, în funcţie de numărul de parametri.
#include <iostream.h>
void arie(double latura)
{
cout << "aria patratului este "<< latura * latura;
}
void arie(double lung, double lat)
{
cout << "aria dreptunghiului este "<< lung * lat;
}
main()
{
arie(3);
arie (4, 7);
double d = 7;
arie(&d);
}
Exerciţii:
1) Se da un sir de numere intregi. Se cauta un subsir cu lungimea cuprinsa intre l si
u, format din elemente consecutive ale sirului initial, cu suma elementelor
maxima.
2) Se considera un numar natural n.Determinati cel mai mic numar m care se poate
obtine din n, prin eliminarea unui numar de k cifre din acesta fara a modifica
ordinea cifrelor ramase.
3) Se citesc de la tastatura un numar natural n si un sir de numere naturale. Sa se
scrie un program care afiseaza indicii i si j care indeplinesc urmatoarele conditii:
) .max
;11,,,)
1) ;
esteijdiferentac ima
jkikaaaab
njia
kjki


 Probleme propuse:
1) Se considera N numere intregi care trebuie repartizate in p grupuri. Grupurile sunt
identificate prin numere naturale cuprinse intre 1 si p. Repartizarea in grupuri
trebuie sa se realizeze astfel incat suma numerelor din oricare grup i sa fie
divizibila cu numarul total de numere care fac parte din grupurile identificate prin
valori cuprinse intre i si p.
2) Consideram ca toate punctele de coordonate intregi din plan (coordonate mai mici
de 1000) sunt colorate in negru, cu exceptia a n puncte care sunt colorate in rosu.
Doua puncte rosii aflate pe aceeasi linie verticala (au aceeasi ordonata sau aceeasi
abscisa) pot fi unite printr-un segment. Coloram in rosu toate punctele de
coordonate intregi de pe acest segment. Repetam operatia cat timp se obtin puncte
rosii noi. Cunoscand coordonatele celor n puncte care erau initial rosii, aflati
numarul maxim de puncte rosii care vor exista in final.
3) Se considera o matrice binara de dimensiune m x n (elementele matricei sunt 0
sau
1). Se cere sa se determine aria maxima care poate fi acoperita de doua
dreptunghiuri care contin numai elemente cu valoare 0 (dreptunghiurile nu se pot
suprapune).
in.txt out.txt
6 8 23
10000000
10000000
11100011
00100011
00100011
00111111

Lucrarea 10 Utilizarea şi programarea calculatoarelor I


1
Lucrarea10
PROCEDURI ȘI FUNCȚII ÎN LIMBAJUL PASCAL
10.1. Scopul lucrării
Asimilarea de către studenți a lucrului cu subprograme (nume generic pentru
proceduri și
funcții).
10.2. Considerații teoretice
10.2.1. Noțiuni generale
În programele de mari dimensiuni, datele pot suferi prelucrări repetate conform
aceluiași tip
de algoritm. De exemplu într-un program de statistică matematica este necesară
calcularea
frecvenței a valorii medii a unor șiruri diferite de date. În această situație, este utilă
folosirea unei
secvențe unice de program care să calculeze media șirului de date și ea să fie rulată
ori de câte ori
este nevoie, dar cu alte date concrete. În acest mod se conturează ideea folosirii
subprogramelor -
acele porțiuni unice de program, la care se face apel, din interiorul unui program
principal, ori de
câte ori este nevoie.
În concluzie, realizarea programelor complexe impune organizarea sub forma de
proceduri
și funcții - numite generic subprograme - a acțiunilor care concură la realizarea unui
scop parțial
comun. Subprogramele sunt miniprograme de sine stătătoare, constituite ca orice
program mare din:
- instrucțiuni,
- date locale
- subprograme incluse (încuibate=nested).
Deci subprogramele pot fi privite ca module aparținând programului principal. Datele
locale
ale unui subprogram există doar atât timp cât subprogramul care le conține este în
curs de execuție.
Datele inițiale ale subprogramului îi sunt transmise de la programul apelând (în
general programul
principal) odată cu apelul lui, folosindu-se în acest scop o listă de parametri de apel.
În Pascal se face distincție între noțiunea de funcție - care furnizează un singur
rezultat
atribuit numelui de funcție și procedură - care oferă rezultatele doar cu ajutorul
parametrilor. Prin
urmare funcția poate fi privită ca un caz special de variabilă, care oferă valoarea
asociată, nu direct
ca o variabilă, ci indirect, prin rularea instrucțiunilor care o compun. Există limbaje,
care nu fac
distincție între funcție și procedură, un exemplu în acest sens fiind limbajul C.
Subprogramele sunt părți de program care se identifică printr-un nume cu care pot fi
apelate
(activate). La rândul său un subprogram poate apela un alt subprogram sau mai
multe. Procedurile
pot fi apelate prin instrucțiunea de apel procedură. Funcțiile pot fi apelate în cadrul
unei expresii
prin numele lor. Lucrarea 10 Utilizarea şi programarea calculatoarelor I
2
În general avem următoarele situații:
a) Program Principal b) Apelul unui subprogram SP c) Apelul cascadat al unor
fără apelarea din puncte diferite ale PP subprograme (SP1, SP2)
subprogramelor
unde: PP - program principal
SP - subprogram
10.2.2. Declararea procedurilor și funcțiilor
Sintaxa declarației de procedură este următoarea: antet_de_procedură;
corp_de_procedură;
unde antetul de procedură este:
PROCEDURE nume_procedura [lista_parametrilor_formali]
iar corpul de procedură este:
[interrupt;|near;|far;](bloc|forward|external; directiva_inline|directiva_ansamblor)
Sintaxa declarației de funcție este următoarea:
FUNCTION nume_funcție[lista_parametrilor_formali] : tip_rezultat
iar corpul este:
[near; | far;](bloc | forward; | external; directiva_inline | directiva_ansamblor)
10.2.3. Sintaxa parametrilor formali
Declararea unei proceduri sau funcții specifică o listă de parametrii formali. Fiecare
parametru declarat în lista parametrilor formali este local procedurii sau funcției și
poate fi referit în
blocul asociat procedurii sau funcției prin identificatorul său.
Lista parametrilor formali se definește prin:
(secțiune_parametrilor_formali { ; secțiunea_parametrilor_formali } ) Lucrarea 10
Utilizarea şi programarea calculatoarelor I
3
unde: secțiunea parametrilor formali este:
specificare_parametru_valoare
specificare_parametru_variabil
specificare_parametru_constant
specificare_parametru_procedura
specificare_parametru_funcție
Prin specificare_parametru_valoare se înțelege: lista_de_identificatori : nume_tip
Prin specificare_parametru_variabil se înțelege: var lista_de_identificatori [ :
nume_tip ]
O specificare_parametru_constant este : const lista_de_identificatori [ : nume_tip ]
O specificare_parametru_procedura este : lista_de_identificatori :
nume_tip_procedura
iar o specificare_parametru_funcție are forma : lista_de_identificatori :
nume_tip_funcție.
Tipurile folosite în lista parametrilor formali trebuie să fie nume de tipuri definite în
programul (blocul) apelat sau trebuie să fie tipuri predefinite în limbaj.
10.2.4. Noțiunea de bloc (corpul) a unui subprogram
Corpul unui subprogram (procedura sau funcție) este un bloc sau o directivă. Un
bloc este
constituit din :
- declarații de etichete (label);
- definiții de constante (const);
- definiții de tip (type);
- declarații de variabile (var);
- declarații de proceduri (procedure);
- declarații de funcții (function)
- șir de instrucțiuni (partea executabilă a blocului).
Deoarece subprogramele sunt incluse în blocul programului principal, iar blocurile
subprogramelor pot conține la rândul lor alte subprograme, rezultă ca blocurile pot fi
îmbrăcate
(suprapuse). Blocul unei funcții trebuie să conțină cel puțin o instrucțiune de atribuire
care atașează
numelui funcției o valoare. Rezultatul funcției va fi ultima valoare astfel atribuită.
Dacă nu există
sau dacă nu a fost executată o astfel de instrucțiune de atribuire, atunci valoarea
returnată de funcție
este nedeterminată.
10.2.5. Apelarea (activarea) procedurilor și funcțiilor
Procedurile și funcțiile pot fi apelate prin invocarea numelui lor. Numele funcției se
introduce în expresia în care se folosește valoarea returnată de funcție. În ambele
cazuri, numele
trebui să fie urmat de lista parametrilor actuali. Desigur, orice diferență (număr de
parametri, tipul
lor) dintre lista parametrilor formali declarată în antetul subrutinei și lista parametrilor
actuali
folosită pentru apel, constituie o eroare gravă care este semnalată în faza de
compilare a
programului.
Parametrii actuali pot fi: - variabile;
- expresii;
- proceduri;
- funcții. Lucrarea 10 Utilizarea şi programarea calculatoarelor I
4
Înainte de apelul subprogramului, valorile parametrilor actuali sunt salvate pe stiva
de unde
sunt preluați de subprogram. Acest mecanism de substituire a parametrilor formali
prin parametrii
actuali se numește transmisia parametrilor către subprogram. În Pascal există două
mecanisme de
bază pentru transmisia parametrilor: - prin valoare
- prin adresa.
Transmisia prin valoare se realizează ca și cum la intrarea în procedura sau funcția
apelată
s-ar găsi o declarație a parametrului formal cu tipul corespunzător și o instrucțiune
de atribuire de
forma:
parametru formal := parametru actual;
Transmisia prin adresă se folosește atunci când valoarea unei variabile trebuie
redată
apelantului (adică un rezultat obținut în subprogramul apelat trebuie returnat
subprogramului
apelant). Aceasta metodă de transmisie este semnalata prin prezența cuvântului
cheie "var" plasat în
fața numelui parametrului formal, care se referă la parametrul formal, care are și
atributul de tip.
La orice apel de subprogram transmisia parametrilor se realizează utilizând zona
stiva a
memoriei. În stiva sunt depuse următoarele:
- adresa de return (adică adresa instrucțiunii ce urmează instrucțiunii de apel de
subprogram);
- valorilor parametrilor transmiși prin valoare (se face o operație de copiere în stiva a
valorilor transmise);
- adresele parametrilor variabili.
La terminarea subprogramului, valorile din stiva se pierd, motiv pentru care
parametrii
transmiși prin valoare nu se pot returna în programul apelant. Pentru parametrii
transmiși prin
adrese, se pierd adresele lor de pe stivă, dar valorile din locațiile de memorie
corespunzătoare se
păstrează ! Corespondența între un parametru actual și un parametru formal se face
prin poziția
ocupată de aceștia în cele două liste. Erorile nu sunt posibile, deoarece
neconcordanțele sunt
semnalate încă din faza de compilare. Folosirea numelui procedurii (funcției) în
cadrul corpului
procedurii (funcției) apelante se numește apel recursiv de procedură (funcție), lucru
permis în
limbajul Turbo Pascal. Se menționează totuși că folosirea tehnicilor recursive nu
constituie
întodeauna soluțiile optime, deoarece este nevoie de un spațiu mare de memorie în
stivă.
10.2.6. Subprograme Near și Far
Antetul de procedură și funcție poate fi urmat de cuvântul Near sau Far, pentru a
forța
generarea apelurilor în modelul de apel
- "apropiat" (Near)
- "îndepărtat" (Far).
În modelul de apel "apropiat" se poate executa un salt la o alta locație în interiorul
aceluiași
segment de cod. Adresele locațiilor la care se face saltul se face pe 2 octeți (numai
deplasamentul).
Procedurile și funcțiile declarate într-un program sau în secțiunea de implementare a
unui unit
folosesc implicit modelul apropiat. În modelul de apel "depărtat" se poate transfera
controlul într-un
alt segment de cod. Adresele la care se face saltul sunt generate pe 4 octeți
(segment+ deplasament).
Procedurile și funcțiile declarate în secțiunea de interfață a unui unit folosesc implicit
modelul
depărtat, deci ele pot fi apelate din alte unit - uri (segmente de cod).
10.2.7. Proceduri de întrerupere (Interrupt)
Limbajul Turbo Pascal permite elaborarea procedurilor de întrerupere. Cuvântul
cheie
Interrupt plasat după antetul de bloc semnalizează compilatorului o astfel de
procedură. Lucrarea 10 Utilizarea şi programarea calculatoarelor I
5
Antetul procedurilor de întrerupere trebuie să aibă următorul format:
procedure nume (Flags, CS, IP, AX, BX, CX, DX, SI,DI, DS, ES, BP : word) ;
Interrupt;
adică parametrii formali sunt regisării de procesor.
Se menționează că după antet poate să urmeze fie un bloc, fie una din dintre
directivele
Forwoard, External sau Online.
10.2.8. Directivele subprogramelor
1) Directiva Forward, așezată imediat după antet, înlocuiește blocul (corpul)
programului și
permite apariția blocului undeva mai jos în program, unde va fi precedat numai de
numele
subprogramului. Deci cu ajutorul acestei directive se pot separa fizic cele două
componente de bază
ale declarației unui subprogram (procedură sau funcție) : antetul subprogramului de
blocul
subprogramului.
2) Directiva Inline permite scrierea diferitelor instrucțiuni direct în cod mașină în locul
blocului
procedurii respective.
10.2.9. Declarații externe
Declarațiile externe asigură o interfață cu procedurile și funcțiile scrise în limbaj de
asamblare și care au fost compilate separat cu Turbo Assembler. Extensia implicită
a fișierelor
compilate este *.ASM. Codul extern trebuie legat cu programul sau unit-ul Pascal cu
directiva { $L
nume_fișier }. Antetul de procedurilor și funcțiilor care au fost scrise în limbaj de
asamblare este
urmat de cuvântul cheie External, iar blocul corespunzător este înlocuit cu directiva
$L, unde
nume_fișier specifică unitatea, calea, numele fișierului și extensia codului obiect
compilat separat.
10.3. Mersul lucrării
1.Se copiază folderul L10 de pe drive Z:\UPC\Sem1 pe D:\Home\
2.Se vizualizează și se studiază conținutul lucrării de laborator din fișierul: Lucrarea
Nr. 10.pdf.
Se întocmește referatul
3.Se incarca programul Luc10P.pas respectiv Luc10F.pas și se urmăresc
elementele sale
componente iar prin rulare modul de funcționare, făcându-se aprecierile necesare.
4.Fiecare student va realiza câte un program simplu din lista de aplicații -
TEME10.PDF, intitulat
Tema10_numestud.pas asemănător cu cel prezentat. Se compilează și rulează
acest program
corectându-se eventualele erori.
5. Se trimite acest program prin mail cadrului didactic.
6. Se șterge folderul L10 din D:\Home.

Recursivitate
Un lucru important de stiut, legat de subprograme, este ca ele sunt necesare daca vrem sa
folosimrecursivitate.

Un subprogram este recursiv daca in implementarea lui se apeleaza pe el insusi.

Recursivitatea poate fi un concept destul de greu de inteles, asa ca vom incepe cu un exemplu. Sa
vedem cum rescriem functia care calculeaza factorialul, folosind recursivitatea.

1. function Fact(X: Integer): Longint;
2. begin
3.   if X > 1
4.     then Fact := Fact(X - 1) * X
5.     else Fact := 1
6. end;

Dupa se poate vedea, recursivitatea permite si formularea mai eleganta a solutiei.

Sa incercam sa intelegem ce se intampla. Factorial de N (notat si N!) este definit ca o inmultire


succesiva a numerelor de la 1 la N (1 x 2 x ... x N). Din asta putem vedea ca N! este egal cu (N-1)!
x N. La randul lui, (N-1)! = (N-2)! x (N-1) si asta poate continua, pana cand N este egal cu 1.
Daca incercam sa calculam 1! folosind aceeasi relatie (adica 1! = 0! x 1) o sa cam dam gres,
fiindca 0, inmultit cu orice numar, da 0.

Pe scurt, daca avem un caz initial caruia ii stim rezultatul, iar restul cazurilor se pot rezolva in
functie de cazul initial, problema poate fi rezolvata recursiv. Cazul initial, pe functia de mai sus,
este cazul in care X nu este mai mare decat 1 (adica este mai mic sau egal !), acest caz avand
rezultatul 1. Pentru orice alta valoare pozitiva a lui X, rezolvarea se face in functie de X-1, pana
cand X ajunge in cazul initial.

Ca urmare, aceste doua relatii de mai sus:

 N! = (N-1)! x N
 1! = 1

sunt tot ce ne trebuie pentru a ne defini functia recursiva de calculare a factorialului.

Sa vedem ce se intampla, pas cu pas, pentru N egal cu 3.

1. Fact(3)
2. X = 3 -> apelam Fact(2) si inmultim cu 3
3. X = 2 -> apelam Fact(1) si inmultim cu 2
4. X = 1 -> 1, se termina functia, revenim in apelul precedent
5. Fact = 1, care inmultit cu 2 este egal cu 2, revenim in
apelul precedent
6. Fact = 2, care inmultit cu 3 este egal cu 6, se termina
functia si revenim in locul unde a fost initial apelata
functia.

 Deci, daca avem o problema care poate fi exprimata prin subprobleme ale ei si putem gasi o
conditie de terminare a apelurilor recursive (in acest caz, X = 1), problema poate fi rezolvata
printr-un subprogram recursiv.

Atentie: Apelurile recursive consuma relativ multa memorie. Daca o problema poate fi rezolvata
iterativ (fara apeluri recursive), e de preferat (in general) ca problema sa fie rezolvata iterativ. O
lista prea lunga de apeluri recursive poate genera "stack overflow" si bloca programul /
calculatorul.

Pentru edificare, atasez acelasi program care calculeaza factorialul, modificat pentru a afisa ce se
intampla. Sper sa va fie de ajutor, impreuna cu explicatiile de mai sus.
Codul sursa al programului:

1. uses crt;
2.  
3. const lin = 9;
4.       line
= '---------------------------------------------------------
--------';
5.       Wait = 1000;
6.  
7. var i, n, f, lFact, test: longint;
8.  
9.   function Fact(X: Integer): Longint; {X este un parametru,
transmis prin valoare}
10.   begin
11.     if X > 1
12.       then
13.         begin
14.           WriteLn('Fact(', X, ') = Fact(', X - 1 ,') *
', X);
15.           WriteLn(line);
16.           Delay(Wait);
17.  
18.           Fact := Fact(X - 1) * X;
19.           Delay(Wait);
20.  
21.           TextColor(LightGreen);
22.           if Test > 0 then
23.             Test := Test * X;
24.           GotoXY(40, (N - X) * 2 + lin);
25.           Write('Fact(', X,') = ', Test);
26.         end
27.       else
28.         begin
29.           TextColor(LightRed);
30.           WriteLn('X = 1                                
' +
31.                   'Fact(1) = 1, caz initial !');
32.           TextColor(LightGray);
33.           WriteLn(line);
34.           Delay(Wait);
35.           WriteLn('Functia s-a terminat, revenim din
apel ^^^');
36.           Delay(Wait);
37.           Fact := 1;
38.           Test := 1;
39.         end;
40.   end;
41.  
42. begin
43.   test := 0;
44.   repeat {verificam daca 1 <= N <= 6}
45.     ClrScr;
46.     Write('Dati N (maxim 6): '); ReadLn(n);
47.   until (N > 0) and (N < 7);
48.   ClrScr;
49.  
50.   TextColor(LightRed);
51.   GotoXY(Length(line) div 2 - 16 ,2);
52.   WriteLn('Calculul factorialului - recursiv');
53.   WriteLn(line);
54.   WriteLn;
55.   TextColor(LightGray);
56.   WriteLn('Se apeleaza Fact(', N,') ...');
57.   Delay(Wait);
58.  
59.   TextColor(lightGray);
60.   GotoXY(1, lin);
61.   F := Fact(N);
62.  
63.   Delay(Wait);
64.   GotoXY(1, N * 2 + lin + 3);
65.   TextColor(LightGray);
66.  
67.   Write('Fact(', N, ') este egal cu : ');
68.   TextColor(LightGreen);
69.   WriteLn(f);
70.   TextColor(LightGray);
71.   Write('... apasa orice tasta pentru a termina
programul ...');
72.  
73.   While Keypressed Do
74.     Readkey; {daca s-a apasat o tasta in timp ce
programul rula,
75.               va astepta totusi apasarea urmatoarei
taste}
76.   ReadKey;
77. end.

Dupa cum am explicat mai sus, se pot declara variabile in interiorul subprogramelor, chiar si cu
nume de variabile care exista deja definite in programul principal. Problema care se ridica este
urmatoarea : de unde stie compilatorul (si implicit, programatorul) care variabila va fi folosita in
anumite zone ale programului ?

Nu trebuie sa va speriati, este foarte simplu si usor de inteles.

Variabilele globale ale programului sunt vizibile oriunde in program. Daca un subprogram isi
defineste o variabila cu acelasi nume, atunci variabila locala e prioritara in acel subprogram (si
in posibilele subprograme ale subprogramului !).

1. var i, n, f, lFact: integer;
2.  
3.   function Fact(X: Integer): Longint; {X este un parametru, transmis
prin valoare}
4.   var lFact: Longint; {variabila locala}
5.   begin
6.     lFact := 1;
7.     WriteLn('lFact local  = ', lFact);
8.  
9.     for i := 1 to X do
10.       lFact := lFact * i;
11.  
12.     X := -1;
13.     Fact := lFact; {am asignat rezultatul in numele functiei !}
14.   end;
15.  
16. begin
17.   Write('Dati N: '); ReadLn(n);
18.  
19.   lFact := 157;
20.   WriteLn('lFact global = ', lFact);
21.  
22.   F := Fact(N);
23.   WriteLn('Factorial de N este egal cu : ', f);
24.  
25.   ReadLn; {asteptam sa fie apasat Enter}
26. end.

Acest program va afisa urmatoarele linii (pentru N egal cu 5):

1. Dati N: 5
2. lFact global = 157
3. lFact local  = 1
4. Factorial de N este egal cu : 120

65
8. Subprograme Pascal :
Procedure, Function , parametri, vizibilitate.
8.1. Subprograme Pascal : Procedure, Function.
În limbajul Pascal exist• dou• tipuri de subprograme: func•ii •i proceduri.
Definirea acestor subprograme în cadrul unui program Pascal se face în
partea de declara•ii, astfel :
<Def_subprogram> ::= <Def_func•ie> | <Def_procedur•>
unde :
<Def_func•ie> ::= <Antet_func•ie> ; <Bloc>
<Def_procedur•> ::= <Antet_procedur•> ; <Bloc>
iar
<Antet_func•ie> ::= FUNCTION <Nume> [ (L_p_f) ] : <Tip_f>
<Antet_procedur•> ::= PROCEDURE<Nume> [ (L_p_f) ]
<Nume> este un identificator care reprezint• numele subprogramului definit, iar
lista parametrilor formali <L_p_f> este optional• •i ea precizeaz• variabilele de
care depinde subprogramul •i tipul acestor variabile;
<Tip_f> reprezint• codomeniul func•iei •i poate fi un tip simplu (Real, Integer,
Byte, Boolean, Char, String, etc). Este obligatoriu ca în corpul func•iei s• existe
cel pu•in o instruc•iune (de atribuire) prin care func•iei s• i se atribuie o valoare
(<Nume>:= . . . ) .
Apelarea unei func•ii se face scriind într-o expresie numele func•iei urmat
de lista parametrilor actuali, iar apelarea unei proceduri se face scriind numele
procedurii urmat de lista parametrilor actuali pe locul unei instruc•iuni, ceea ce
echivaleaz• cu execu•ia tuturor instruc•iunilor din bloc, astfel
<Apel-procedura> ::= <Nume> [ (<Lista-p.a.> ]
Dac• apelul unei func•ii apare în cadrul unei expresii într-o anumit•
instruc•iune, apelul unei proceduri constituie o instruc•iune de sine st•t•toare.66
8.2. Parametri.
Un subrogram este apelat pentru a rezolva o anumit• subproblem•. În
acest scop îi vom furniza ni•te date de intrare •i el ne va da ca rezultate ni•te date
de ie•ire prin care se realizeaz• comunicarea între modulul apelant (parametri
actuali) •i subprogram (parametri formali).
Parametrii actuali de intrare sunt expresii (cu a c•ror valori lucreaz•
subprogramul) pe când cei de ie•ire vor fi variabile (unde se vor depune
rezultatele).
Parametrii formali reprezint• datele de intrare (c•rora le corespunde
valorile expresiilor date prin parametrii actuali, deci vor fi de tip valoare) •i de
ie•ire (c•rora le corespunde adresele variabilelor corespunz•toare parametrilor
actuali, deci vor fi de tip variabil•) ale subprogramului.
Lista parametrilor formali este format• din mai multe sec•iuni de
parametri separate între ele de caracterul ';' . Sintaxa acestei liste este:
<L_p_f.> ::= <spf> { ; <spf> }
unde prin <spf> s-a notat o sec•iune de parametri formali care are sintaxa
<spf> ::= <sp_val> | <sp_var> | <p_functie> | <p_procedura>
Sec•iunea de parametri valoare <sp_val> are sintaxa
<sp_val> ::= <lista_id> : <id_tip>, iar
sec•iunea de parametri variabil• <sp_var> are sintaxa
<sp_var> ::=VAR <lista_id> : <id_tip>
unde <id_tip> este un identificator de tip, definit anterior, deci asem•n•toare
sec•iunii parametrilor valoare, singura diferen•• fiind prezen•a cuvântului VAR în
fa•a listei.
Trebuie s• existe o coresponden•• biunivoc• (ca num•r, pozi•ie, tip,
semnifica•ie, etc.) între parametrii actuali •i cei formali.
Date de intrare Date de iesire Subprogram67
8.3. Vizibilitate.
În defini•ia unui subprogram apare la început un antet, dup• care urmeaz•
un bloc, care con•ine o list• de declara•ii. Elementele definite în lista de
declara•ii sunt locale pentru blocul în care sunt definite. Acesta constituie
domeniul de vizibilitate al acestor elemente; ele pot fi folosite numai în interiorul
subprogramului în care au fost declarate, nu •i în afara acestuia.
Fie S un subprogram al programului P (vezi figura de mai jos). Pe lâng•
variabilele locale ale subprogramului S , toate elementele declarate în lista de
declara•ii ale programului P sunt considerate globale pentru subprogramul S •i
pot fi folosite în acest subprogram. Deci elementele declarate în S pot fi folosite
numai în S, nu •i în restul programului P. Ele sunt locale pentru S, dar sunt
globale •i pot fi folosite în subprogramele S1 •i S2 incluse în S. Elementele
definite în P sunt globale •i pot fi folosite în S, S1 •i S2.
Considerând programul principal
ca un bloc de nivel 0, vom considera
subprogramele definite în el ca blocuri
de nivel 1. În general, un bloc definit
întrun bloc de nivel i are nivelul i+1.
Dac• într-un bloc de nivel i se folose•te o variabil• v, •i acela•i
identificator v noteaz• o variabil• într-un bloc de nivel i+1, atunci cele dou•
variabile se consider• distincte de•i au acela•i nume. În acest caz variabila din
blocul interior este cea considerat• existent• în acest bloc, iar cea exterioar• nu
exist• decât în partea blocului de nivel i exterioar• blocului de nivel i+1.
În exemplul urm•tor se realizeaz• reuniunile (A∪B, A∪C •i B∪C) a trei
mul•imi date de la tastatur• (A, B •i C) pe o linie, fiecare mul•ime fiind introdus•
element cu element, acestea fiind separate cu spa•iu sau virgul• ( de exemplu :
100,200,404,6789 ). Mul•imile fiind memorate sub form• de •iruri, se va memora
cardinalul mul•imii pe pozi•ia 0, iar elementele pe pozi•iile 1,2,3,... .
P
n0 (nivelul 0)
S
n1
S1
n2
S2
n2
S2a
n3
S2b
n2368
Pentru c• o mul•ime (de tip •ir) apare ca parametru formal, va trebui s•
declar•m acest tip ( Type Multime = . . . ).
Procedura Cite•te nu are decât un parametru de ie•ire (mul•imea A care se
cite•te), declarat ca parametru de tip variabil• :
Procedura Tip•re•te are un singur parametru de intrare (mul•imea A care
se tip•re•te), declarat ca parametru de tip valoare :
Procedura Reuniune calculeaz• reuninunea a dou• mul•imi. Are doi
parametri de intrare (A •i B) tip valoare •i un parametru de ie•ire (C) de tip
variabil•:
Reuniunea mul•imilor A •i B se calculeaz• astfel :
• se ini•ializeaz• mul•imea C cu A (C:=A) ;
• se adaug• mul•imii C elementele b∈B care nu apar•in mul•imii A (C:=C ∪
B\A).
Func•ia Apart (b,A) determin• dac• b∈A sau nu (returneaz• valoarea
True respectiv False), prin compararea succesiv• a lui b cu elementele mul•imii
A pân• când g•se•te o valoare egal• cu b sau termin• toate posibilit••ile.
Program AuB_AuC_BuC;
Type Multime = Array[0..100] Of Integer;
Var A, B, C, AuB, AuC, BuC : Multime;
Procedure Citeste (Var A:Multime); { Citeste o multime de la tastatura }
Tip•re•te A
Cite•te A
Reuniune
A
B
C69
Var c,p,n : Integer; s : String;70
Begin
Write (’ Dati elementele multimii : ’); Readln (s); n:=0;
While s<>’’ Do Begin
n:=n+1; Val(s,A[n],p);
If p>0 Then Val(Copy(s,1,p-1),A[n],c) Else p:=Length(s);
Delete (s,1,p)
End;
A[0]:=n; { n=Card(A)→ A[0] }
End;
Function Apart (b:Integer; A:Multime) : Boolean; {Apartine b multimii A?}
Var i,n : Integer;
Begin i:=1; n:=A[0];
While (i<=n) And (b<>A[i]) Do i:=i+1;
Apart := i<=n {Apartine, daca i<=n }
End;
Procedure Reuniune (A,B:Multime; Var C:Multime); { C := A ∪ B }
Var i,p,q,r : Integer;
Begin C:=A; p:=A[0]; q:=B[0]; r:=C[0];
For i:=1 To q Do
If Not Apart(B[i],A) Then Begin
r:=r+1; C[r]:=B[i] End C[0]:=r
End;
Procedure Tipareste (A:Multime); { Tipareste pe ecran o multime A }
Var n,i : Integer;
Begin
n:=A[0]; Write (’ {’);
For i:=1 To n Do Write (A[i],’,’);
Writeln (Chr(8),’}’) { Rescrie peste ultima virgula, acolada }
End;
Begin { Modulul principal }
Citeste (A); Citeste (B); Citeste (C);
Reuniune(A,B,AuB); Tipareste (AuB);
Reuniune(A,C,AuC); Tipareste (AuC);
Reuniune(B,C,BuC); Tipareste (BuC); Readln
End.

Subprograms
A subprogram is a program unit/module that performs a particular task. These subprograms
are combined to form larger programs. This is basically called the 'Modular design'. A
subprogram can be invoked by a subprogram/program, which is called the calling program.

Pascal provides two kinds of subprograms:

 Functions: these subprograms return a single value.


 Procedures: these subprograms do not return a value directly.

Functions
A function is a group of statements that together perform a task. Every Pascal program has
at least one function which is the program itself, and all the most trivial programs can define
additional functions.
A function declaration tells the compiler about a function's name, return type, and
parameters. A function definition provides the actual body of the function.
Pascal standard library provides numerous built-in functions that your program can call. For
example, function AppendStr() appends two strings, function New() dynamically allocates
memory to variables and many more functions.

Defining a Function:
In Pascal, a function is defined using the function keyword. The general form of a function
definition is as follows:
function name(argument(s): type1; argument(s): type2; ...): function_type;
local declarations;
begin
...
< statements >
...
name:= expression;
end;
A function definition in Pascal consists of a function header, local declarations and a
function body. The function header consists of the keyword function and a name given to the
function. Here are all the parts of a function:
 Arguments: The argument(s) establish the linkage between the calling program and
the function identifiers and also called the formal parameters. A parameter is like a
placeholder. When a function is invoked, you pass a value to the parameter. This value is
referred to as actual parameter or argument. The parameter list refers to the type, order, and
number of the parameters of a function. Use of such formal parameters is optional. These
parameters may have standard data type, user-defined datatype or subrange data type.

The formal parameters list appearing in the function statement could be simple or subscripted
variables, arrays or structured variables, or subprograms.

 Return Type: All functions must return a value, so all functions must be assigned a
type. Thefunction-type is the data type of the value the function returns. It may be standard,
user-defined scalar or subrange type but it cannot be structured type.
 Local declarations: local declarations refer to the declarations for labels, constants,
variables, functions and procedures, which are application to the body of function only.
 Function Body: The function body contains a collection of statements that define what
the function does. It should always be enclosed between the reserved words begin and end. It
is the part of a function where all computations are done. There must be an assignment
statement of the type - name := expression; in the function body that assigns a value to the
function name. This value is returned as and when the function is executed. The last
statement in the body must be an end statement.

Following is an example showing how to define a function in pascal:

(* function returning the max between two numbers *)


function max(num1, num2: integer): integer;
var
(* local variable declaration *)
result: integer;
begin
if (num1 > num2) then
result := num1
else
result := num2;
max := result;
end;

Function Declarations:
A function declaration tells the compiler about a function name and how to call the function.
The actual body of the function can be defined separately.

A function declaration has the following parts:

function name(argument(s): type1; argument(s): type2; ...): function_type;

For the above defined function max(), following is the function declaration:

function max(num1, num2: integer): integer;

Function declaration is required when you define a function in one source file and you call that
function in another file. In such case you should declare the function at the top of the file
calling the function.

Calling a Function:
While creating a function, you give a definition of what the function has to do. To use a
function, you will have to call that function to perform the defined task. When a program calls
a function, program control is transferred to the called function. A called function performs
defined task and when its return statement is executed or when it last end statement is
reached, it returns program control back to the main program.

To call a function you simply need to pass the required parameters along with function name
and if function returns a value then you can store returned value. Following is a simple
example to show the usage:

program exFunction;
var
a, b, ret : integer;

(*function definition *)
function max(num1, num2: integer): integer;
var
(* local variable declaration *)
result: integer;
begin
if (num1 > num2) then
result := num1
else
result := num2;
max := result;
end;
begin
a := 100;
b := 200;
(* calling a function to get max value *)
ret := max(a, b);
writeln( 'Max value is : ', ret );
end.

Procedures are subprograms that, instead of returning a single value, allow to obtain a group
of results.

Defining a Procedure:
In Pascal, a procedure is defined using the procedure keyword. The general form of a
procedure definition is as follows:
procedure name(argument(s): type1, argument(s): type 2, ... );
< local declarations >
begin
< procedure body >
end;
A procedure definition in Pascal consists of a header , local declarations and a body of
the procedure. The procedure header consists of the keyword procedure and a name given to
the procedure. Here are all the parts of a procedure:
 Arguments: The argument(s) establish the linkage between the calling program and
the procedure identifiers and also called the formal parameters. Rules for arguments in
procedures are same as that for the functions.
 Local declarations: local declarations refer to the declarations for labels, constants,
variables, functions and procedures, which are application to the body of the procedure only.
 Procedure Body: The procedure body contains a collection of statements that define
what the procdure does. It should always be enclosed between the reserved words begin and
end. It is the part of a procedure where all computations are done.
Following is the source code for a procedure called findMin(). This procedure takes 4
parameters x, y, z and m and stores the minimum among the first three variables in the
variable named m. The variable m is passed by reference (we will discuss passing arguments
by reference a little later):
procedure findMin(x, y, z: integer; var m: integer);
(* Finds the minimum of the 3 values *)
begin
if x < y then
m := x
else
m := y;
if z <m then
m := z;
end; { end of procedure findMin }

Procedure Declarations:
A procedure declaration tells the compiler about a procedure name and how to call the
procedure. The actual body of the procedure can be defined separately.

A procedure declaration has the following syntax:

procedure name(argument(s): type1, argument(s): type 2, ... );


Please note that the name of the procedure is not associated with any type. For the above
defined procedure findMin(), following is the declaration:
procedure findMin(x, y, z: integer; var m: integer);

Calling a Procedure:
While creating a procedure, you give a definition of what the procedure has to do. To use the
procedure, you will have to call that procedure to perform the defined task. When a program
calls a procedure, program control is transferred to the called procedure. A called procedure
performs the defined task and when its last end statement is reached, it returns the control
back to the calling program.

To call a procedure you simply need to pass the required parameters along with the procedure
name as shown below:

program exProcedure;
var
a, b, c, min: integer;
procedure findMin(x, y, z: integer; var m: integer);
(* Finds the minimum of the 3 values *)
begin
if x < y then
m:= x
else
m:= y;
if z < m then
m:= z;
end; { end of procedure findMin }
begin
writeln(' Enter three numbers: ');
readln( a, b, c);
findMin(a, b, c, min); (* Procedure call *)
writeln(' Minimum: ', min);
end.

When the above code is compiled and executed, it produces following result:

Enter three numbers:


89 45 67
Minimum: 45

Recursive Subprograms
We have seen that a program or subprogram may call another subprogram. When a
subprogram calls itself, it is referred to as a recursive call and the process is known as
recursion.

To illustrate the concept, let us calculate the factorial of a number. Factorial of a number n is
defined as:

n! = n*(n-1)!
= n*(n-1)*(n-2)!
...
= n*(n-1)*(n-2)*(n-3)... 1

The following program calculates the factorial of a given number by calling itself recursively.

program exRecursion;
var
num, f: integer;
function fact(x: integer): integer; (* calculates factorial of x - x! *)
begin
if x=0 then
fact := 1
else
fact := x * fact(x-1); (* recursive call *)
end; { end of function fact}
begin
writeln(' Enter a number: ');
readln(num);
f := fact(num);
writeln(' Factorial ', num, ' is: ' , f);
end.

When the above code is compiled and executed, it produces following result:

Enter a number:
5
Factorial 5 is: 120
Following is another example which generates the Fibonacci Series for a given number using
arecursive function:
program recursiveFibonacci;
var
i: integer;
function fibonacci(n: integer): integer;
begin
if n=1 then
fibonacci := 0
else if n=2 then
fibonacci := 1
else
fibonacci := fibonacci(n-1) + fibonacci(n-2);
end;
begin
for i:= 1 to 10 do
write(fibonacci (i), ' ');
end.

When the above code is compiled and executed, it produces following result:

0 1 1 2 3 5 8 13 21 34

Arguments of a Subprogram:
If a subprogram (function or procedure) is to use arguments, it must declare variables that
accept the values of the arguments. These variables are called the formal parameters of the
subprogram.

The formal parameters behave like other local variables inside the subprogram and are
created upon entry into the subprogram and destroyed upon exit.

While calling a subprogram, there are two ways that arguments can be passed to the
subprogram:

Call Type Description

This method copies the actual value of an argument into


the formal parameter of the subprogram. In this case,
Call by value
changes made to the parameter inside the subprogram
have no effect on the argument.

This method copies the address of an argument into the


formal parameter. Inside the subprogram, the address is
Call by reference used to access the actual argument used in the call. This
means that changes made to the parameter affect the
argument.
By default, Pascal uses call by value to pass arguments. In general, this means that code
within a subprogram cannot alter the arguments used to call the subprogram. The example
program we used in the chapter 'Pascal - Functions' called the function named max()
using call by value.
Whereas, the example program provided here ( exProcedure) calls the procedure findMin()
using call by reference.

-------------

Various Date & Time Functions:


Free Pascal provides the following date and time functions:

S. Function Name & Description


N

function DateTimeToFileDate(DateTime: TDateTime):LongInt; 


1
Convert DateTime type to file date.

function DateTimeToStr( DateTime: TDateTime):; 


2
Construct string representation of DateTime

function DateTimeToStr(DateTime: TDateTime; const FormatSettings:


3 TFormatSettings):;
Construct string representation of DateTime

procedure DateTimeToString(out Result: ;const FormatStr: ;const DateTime:


4 TDateTime); 
Construct string representation of DateTime

procedure DateTimeToString( out Result: ; const FormatStr: ; const DateTime:


5 TDateTime; const FormatSettings: TFormatSettings ); 
Construct string representation of DateTime

procedure DateTimeToSystemTime( DateTime: TDateTime; out SystemTime:


6 TSystemTime ); 
Convert DateTime to system time

function DateTimeToTimeStamp( DateTime: TDateTime):TTimeStamp;Convert


7
DateTime to timestamp 

function DateToStr( Date: TDateTime ):; 


8
Construct string representation of date

function DateToStr( Date: TDateTime; const FormatSettings:


9 TFormatSettings ):; 
Construct string representation of date

function Date: TDateTime; 


10
Get current date

function DayOfWeek( DateTime: TDateTime ):Integer; 


11
Get day of week

procedure DecodeDate( Date: TDateTime; out Year: Word; out Month: Word;
12 out Day: Word ); 
Decode DateTime to year month and day

procedure DecodeTime( Time: TDateTime; out Hour: Word; out Minute: Word;
13 out Second: Word; out MilliSecond: Word ); 
Decode DateTime to hours, minutes and seconds

function EncodeDate( Year: Word; Month: Word; Day: Word ):TDateTime; 


14
Encode year, day and month to DateTime

function EncodeTime( Hour: Word; Minute: Word; Second: Word; MilliSecond:


15 Word ):TDateTime; 
Encode hours, minutes and seconds to DateTime

function FormatDateTime( const FormatStr: ; DateTime: TDateTime ):; 


16
Return string representation of DateTime

function FormatDateTime( const FormatStr: ; DateTime: TDateTime; const


17 FormatSettings: TFormatSettings ):; 
Return string representation of DateTime

function IncMonth( const DateTime: TDateTime; NumberOfMonths: Integer =


18 1 ):TDateTime; 
Add 1 to month
function IsLeapYear( Year: Word ):Boolean; 
19
Determine if year is leap year

function MSecsToTimeStamp( MSecs: Comp ):TTimeStamp; 


20
Convert number of milliseconds to timestamp

function Now: TDateTime; 


21
Get current date and time

function StrToDateTime( const S: ):TDateTime; 


22
Convert string to DateTime

function StrToDateTime( const s: ShortString; const FormatSettings:


23 TFormatSettings ):TDateTime; 
Convert string to DateTime

function StrToDateTime( const s: AnsiString; const FormatSettings:


24 TFormatSettings ):TDateTime; 
Convert string to DateTime

function StrToDate( const S: ShortString ):TDateTime; 


25
Convert string to date

function StrToDate( const S: Ansistring ):TDateTime; 


26
Convert string to date

function StrToDate( const S: ShortString; separator: Char ):TDateTime; 


27
Convert string to date

function StrToDate( const S: AnsiString; separator: Char ):TDateTime; 


28
Convert string to date

function StrToDate( const S: ShortString; const useformat: ; separator:


29 Char ):TDateTime; 
Convert string to date

function StrToDate( const S: AnsiString; const useformat: ; separator:


30 Char ):TDateTime; 
Convert string to date

function StrToDate( const S: PChar; Len: Integer; const useformat: ; separator:


31 Char = #0 ):TDateTime; 
Convert string to date

function StrToTime( const S: Shortstring ):TDateTime; 


32
Convert string to time

function StrToTime( const S: Ansistring ):TDateTime; 


33
Convert string to time

function StrToTime( const S: ShortString; separator: Char ):TDateTime; 


34
Convert string to time

function StrToTime( const S: AnsiString; separator: Char ):TDateTime; 


35
Convert string to time

function StrToTime( const S: ; FormatSettings: TFormatSettings ):TDateTime; 


36
Convert string to time

function StrToTime( const S: PChar; Len: Integer; separator: Char =


37 #0 ):TDateTime; 
Convert string to time

function SystemTimeToDateTime( const SystemTime:


38 TSystemTime ):TDateTime; 
Convert system time to datetime
function TimeStampToDateTime( const TimeStamp:
39 TTimeStamp ):TDateTime; 
Convert time stamp to DateTime

function TimeStampToMSecs( const TimeStamp: TTimeStamp ):comp; 


40
Convert Timestamp to number of milliseconds

function TimeToStr( Time: TDateTime ):; 


41
Return string representation of Time

function TimeToStr( Time: TDateTime; const FormatSettings: TFormatSettings


42 ):; 
Return string representation of Time

function Time: TDateTime; 


43
Get current time

The following example illustrates the use of some of the above functions:

Program DatenTimeDemo;
uses sysutils;
var
year, month, day, hr, min, sec, ms: Word;
begin
writeln ('Date and Time at the time of writing : ',DateTimeToStr(Now));
writeln('Today is ',LongDayNames[DayOfWeek(Date)]);
writeln;
writeln('Details of Date: ');
DecodeDate(Date,year,month,day);
writeln (Format ('Day: %d',[day]));
writeln (Format ('Month: %d',[month]));
writeln (Format ('Year: %d',[year]));
writeln;
writeln('Details of Time: ');
DecodeTime(Time,hr, min, sec, ms);
writeln (format('Hour: %d:',[hr]));
writeln (format('Minutes: %d:',[min]));
writeln (format('Seconds: %d:',[sec]));
writeln (format('Milliseconds: %d:',[hr]));
end.

When the above code was compiled and executed, it produced following result:

Date and Time at the time of writing : 7/24/2012 8:26:


Today is Tuesday
Details of Date:
Day:24
Month:7
Year: 2012
Details of Time:
Hour: 8
Minutes: 26
Seconds: 21
Milliseconds: 8

This chapter explains dynamic memory management in Pascal. Pascal programming language
provides several functions for memory allocation and management.

Allocating Memory Dynamically


While doing programming, if you are aware about the size of an array, then it is easy and you
can define it as an array. For example to store a name of any person, it can go max 100
characters so you can define something as follows:

var
name: array[1..100] of char;

But now let us consider a situation where you have no idea about the length of the text you
need to store, for example you want to store a detailed description about a topic. Here we
need to define a pointer to string without defining how much memory is required.

Pascal provides a procedure newto create pointer variables.


program exMemory;
var
name: array[1..100] of char;
description: ^string;
begin
name:= 'Zara Ali';
new(description);
if not assigned(description) then
writeln(' Error - unable to allocate required memory')
else
description^ := 'Zara ali a DPS student in class 10th';
writeln('Name = ', name );
writeln('Description: ', description^ );
end.

When the above code is compiled and executed, it produces following result:

Name = Zara Ali


Description: Zara ali a DPS student in class 10th
Now, if you need to define a pointer with specific number of bytes to be referred by it later,
you should use the getmem function or the getmem procedure, which has the following
syntax:
procedure Getmem(
out p: pointer;
Size: PtrUInt
);

function GetMem(
size: PtrUInt
):pointer;
In the previous example, we declared a pointer to a string. A string has a maximum value of
255 bytes. If you really don't need that much space, or a larger space, in terms of
bytes, getmem subprogram allows specifying that. Let us rewrite the previous example,
using getmem:
program exMemory;
var
name: array[1..100] of char;
description: ^string;
begin
name:= 'Zara Ali';
description := getmem(200);
if not assigned(description) then
writeln(' Error - unable to allocate required memory')
else
description^ := 'Zara ali a DPS student in class 10th';
writeln('Name = ', name );
writeln('Description: ', description^ );
freemem(description);
end.

When the above code is compiled and executed, it produces following result:

Name = Zara Ali


Description: Zara ali a DPS student in class 10th

So you have complete control and you can pass any size value while allocating memory unlike
arrays where once you defined the size cannot be changed.

Resizing and Releasing Memory


When your program comes out, operating system automatically release all the memory
allocated by your program but as a good practice when you are not in need of memory
anymore then you should release that memory.

Pascal provides the procedure dispose to free a dynamically created variable using the
procedurenew. If you have allocated memory using the getmemsubprogram, then you need to
use the subprogram freemem to free this memory. The freemem subprograms have the
following syntax:
procedure Freemem(
p: pointer;
Size: PtrUInt
);

function Freemem(
p: pointer
):PtrUInt;
Alternatively, you can increase or decrease the size of an allocated memory block by calling
the functionReAllocMem. Let us check the above program once again and make use
of ReAllocMem and freememsubprograms. Following is the syntax for ReAllocMem:
function ReAllocMem(
var p: pointer;
Size: PtrUInt
):pointer;
Following is an example which makes use of ReAllocMem and freemem subprograms:
program exMemory;
var
name: array[1..100] of char;
description: ^string;
desp: string;
begin
name:= 'Zara Ali';
desp := 'Zara ali a DPS student.';
description := getmem(30);
if not assigned(description) then
writeln('Error - unable to allocate required memory')
else
description^ := desp;

(* Suppose you want to store bigger description *)


description := reallocmem(description, 100);
desp := desp + ' She is in class 10th.';
description^:= desp;
writeln('Name = ', name );
writeln('Description: ', description^ );
freemem(description);
end.
When the above code is compiled and executed, it produces following result:

Name = Zara Ali


Description: Zara ali a DPS student. She is in class 10th

Memory Management Functions


Pascal provides a hoard of memory management functions that is used in implementing
various data structures and implementing low level programming in Pascal. Many of these
functions are implementation dependent. Free Pascal provides the following functions and
procedure for memory management:

S.
Function Name & Description
N

function Addr(X: TAnytype):Pointer;


1
Return address of variable

function Assigned(P: Pointer):Boolean;


2
Check if a pointer is valid

function CompareByte(const buf1; const buf2; len: SizeInt):SizeInt;


3
Compare 2 memory buffers byte per byte

function CompareChar(const buf1; const buf2; len: SizeInt):SizeInt;


4
Compare 2 memory buffers byte per byte

function CompareDWord(const buf1; const buf2; len: SizeInt):SizeInt;


5
Compare 2 memory buffers byte per byte

function CompareWord(const buf1; const buf2; len: SizeInt):SizeInt;


6
Compare 2 memory buffers byte per byte

function Cseg: Word;


7
Return code segment

procedure Dispose(P: Pointer);


8
Free dynamically allocated memory

procedure Dispose(P: TypedPointer; Des: TProcedure);


9
Free dynamically allocated memory

function Dseg: Word;


10
Return data segment

procedure FillByte(var x; count: SizeInt; value: Byte);


11
Fill memory region with 8-bit pattern

procedure FillChar( var x; count: SizeInt; Value: Byte|Boolean|Char);


12
Fill memory region with certain character

procedure FillDWord( var x; count: SizeInt; value: DWord);


13
Fill memory region with 32-bit pattern

procedure FillQWord( var x; count: SizeInt; value: QWord);


14
Fill memory region with 64-bit pattern

procedure FillWord( var x; count: SizeInt; Value: Word);


15
Fill memory region with 16-bit pattern

procedure Freemem( p: pointer; Size: PtrUInt);


16
Release allocated memory

procedure Freemem( p: pointer );


17
Release allocated memory
procedure Getmem( out p: pointer; Size: PtrUInt);
18
Allocate new memory

procedure Getmem( out p: pointer);


19
Allocate new memory

procedure GetMemoryManager( var MemMgr: TMemoryManager);


20
Return current memory manager

function High( Arg: TypeOrVariable):TOrdinal;


21
Return highest index of open array or enumerated

function IndexByte( const buf; len: SizeInt; b: Byte):SizeInt;


22
Find byte-sized value in a memory range

function IndexChar( const buf; len: SizeInt; b: Char):SizeInt;


23
Find char-sized value in a memory range

function IndexDWord( const buf; len: SizeInt; b: DWord):SizeInt;


24
Find DWord-sized (32-bit) value in a memory range

function IndexQWord( const buf; len: SizeInt; b: QWord):SizeInt;


25
Find QWord-sized value in a memory range

function Indexword( const buf; len: SizeInt; b: Word):SizeInt;


26
Find word-sized value in a memory range

function IsMemoryManagerSet: Boolean;


27
Is the memory manager set

function Low( Arg: TypeOrVariable ):TOrdinal;


28
Return lowest index of open array or enumerated

procedure Move( const source; var dest; count: SizeInt );


29
Move data from one location in memory to another

procedure MoveChar0( const buf1; var buf2; len: SizeInt);


30
Move data till first zero character

procedure New( var P: Pointer);


31
Dynamically allocate memory for variable

procedure New( var P: Pointer; Cons: TProcedure);


32
Dynamically allocate memory for variable

function Ofs( var X ):LongInt;


33
Return offset of variable

function ptr( sel: LongInt; off: LongInt):farpointer;


34
Combine segment and offset to pointer

function ReAllocMem( var p: pointer; Size: PtrUInt):pointer;


35
Resize a memory block on the heap

function Seg( var X):LongInt;


36
Return segment

procedure SetMemoryManager( const MemMgr: TMemoryManager );


37
Set a memory manager

function Sptr: Pointer;


38
Return current stack pointer

function Sseg: Word;


39
Return stack segment register value
http://www.tutorialspoint.com/computer_glossary.htm

S-ar putea să vă placă și