Sunteți pe pagina 1din 15

Functii

1
1

6. Functii

Un program contine una sau mai multe functii. Dintre acestea, una este
functie principala.
Fiecare functie are un nume. Numele functiei principale este main.
Celelalte functii au nume definite de utilizator.


1. Structura unei functii

O functie are urmatoarea structura:

tip nume (lista declaratiilor parametrilor formali)
{
declaratii }
instructiuni } corpul functiei
}

Primul rnd din formatul de mai sus reprezinta antetul functiei. Partea
inclusa ntre acolade, impreuna cu acoladele, formeaza corpul functiei.

n cazul tipurilor predefinite, tip din antetul functiei este un cuvnt cheie. El
defineste tipul valorii returnate de functie.

n limbajul C exista doua categorii de functii. O prima categorie
contine functiile care la revenirea din ele returneaza o valoare n punctul de apel.
Tipul acestei valori se defineste prin tip din antetul functiei. Cealalta categorie de
functii contine functiile care nu returneaza nici o valoare la revenirea din ele.

Pentru aceste functii se va folosi cuvantul cheie voidn calitate de tip. El
semnifica lipsa unei valori returnate la revenirea din functie.
O functie poate avea zero sau mai multi parametrii. Lista declaratiilor
Programarea calculatoarelor 2
parametrilor formali este vida n cazul n care functia nu are parametrii formali. n
acest caz antetul functiei se reduce la:

tip nume()

Mentionam ca absenta parametrilor poate fi indicata explicit folosind
cuvantul cheie void. Astfel, antetul de mai sus poate fi scris si sub forma:

tip nume (void)

Se pot defini functii cu un numar variabil de parametrii. n acest caz, lista
declaratiilor parametrilor formali contine numai declaratiile parametrilor care sunt
prezenti la orice apel al functiei. Acestia sunt asa numitii parametri ficsi ai functiei
spre deosebire de ceilalti care se numesc parametri variabili. Parametrii ficsi
preced pe cei variabili. Prezenta parametrilor variabili se indica, in antetul functiei,
prin trei puncte care se scriu dupa ultimul parametru fix al functiei.
n general sunt functii de biblioteca (ex: printf,).
n cazul n care functia are parametrii, declaratiile parametrilor formali se
includ ntre parantezele rotunde prezente dupa numele functiei si se separa prin
virgula daca sunt mai multe.

Exemple:
1. void f(void){...}
2. void f(){...}
3. int g(){...}
4. double h(void){...}
5. int f(int x, double y)
6. double df(long a, int b, unsigned c)
7. void vf(int n, double x, )
Parametrii se utilizeaza pentru a permite transferuri de date la o functie n
momentul apelului ei. Acest mecanism de transfer al datelor prin intermediul
parametrilor ne permite construirea de functii facnd abstractie de valorile
conctrete care vor fi prezente abia la executia programului. n momentul compilarii
Functii

3
3
este necesara numai cunoasterea tipurilor valorilor pe care le vor primi parametrii
la executie. Aceste tipuri sunt definite prin declaratiile parametrilor respectivi,
declaratii care, asa cum am vazut mai sus, se indica n antetul functiei.

Parametrii decarati n antetul unei functii si care apoi se utilizeaza n corpul
functiei, se numesc formali pentru a sublinia faptul ca ei nu reprezinta valori
concrete, ci tin numai locul acestora pentru a putea exprima procesul de calcul
realizat de functie. Ei se concretizeaza la executie prin apelurile functiei. Valorile
parametrilor formali se instantiaza la fiecare apel al unei functii prin asa numitii
parametrii actuali.

Utilizarea parametrilor formali la implementarea functiilor si atribuirea de
valori concrete pentru ei la executie, reprezinta un prim nivel de abstractizare n
programare. Acest mod de programare se numeste programare procedurala si
realizeaza un proces de abstractizare prin parametrii. Acesta a fost primul mod
de programare studiat. Pe parcurs vom vedea si alte moduri.

Observatii:
1. Antetul functiei poate avea si urmatorul format:

tip nume (lista parametrilor formali)
declaratiile parametrilor formali
{...}

Ex: int f(a,b)
int a, float b;
{}

Acest tip de declaratie este o sursa de erori si de aceea se recomanda
prima forma prezentata.

2. Pentru functia principala se pot utiliza antetele:

Programarea calculatoarelor 4
int main()
int main(void)
void main()
void main(void)
main()
main(void)

