Apelarea procedurilor

Unul din motivele importante pentru care definim o procedura este acela ca dorim sa o folosim de mai multe ori, în cât mai multe puncte din program.

Urmatorul program, pe care l-am denumit gratar, ca de altfel si programul desen, realizeaza acest obiectiv.


PROGRAM gratar;

{ Programul contine proceduri care editeaza linii orizontale si verticale - un gratar }
 
PROCEDURE HOR;
{ Afiseaza o linie orizontala lunga de 25 de unitati (#)}
BEGIN
..writeln('#########################')
END { HOR };
 
PROCEDURE VER;
{ Afiseaza 5 bare verticale }
BEGIN
..writeln('|.....|.....|.....|.....|')
END { VER };
 
BEGIN {program principal}
..HOR; VER; HOR; VER; HOR
END { gratar }.

Rezultatul executiei programului:

...#########################...
...|.....|.....|.....|......|...
...#########################...
...|.....|.....|.....|......|...
...#########################...

Pentru a obtine un gratar mai înalt, putem folosi o noua versiune a programului gratar.


PROGRAM gratar2;
{ Programul contine proceduri care editeaza linii orizontale si verticale - un gratar - varianta2 }
VAR i:integer;
 
PROCEDURE HOR;
{ Afiseaza o linie orizontala lunga de 25 de unitati (#)}
BEGIN
..writeln('#########################')
END { HOR };
 
PROCEDURE VER;
{ Afiseaza 5 bare verticale }
BEGIN
..writeln('|.....|.....|.....|.....|')
END { VER };
 
BEGIN { program principal }
..FOR i:=1 TO 5 DO
....BEGIN
......hor;
......ver
....END;
..hor
END { gratar2 }.

Remarcati prezenta variabilei globale i (de tip integer).

În sfârsit, daca dorim sa dam beneficiarului posibilitatea de a-si alege singur înaltimea gratarului, putem rescrie programul principal, definind o procedura cu un parametru valoare, dupa cum urmeaza:


PROGRAM gratar3;
{ Programul contine proceduri care editeaza linii orizontale si verticale -un gratar - varianta3 }
VAR
..inalt:integer;
 
PROCEDURE desen(h: integer);
VAR
..i: integer;
 
..PROCEDURE HOR;
..{ Afiseaza 25 linii orizontale }
..BEGIN
....writeln('#########################')
..END { HOR };
 
..PROCEDURE VER;
..{ Afiseaza 5 linii verticale }
..BEGIN
....writeln('|.....|.....|.....|.....|')
..END {A VER };
 
BEGIN { desen }
..FOR i:=1 TO h DO
....BEGIN
......hor;
......ver
....END;
..hor
END { desen };
 
BEGIN { program principal }
..writeln;
..write('Precizati inaltimea gratarului ');
..readln(inalt);
..writeln;
..desen(inalt)
END { gratar3 }.

Fiind definite în procedura desen, cele doua cunostinte ale noastre - procedurile hor si ver - sunt subordonate procedurii desen. Este corect, deoarece numai procedura desen are nevoie de referiri la definitiile lor. Totusi, se impune o ghidare a cititorului, precizând în acest sens BEGIN {desen}, data fiind... distanta fata de header-ul procedurii desen a zonei de instructiuni proprii procedurii.


Operatia prin care o procedura este activata din programul principal este cunoscuta sub numele de apelare (calling sau invoking, în limba engleza).

Când procedura apelata are un parametru, valoarea efectiva (curenta) ce trebuie sa substituie acel parametru este specificata în paranteze, dupa numele procedurii. În programul gratar3, procedura desen este apelata prin enuntul desen(inalt). În acest caz, inalt este parametrul actual (efectiv), o variabila (globala) întreaga, declarata în sectiunea VAR a programului principal. Procedura desen este definita în termeni ai parametrului formal h, care reprezinta valoarea parametrului. Numele parametrilor formali si efectivi poate fi acelasi, dar este recomandat sa nu fie. Oricum, ei trebuie sa fie de acelasi tip. Atunci când este apelata o procedura care contine mai mult de un parametru, trebuie ca parametrii efectivi (actuali) sa fie listati (în interiorul parantezelor) si separati prin virgule.

Iata o mica procedura, printprodus care foloseste valorile a doi parametri efectivi de tip real: r si s, care au fost declarate (ca si procedura) în programul testproc. Sa urmarim ce se întîmpla.

Exemplu:
PROCEDURE printprodus(a,b:real);
BEGIN
..writeln (a*b:7:2)
END { printprodus };

Enuntul printprodus(7,4) se executa în urmatorii pasi: lui a (din procedura) i se atribuie 7; b ia valoarea 4. Procedura printprodus(7,4) va afisa valoarea 28 (Compilatorul PASCAL admite atribuirea directa de valori întregi unei variabile de tip real, dar nu si invers !). Controlul este predat dupa aceea enuntului imediat urmator apelului de procedura.

PROGRAM testproc;
VAR r, s: real;
 
PROCEDURE printprodus(a,b:real);
BEGIN
..writeln (a*b:7:2)
END { printprodus };
 
BEGIN
..r:=7; s:=4;
..printprodus(r,s);
..printprodus(s,r);
..printprodus(r-3,4*s);
..printprodus(7,4);
..printprodus(2+sqrt(9),sqr(4)/8)
END { testproc }.

Cât priveste ultimul enunt, transmiterea parametrilor presupune mai întâi efectuarea calculelor din cele doua expresii, dupa care se executa pasii cunoscuti, prezentati anterior. În consecinta,
........printprodus(2+sqrt(9),sqr(4)/8)
va afisa 10.00.


De retinut: Parametrii efectivi trebuie sa corespunda ca numar cu parametrii formali, precizati la definirea procedurii; asocierea parametrilor efectivi cu cei formali nu se efectueaza în functie de numele acestora, ci în conformitate cu ordinea de aparitie în lista (parametrii efectivi trebuie sa corespunda cu parametrii formali din punct de vedere al ordinii de aparitie în lista); parametrii efectivi (transmisi prin valoare) pot fi variabile, constante sau expresii; tipul unui parametru efectiv trebuie sa fie identic cu tipul parametrului formal corespunzator; daca parametrul formal este de tip real, parametrul efectiv corespunzator poate fi de tip întreg.

Revenim la procedura cu parametri suma_si_diferenta. Sa urmarim cum ar raspunde aceasta procedura la mai multe apelari lansate din urmatorul program (testproc2).

PROGRAM testproc2;
VAR
..k,m,n,j:integer;
 
PROCEDURE suma_si_diferenta(a,b:integer; VAR c,d:integer);
BEGIN
..c:=a+b; d:=a-b
END { suma_si_diferenta };
 
BEGIN
..suma_si_diferenta(5,2,j,k);writeln(j,k);
..suma_si_diferenta(3*2,12 div 3,m,n);writeln(m,n);
..suma_si_diferenta(5,2,k,8); suma_si_diferenta(7,3.4,m,n);
END { testproc2 }.

Prin apelarea procedurii
....suma_si_diferenta(5,2,j,k);
se calculeaza pentru început cele doua expresii din procedura. Intrucât parametrii c si d sunt de tip VAR, valorile acestora se returneaza programului principal în variabilele j si k.
....Writeln(j,k)
are ca efect obtinerea valorilor: 7 si 3.

Prin apelarea procedurii:
....suma_si_diferenta(3*2,12 div 3,m,n);
rezulta, pentru m si n valorile 10 si 2.

Enuntul:
....suma_si_diferenta(5,2,k,8);
nu are sens, deoarece diferenta 5-2=3 nu poate fi atribuita lui 8 (5+2=7 poate fi atribuita lui k) ! De asemenea enuntul
....suma_si_diferenta (7,3.4,m,n)
nu este corect deoarece al doilea parametru efectiv (3.4) nu respecta regula: tip integer ! De altfel, în toate aceste cazuri eroarea va fi detectata la compilarea programului.

Considerati ca tot ce-am ... povestit pâna acum despre proceduri a fost doar o simpla provocare. Mai serios despre constructia si utilizarea lor într-o conversatie viitoare (vezi Conversatia 7).