Sunteți pe pagina 1din 7

6.

Functii
n general, un program este alcatuit dintr-un ansamblu de module, fiecare
modul corespunznd unei subprobleme a problemei date. La rndul lor, aceste subprobl
eme pot fi descompuse n alte subprobleme, acest proces de descompunere progresiva
putnd continua pna se obtin probleme simple, alcatuite doar din cteva instructiuni
. Identificarea acestor subprobleme, care vor fi mai simplu de tratat, presupune
determinarea unor prelucrari similare efectuate asupra unor informatii diferite
, sau mpartirea problemei n subprobleme, mai simple, dar avnd semnificatii clare. D
escrierea n limbajul C a unei astfel de subprobleme constituie o functie. Deci o
functie este o unitate de sine statatoare de cod (instructiuni) proiectata pentr
u a realiza (rezolva) o anumita problema (task). O functie C joaca acelasi rol p
e care l au functiile, subrutinele si procedurile n alte limbaje de programare, de
si detaliile pot fi diferite.
Aceste functii sunt organizate, din punct de vedere functional (al apelu
rilor), ntr-o structura ierarhica; n vrful acestei ierarhii se afla functia princip
ala (main), sau modulul principal, care apeleaza modulele de la nivelurile infer
ioare. O functie poate fi apelata nu numai de catre functia (modulul) principal,
dar si de alte functii.
Folosirea functiilor presupune existenta unor mecanisme de definire si a
pelare a acestora. Pentru identificarea unei functii, acesteia i se asociaza un
nume, distinct de numele altor functii. Pentru a specifica informatiile pe care
functia le schimba cu o alta functie, sau modulul principal, de care va fi apela
ta, functiei i se asociaza o lista de parametri. n cadrul definirii unor functii,
acesti parametri sunt denumiti parametri formali (ntruct au rol descriptiv; descr
iu operatiile efectuate de functie). n cadrul apelului unei functii, parametrii s
e numesc actuali sau efectivi, si acestia i vor nlocui pe cei formali, n momentul a
pelului.
Si n exemplele utilizate anterior s-au folosit functii, de exemplu pentru
citirea, respectiv scrierea datelor s-au utilizat functiile: scanf() si printf
().
Pe lnga aceste functii de biblioteca, un program C poate contine o singur
a functie, main(), ca n exemplele prezentate pna acum.
Spre deosebire de Pascal, o functie C nu poate contine alte functii. Functiile d
antet, care v
efinite de utilizator pot fi incluse ntr-unul sau mai multe fisiere
or fi compilate separat.
n general, o functie poate realiza att actiuni ct si furniza rezultate.
6.1. Definirea functiei si transferul parametrilor
Formatul general pentru definirea unei functii este:
tip_returnat nume_functie (tip1 param1, tip2 param2, )
{
declaratii_variabile_locale
/* corpul functiei:
prelucrarile efectuate de aceasta */
. . . . . . . . . . .
return (expresie);
}
Se defineste functia nume_functie , care returneaza o valoare de un anumit
tip
tip_returnat (tipul expresiei)
si are parametrii formali param1, param2,
, dec
larati de tipurile: tip1, tip2,
.
Daca functia nu returneaza o valoare, tip_returnat nu este specificat sau
este void (adica nimic). Daca functia returneaza o valoare de tip int, tip_return
at poate fi omis, desi specificarea tipului int, ca valoare returnata, este o mai
buna practica de programare (si se recomanda, pentru a pune n evidenta valoarea
returnata). Daca ntre paranteze se specifica numai void, functia nu are argumente
.
Daca se utilizeaza puncte ( ) ca ultimul (sau singurul) parametru n lista d
e parametri, functia va lua un numar variabil de argumente, ca n declaratia:
int printf (char*format, )
{

. . . .
}
Declaratiile pentru argumente de tip tablou cu o singura dimensiune nu t
rebuie sa specifice numarul de elemente din tablou. Pentru tablouri multidimensi
onale, marimea fiecarei dimensiuni, mai putin prima, trebuie specificata.
Daca functia returneaza o singura valoare, tipul acesteia precede numele
functiei, iar valoarea returnata este cea indicata de declaratia return (expres
ie);. Parantezele ce includ expresia sunt optionale, dar ele sunt folosite de mu
lti programatori.
Spre deosebire de Pascal sau Fortran n care sunt diferite proceduri (subr
utine) ce returneaza oricte valori, inclusiv nici una, si functii care returneaza
o singura valoare, limbajul C nu face deosebire ntre acestea. n C sunt doar funct
ii, care pot, optional, returna o singura valoare, n modul descris anterior.
O functie care returneaza o valoare poate fi utilizata n expresii, n timp
ce o functie de tip void nu are o valoare si nu poate fi utilizata ntr-o expresie
.
Formatul general al apelului unei functii este:
nume_functie (arg1, arg2, );
Valorile arg1, arg2, sunt transmise ca argumente efective pentru functie
. Daca functia nu are argumente, sunt specificate, obligatoriu, cele doua parant
eze ( ).
Daca se apeleaza o functie care este descrisa (definita), dupa apelul sa
u, sau definita n alt fisier trebuie inclusa o declaratie a prototipului functiei
, ce are formatul general:
tip_returnat nume_functie (tip1 param1, tip2 param2,
);
Aceasta declaratie precizeaza compilatorului tipul valorii returnate de
functie, numarul de argumente pe care le ia si tipul fiecarui argument. De exem
plu:
long double power (double x, int n);
Numele argumentelor dintre paranteze pot fi omise, ntruct important este t
ipul argumentelor si nu numele lor:
long double power (double, int);
deoarece numele sunt nesemnificative n acest moment.
Daca compilatorul a ntlnit anterior definitia functiei sau o declaratie de
prototip pentru functie, fiecare argument va fi automat convertit pentru a se p
otrivi cu tipul asteptat de functie, cnd aceasta este apelata.
Daca nu a fost ntlnita nici definitia functiei, nici o declaratie de proto
tip, compilatorul va presupune ca functia returneaza o valoare de tip int, si va
converti automat toate argumentele de tip float la tipul double, iar cele de ti
p char sau short int la tipul int, nainte de a le transmite functiei. Celelalte t
ipuri de argumente ale functiei vor fi transmise fara conversie.
Toate argumentele pentru o functie pot fi transmise prin valoare; adica
valorile transmise, prin variabile sau expresii, sunt utilizate pentru a initial
iza argumentele formale ale functiei, si deci valorile argumentelor efective nu
pot fi modificate de functie. Functia nu are acces niciodata la argumentele actu
ale (efective) ale apelului, daca sunt transmise prin valoare. Valorile pe care
le manipuleaza functia sunt propriile sale copii, locale, care sunt memorate n st
iva. Odata ce functia se termina stiva este descarcata, deci aceste valori local
e se pierd. Din acest motiv argumentele actuale nu sunt modificate, ceea ce nseam
na ca programatorul nu trebuie sa salveze si sa refaca valorile argumentelor, la
apelul unei functii.
Transferul parametrilor prin valoare nu este potrivit n situatiile:
cnd se transfera un obiect mare: necesita timp si spatiu pentru a aloca s
i copia obiectul n stiva, care poate fi prea mare pentru aplicatii n timp real;
cnd valorile argumentelor trebuie sa fie modificate.
Daca un pointer (referinta) este transmis unei functii, functia poate mo
difica valorile referite de pointer, dar nu poate modifica valoarea acestui poin
ter.
Utilizarea referintei (pointerului) unui argument pentru transmiterea ac
estuia se impune cnd functia trebuie sa returneze rezultate. De asemenea poate fi