Primele si ultimele doua antete presupun ca functia main returneaza o
valoare ntreaga la revenirea din ea n sistemul de operare.

Functia main poate avea si parametrii. Acestia, cnd sunt prezenti, permit
utilizarea de catre program a unor argumente definite la lansarea programului.

main(int argc, char *argv[])
unde:
- argc - numarul argumentelor plus 1;
- *argv[ ] - tablou de pointeri la argumentele de apel;
argv[0] - pointer spre calea fisierului cu imaginea
executabila a programului
argv[i] - pointer spre al i-lea argument


2. Apelul si prototipul functiilor

ntr-un program o functie poate avea o definitie si unul sau mai multe
apeluri.

O functie poate fi apelata folosind o constructie de forma:

nume(lista_parametrilor_actuali)

unde:
- nume - Este numele functiei care se apeleaza.
Functii

5
5
- lista_parametrilor_ actuali - Este fie vida daca functia nu are parametrii, fie se
compune din unul sau mai multi parametrii actuali separati prin virgule. Un
parametru actual este o expresie. Parametrii actuali se corespund cu cei formali
prin ordine si tip.

La apel se atribuie parametrilor formali valorile parametrilor actuali si apoi
executia continua cu prima instructiune din corpul functiei apelate. La revenirea din
functie se ajunge n functia din care s-a facut apelul si executia continua cu
constructia urmatoare apelului.

Pentru a apela o functie putem utiliza constructia de mai sus urmata de
caracterul punct si virgula.

O alta posibilitate este aceea de a folosi constructia de mai sus drept
operand al unei expresii. Un astfel de apel este posibil numai pentru functiile care
returneaza o valoare la revenirea din ele. n acest caz valoarea returnata de functie
se foloseste la evaluarea expresiei din care s-a facut apelul.

O functie poate fi apelata daca n prealabil a fost definita.
Apelurile functiei nu pot fi precedate totdeauna de definitia ei. n astfel de
cazuri definitia functiei apelate este nlocuita printr-un asa numit prototipal ei.
Prototipul unei functii are un format asemanator cu antetul ei. Acesta
reprezinta o informatie pentru compilator cu privire la:
- tipul valorii returnate de functie;
- existenta si tipurile parametrilor functiei.
De aceea un prototip al unei functii poate fi scris ca si antetul functiei
respective, urmat de punct si virgula. Exista si o forma prescurtata pentru prototip
si anume aceea n care se omite numele parametrilor:

tip nume (lista tipurilor parametrilor formali);

Exemple:
1. void f(void);
Programarea calculatoarelor 6
2. double a(void);
3. void c(int x, long y[], double z);
sau
void c(int, long [], double);

Observatie:
Limbajul C se livreaza cu o serie de functii care au o utilizare frecventa n
programe. Ele se numesc functii standard de biblioteca si au prototipurile n fisiere
de extensie .h.

Compilatorul utilizeaza datele din prototip pentru a verifica tipurile
parametrilor de la apel (parametrii actuali). n cazul n care un parametru actual are
un tip diferit de tipul corespunzator din prototip, compilatorul C converteste
automat valoarea parametrului actual spre tipul indicat n prototip.
Se recomanda ca aceasta regula sa nu fie utilizata. Se poate utiliza n acest
scop operatorul de conversie explicita ((tip))

Exemplu. Fie
int n;
f(double);
n loc de
f(n);
se poate utiliza
f((double) n);

Revenirea dintr-o functie se poate realiza n doua moduri:
a. Dupa executia ultimei instructiuni din corpul functiei;
b. La ntlnirea instructiunii return.
Instructiunea return este instructiunea de revenire din functie. Ea are
formatele:
1. return
2. return expresie
Formatul 2 se foloseste n corpul unei functii care returneaza o valoare la
Functii

7
7
revenirea din ea. Valoarea expresiei din instructiunea return este chiar valoarea
returnata de functie.
n cazul n care tipul acestei expresii difera de tipul din antet, valoarea
expresiei se converteste automat spre tipul din antet, nainte de a reveni din functie.
Formatele a si b1 se utilizeaza numai n corpul unei functii care nu
returneaza nici o valoare.

Exemplu:
Program de calcul m! m=0..150


#include <stdio.h>
#include <conio.h>
double fact(int);
#define NMAX 170
main()
{
int m;
for(m=0; m<=NMAX; m++) {
printf("m=%d\tm!=%g\n",m,fact(m));
if((m+1)%23 == 0) {
printf("Apasati o tasta pentru a continua\n");
getch();
}
}
}
double fact(int n)
{
double f;
int i;
if(n<0 || n>NMAX)
return -1.0;
for(i=2, f=1.0; i<=n; i++) f *= i;
Programarea calculatoarelor 8
return f;
}

3. Definitia unei functii n C++ (extensia .cpp)

Definitia unei functii in C++ are formatul:

specificator_de_clasa tip modificatori nume (lista declaratiilor
parametrilor formali)

unde:
- specificator_de_clasa poare fi static (functia este recunoscuta numai n fisierul
unde se afla) sau extern (globala, implicit).
- modificatori sunt specifici diferitelor implementari ale limbajului C++. n cazul
Turbo C++ cei mai importanti modificatori sunt:
cdecl, pascal, near, far, huge.
Acesti modificatori se utilizeaza cnd se linkediteaza programe scrise n
mai multe limbaje (cdecl, pascal), sau cu diferite modele de memorie (near, far,
huge).
Modele de memorie :

Date Cod
tiny max 64Ko (near)
small near near
medium near far
compact far near
large far far
huge* far far
* tablourile pot depasi 64Ko

Spre deosebire de C in C++ se pot face initializari ale parametrilor
formali. Parametrii formali initializati se numesc parametrii impliciti.
Functii

9
9
La apelul functiilor, unui parametru implicit poate sa-i corespunda sau nu un
parametru actual. n cazul n care unui parametru implicit nu-i corespunde, la apel
un parametru actual, parametrul formal respectiv ia ca valoare valoarea sa initiala.
Aceasta se mai numeste valoarea implicita a parametrului respectiv.
Daca la un apel, unui parametru implicit i corespunde un parametru actual,
atunci parametrului formal respectiv i se atribuie n mod obisnuit valoarea
parametrului actual care i corespunde. Cu alte cuvinte, n acest caz se neglijeaza
valoarea implicita a parametrului formal.
Parametrii impliciti trebuie sa ocupe ultimele pozitii n lista declaratiilor din
antetul functiei.
Ex: int f(int zi, int luna, int an=1998)

4. Apel prin valoare si apel prin referinta

n limbajul C, la apelul unei functii, fiecarui parametru formal i se atribuie
valoarea parametrului actual care i corespunde. Deci, la apelul unei functii se
transfera valorile parametrilor actuali. Acest tip de apel se numeste apel prin
valoare (call by value).

Valorile parametrilor actuali se pastreaza pe stiva.

Apelul prin valoare este utilizeaza n cazul n care functia apelata nu trebuie
sa modifice valorile parametrilor actuali, deoarece n felul acesta parametrii actuali
sunt protejati fata de eventualele modificari care ar putea apare din greseala.
De aici rezulta ca la apelul prin valoare transferul datelor este
unidirectional, adica valorile se transfera prin parametrii numai de la functia care
face apelul spre cea apelata, nu si invers.

Exista situatii cnd se doreste ca functia apelata sa modifice valorile
parametrilor actuali. n unele limbaje de programare, la apel nu se transfera valorile
parametrilor actuali, ci adresele acestor valori. n acest caz, se spune ca apelul
este prin referinta (call by reference) (ex: la FORTRAN).

Programarea calculatoarelor 10
ntre cele doua tipuri de apeluri exista o diferenta esentiala si anume:
- n cazul apelului prin valoare, functia apelata nu poate modifica parametrii actuali
din functia care a facut apelul, neavnd acces la ei;
- n cazul apelului prin referinta, functia apelata, dispunnd de adresa parametrilor
actuali, i poate modifica.


Limbajele Pascal si C++ permit ambele tipuri de apeluri.
n limbajul C apelul prin referinta poate fi realizat folosind pointeri.


5. Realizarea apelului prin referinta utiliznd parametrii de tip pointer

n cazul n care un parametru actual este un nume de tablou, apelul prin
valoare devine apel prin referinta, parametrului formal corespunzator lui i se
atribuie ca valoare adresa primului element al tabloului.

Deci daca se face apelul:

int tab[...];
...
f(tab);
...

si f are antetul:

void f(int v[])

atunci la apel v are aceeasi valoare ca si tab. Aceasta nseamna ca v[i] si tab[i]
nseamna acelasi lucru.

Exemple:
1. Fie functia:
Functii