utilizata n situatiile cnd se transmite un obiect de dimensiuni mari, cnd se trans


mite doar adresa obiectului; n locul copierii ntregului obiect, daca se transmite
argumentul prin valoare.
Pentru a evita modificarea, din greseala, a pointerului (referintei), o buna pra
ctica este aceea de a declara argumentul de tip const. Aceasta permite compilato
rului sa previna modificarea neintentionata a acestuia, mai ales ntr-un lant de a
peluri de functii, la care argumentul este transmis.
Exemple:
1)
Se va scrie un program care citeste perechi de numere ntregi si afiseaza
cel mai mare divizor comun pentru fiecare pereche. Se va utiliza o functie pentr
u determinarea celui mai mare divizor comun. Programul se va executa ciclic pna s
e citeste o valoare nula. (Transmiterea parametrilor se va face prin valoare, ntr
uct functia primeste doi ntregi si returneaza unul singur - cel mai mare divizor c
omun).
/*
programul determina cel mai mare divizor comun pentru perechi de numere
intregi, introduse de la tastatura, pana se introduce o valoare egala cu zero
*/
#include <stdio.h>
int cmmdc (int a, int b)
{
int rest;
while ( b != 0 )
{
rest = a % b;
a = b;
b = rest;
}
return ( a );
}
void main (void)
{
int cmmdc (int a, int b);
int x, y;
printf ("Numerele :");
scanf ("%d%d", &x, &y);
while ( ( x*y ) != 0 )
{
printf ("Cel mai mare divizor comun este :%d\n", cmmdc (x,y));
printf ("Numerele : ");
scanf ("%d%d", &x, &y);
}
}
2)
Tiparirea unui numar ntreg n toate bazele de la 2 la 36 (transmitere tot p
rin valoare)
/*
Programul afiseaza valorile unui numar intreg in toate bazele de la 2 la
36,
utilizand pentru conversia intr-o baza data ca parametru o functie (con
versie).
*/
#include <stdio.h>
#define LUNG_MAX 32
const int baza_max = 36;
void main(void)
{
long int numar;
int domeniu;
void conversie (long int valoare, int baza);
printf ("Programul afiseaza valoarea unui numar intreg in \n"
"toate bazele de la 2 la 16 \n");

printf ("Valoarea de convertit:");


scanf ("%li", &numar);
for (domeniu=2 ; domeniu <= baza_max ; ++domeniu)
{
conversie (numar, domeniu);
printf (" /baza: %d \n", domeniu);
}
}
void conversie (long int valoare, int baza)
{
char cifra[LUNG_MAX];
int index = 0;
if (valoare < 0)
{
printf("-");
valoare = -valoare;
}
do
{
if (valoare % baza < 10)
cifra[index] = '0' + valoare % baza;
else
cifra [index] = 'A' + valoare % baza-10;
index ++;
valoare /= baza;
} while (valoare > 0);
for (--index ; index >= 0; --index)
printf ("%c", cifra[index]);
}
3)
Sa se scrie un program care calculeaza si afiseaza sumele partiale ale s
eriei armonice:
+ 1/n ;
S(n) = 1 + 1/2 + 1/3 +
pentru diferite valori ale lui n. Rezultatele vor fi afisate sub forma unor nume
re rationale de tip fractie ireductibila a/b, unde a si b sunt ntregi.
Pentru a rezolva aceasta problema putem folosi doua functii:
o functie pentru simplificarea unei fractii prin cel mai mare divizor co
mun (utiliznd algoritmul lui Euclid); spre deosebire de functia din primul exempl
u, aceasta primeste fractia si o returneaza simplificata;
o functie care aduna doua fractii:
a1/b1 + a2/b2 = (a1*b2 + b1*a2) / (b1*b2) ;
si va returna fractia simplificata n prima din cele doua fractii. Cele doua funct
ii vor utiliza transmiterea parametrilor prin referinta, deoarece returneaza cte
doua valori: numaratorul si numitorul fractiei.
/*
programul calculeaza si afiseaza sumele partiale ale seriei:
1 + 1/2 + 1/3 + 1/4 + 1/5 + 1/6 + . . . + 1/n
afisarea se face sub forma unor numere rationale, de tip fractii ireduct
ibile a/b.
Se utilizeaza doua functii:
- prima aduna doua fractii, si returneaza fractia rezultata;
- a doua simplifica o fractie, si o returneaza;
Transferul parametrilor se face prin referinta ( pointeri ).
*/
#include <stdio.h>
void main(void)
{
int nr_linii = 0;
long int numarator, numitor, i, n;
void aduna_fractii (long int *pa1, long int *pb1, long int pa2, long int pb2);
void simplifica (long int *pa, long int *);

printf("\n Introduceti nr.");


scanf("%li", &n);
numarator = 1;
numitor = 1;
printf("\n");
printf("%5li/%-5li ", numarator, numitor);
for ( i = 2 ; i <= n ; ++i)
{
aduna_fractii ( &numarator, &numitor, 1, i);
simplifica ( &numarator, &numitor);
printf("%5li/%-5li ", numarator, numitor);
nr_linii++;
/* numarul de fractii afisate pe o linie */
if (nr_linii % 5 == 0)
printf("\n");
}
}
void aduna_fractii ( long int *pa1, long int *pb1, long int a2, long int b2)
{
*pa1 = (*pa1)*b2+(*pb1)*a2;
*pb1 = (*pb1)*b2;
}
void simplifica (long int *pa, long int *pb)
{
long int ca, cb, rest;
ca = *pa;
cb = *pb;
while ( cb )
{
rest = ca % cb;
ca = cb;
cb = rest;
}
*pa /= ca;
*pb /= ca;
}
6.2. Variabile locale si globale
Functiile pot comunica (transmite parametri) si prin intermediul variabi
lelor globale. O variabila globala este o variabila a carei valoare poate fi acc
esata de orice functie, din cadrul unui program. Variabilele globale, pentru a p
utea fi accesate de orice functie, sunt declarate n exteriorul acestor functii, a
stfel nct nu apartin unei anumite functii.
n programul urmator, prezentat ca exemplu, toate functiile utilizate nu a
u nici un parametru; ele utilizeaza pentru efectuarea prelucrarilor si transmite
rea valorilor variabilele globale: numar_convertit[ ], numar si baza.
Variabilele globale sunt definite primele n program. Utilizarea lor poate
fi acceptata n programele n care multe functii trebuie sa aiba acces la valorile
aceleiasi variabile. n acest mod se reduce numarul de argumente necesare a fi tra
nsmise unei functii.
Dezavantajul utilizarii variabilelor globale consta n reducerea generalit
atii functiei, deoarece se refera la o anumita variabila globala; de asemenea, n
unele cazuri, aceasta diminueaza si claritatea programului. Functiile ce utilize
aza variabilele globale nu mai pot fi utilizate n cadrul altor module, deoarece e
le depind de context: nume variabile globale, tipul lor, etc.
Variabilele declarate n cadrul unei functii (sau bloc) sunt variabile loc
ale ale functiei (sau blocului). Ele sunt definite numai n domeniul functiei (blo
cului) reprezentat de corpul functiei sau blocului respectiv, inclusiv blocurile
incluse n acestea, exceptnd blocurile interioare acestora n care variabilele au fo

st redeclarate.
Variabilele definite n cadrul unei functii sunt denumite si variabile loc
ale automatice, deoarece ele sunt automat create la apelul functiei si valorile lo
r sunt locale functiei.
Variabilele locale, declarate ntr-o functie (bloc) exista numai pe durata
executiei acelei functii (bloc), fiind create la intrarea n functie, prin alocar
e de memorie, si distruse la iesirea din functie, prin eliberarea memoriei ocupa
te.
Variabilele declarate n exteriorul unui bloc pot fi referite din cadrul b
locului; pentru acest bloc, variabilele acestea sunt nelocale (sau globale).
ntr-un bloc (al unei functii) sunt accesibili toti identificatorii defini
ti n acel bloc, precum si cei din blocurile n care acesta este inclus. Pentru oric
are din acesti identificatori, definitia valabila n blocul considerat este cea af
lata n blocul cel mai apropiat.
Parametrii formali declarati n prototipul functiei pot fi folositi pentru
a referi argumentele functiei oriunde n cadrul corpului functiei.
Exemplu de utilizare a variabilelor globale: programul converteste un numar ntreg
ntr-o alta baza.
/*

Programul afiseaza un numar intreg intr-o baza ,folosind o


functie pentru conversia in baza specificata;
Se utilizeaza pentru transferul parametrilor intre functii:
VARIABILE GLOBALE

*/
#include <stdio.h>
int numar_convertit[16];
int numar, baza;
void main(void)
{
void citeste_numar_baza(void);
void conversie (void);
citeste_numar_baza();
if (baza < 2 || baza > 16)
{
printf ("Baza eronata ! Implicit baza = 10 \n");
baza = 10;
}
conversie();
}
void citeste_numar_baza(void)
{
printf ("Numar de convertit:");
scanf ("%d", &numar);
printf ("In baza:");
scanf ("%d", &baza);
}
void conversie (void)
{
char cifra_baza[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','
F'};
int index=0;
if (numar < 0)
{
printf("-");
numar = -numar;
}
do
{
numar_convertit[index] = numar % baza;
numar /= baza;

index ++;
} while (numar != 0);
for ( --index ; index >= 0 ; --index )
printf ("%c", cifra_baza[numar_convertit[index]]);
printf ("\n");
}
n acest exemplu, functiile definite nu au argumente, motiv pentru care la declara
rea functiilor s-a utilizat tipul void pentru argumente; de asemenea functiile n
u returneaza nici o valoare. Prelucrarile efectuate de aceste functii se fac, de
fapt, asupra variabilelor globale, definite n afara functiilor.
Efecte laterale
Orice functie, fie ca nu este de tip void si calculeaza o valoare pe car
e o ntoarce ca rezultat al apelului sau, fie ca este de tip void, poate modifica
si variabilele globale (sau nelocale) ale programului, pe lnga valorile transmise
ca parametrii, prin referinta (pointeri).
Acestea constituie efecte laterale ale functiei si, de obicei, fac nteleg
erea programelor mai dificila. Din acest motiv se evita modificarea variabilelor
globale n cadrul functiilor.
De asemenea, daca dorim ca functia sa nu modifice valorile parametrilor,
chiar daca sunt transmisi prin referinta, parametrii respectivi trebuie declara
ti de tip const n antetul functiei. n acest fel se evita unele erori de programare
, dar si prelucrarile realizate de functie devin mai clare.

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