11
11
Antetul: void f(int x[100]) sau void f(int x[])
Corp: for(s=0;n>0;n--) s+=x[n-1];
Apelul: f(tab);
2. double mat[4][10];
Antetul: void fct(double mat[][10])
Apelul: fct(mat);


Folosind pointeri si n alte cazuri, putem sa transformam apelul prin valoare
n apel prin referinta. Astfel daca x este o variabila simpla, putem transfera la apel
n locul valorii lui x, adresa lui x:

int x;
...
h(x); // se transfera valoarea lui x
...
g(&x);// se transfera adresa lui x
...

Antetele celor doua functii vor fi:

void f(int i)
void g(int *pi)

La apel, lui pi i se atribuie ca valoare adresa lui x. De aceea, functia g are
posibilitatea sa modifice valoarea lui x. De exemplu, daca n corpul functiei g se
utilizeaza atribuirea:

...
*pi=100;
...

atunci lui x i se atribuie valoarea 100.
Programarea calculatoarelor 12
n felul acesta, apelul prin valoare se poate folosi pentru a realiza apelul
prin referinta.

Exemplu:

void swap(int* px, int* py)
{
int temp;
temp=*px; *px=*py; *py=temp;
)
apelul:
int a,b;

a=5; b=6;
swap(&a,&b);
// dupa apel a=6, b=5

6. Pointeri spre functii

Numele unei functii este un pointer spre functia respectiva. De aceea,
numele unei functii poate fi folosit ca parametru actual la apelul unei functii. n felul
acesta, o functie poate transfera functiei apelate un pointer spre o functie. Functia
apelata, la rndul ei, poate apela functia care i-a fost transferata n acest fel.
Fie, de exemplu, f o functie care are ca parametru o alta functie. Apelul:
f(g);
unde g este numele unei functii, transfera functiei f pointerul spre functia g.
Inainte de apel, ambele functii (f si g) trebuie sa fie definite sau sa li se
indice prototipurile.

Fie:
tipg g(listag);

Daca scriem:
Functii

13
13
tip *nume(lista)
rezulta o functie ce returneaza un pointer spre tip, si nu asta vrem. Este ca si (tip *)
nume(lista).

Prezenta parantezelor conduce la faptul ca nume este o functie si nu un
pointer. Aceasta deoarece parantezele rotunde reprezinta operatori mai prioritari
dect operatorul unar *. Pentru ca nume sa fie pointer, este nevoie ca operatorul
unar * sa se aplice prioritar fata de parantezele care indica prezenta unei functii.
Aceasta se obtine folosind o constructie de forma:

tip (*nume)(lista)
n cazul de fata nume este un pointer spre o functie.
n exemplul de mai sus prototipul functiei f poate fi scris:

tipf f(tipg (*)(listag));

Antetul functiei f va fi:

tipf f(tipg (*p)(listag))

iar n corpul functiei vom utiliza apeluri de forma:

(*p)(...); sau x=(*p)(...);

Exemple:
1. int g(void);
double( f(int (*)(void); // functia f are ca si parametru o
// functie ce returneaza int si nu are parametrii

2. double h(int, float);
int f(double (*) (int,float));


Programarea calculatoarelor 14
7. Realizarea apelului prin referinta n limbajul C++

n limbajul C++ (extensia .cpp) se poate folosi pentru apel prin referinta
operatorul unar &.
Tipul referinta se introduce prin:

tip& nume;

Numele declarat n acest fel se spune ca este o referinta.
O variabila referinta se poate initializa la definirea sau declararea ei, cu
numele unei alte variabile.

Tipul referinta creeaza sinonime pentru nume deja definite. De aceea
operatorul unar & se mai numeste si operator de referentiere.
Operatorul unar * utilizat la declararea pointerilor are n expresii un efect
invers celui de referentiere si de aceea el se numeste operator de dereferentiere.

Exemplu:
int i;
int& ri=i;

Variabila ri este sinonima cu variabila i. Ele reprezinta acelasi ntreg.

Exemplu:

void swap(int& ra, int& rb)
{
int temp;
temp=ra; ra=rb; rb=temp;
}
apelul:
int a,b;

Functii

15
15
a=5; b=6;
swap(a,b);
// dupa apel a=6, b=5
n limbajul C++, o functie poate returna o referinta la o data de un tip
oarecare. n acest caz, tip din antetul unei functii are forma:

tip&

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