Sunteți pe pagina 1din 13

Funcii

Un program n C este un ansamblu de funcii care efectueaz o activitate bine definit.


Dintre aceste funcii, ntotdeauna o funcie este numit main i este funcia care este apelat la
lansarea n execuie a programului.
Definirea unei funcii
Forma general a unei funcii este:
tip_rezultat nume_funcie( list_de_parametrii )
{
declaraii_locale
instruciuni
}
unde tip_rezultat este un tip de date oarecare, mai puin tipul tablou, i specific tipul de
date pe care l returneaz funcia. Cnd nu se specific tipul, se consider c funcia
returneaz o valoare de tip int. Pentru o funcie care nu ntoarce un rezultat, se va specifica
tipul void. Dup tipul rezultatului, se specific numele funciei, nume_funcie, urmat de lista
parametrilor formali (list_de_parametrii) ncadrat de paranteze rotunde. Aceasta este o list
de variabile separate prin virgul. Fiecare variabil se declar individual, specificndu-se tipul
i numele. Forma general a listei de parametrii formali este urmtoarea:
(tip_1 nume_var_1, tip_2 nume_var_2,..., tip_n nume_var_n)
Exemple de declaraii de liste corect i incorect:
f(int k, int i, int j)
f(int k, i, j)

/* lista corecta
/* lista incorecta

*/
*/

O list poate s vid, adic s nu conin parametrii. ntr-un asemenea caz, se poate
folosi cuvntul void ncadrat de paranteze rotunde sau numai de paranteze, care nu trebuie s
lipseasc.
Exemple de declaraii de liste vide:
f(void)
g()
Fiecare funcie este un bloc de cod discret. O funcie nu poate avea acces la codul unei
alte funcii dect printr-un apel de funcie. Variabilele declarate ntr-o funcie sunt variabile
locale, adic sunt create la intrarea n funcia respectiv i distruse la ieirea din aceasta. Nu se
poate defini o funcie ntr-o alt funcie, deci toate funciile au aceeai sfer de influen.
Apelul unei funcii
Apelul unei funcii se face specificnd numele funciei urmat de lista parametrilor
actuali. Aceasta este format din variabile, constante sau expresii compatibile ca tip cu
parametrii formali, adic fiecrui parametru formal i se asociaz o variabil, o constant sau o
expresie compatibil ca tip.
58

Dac lista de parametrii este vid, apelul se face specificnd numale funciei urmat de
paranteze rotunde.
De exemplu, n cazul funciilor:
int f(int k,int i,float a)
int g(void)
apeluri ale funciilor apar n urmtoarea secven:

int m, j;
float b;
j=g();
f(m, j+1, 12.5);

Prototipul unei funcii


Definiia unei funcii apare n cadrul fiierului surs, naintea fiecrui apel, numai n
cazuri particulare. Definiia lipsete n cazul funciilor din biblioteci sau atunci cnd funcia se
afl n alt fiier surs sau proiect (n cadrul unui proiect, nu se admite ca o funcie s fie
definit de dou ori).
Pentru ca la compilare s se poat efectua verificarea i validarea apelurilor unei
funcii, limbajul C prevede declaraii fr definire ale funciilor, numite prototipuri. Acestea
sunt recomandate n C i impuse n C++.
Forma general de definire a unui prototip este:
tip_rezultat nume_funcie(tip_1 nume_var_1, tip_2 nume_var_2,..., tip_n nume_var_n);
Exemple de prototipuri de funci:
int f(int k,int i,float a);
void g(int *p1,int *p2);
Prototipurile permit compilatorului s verifice i s gseasc diferenele dintre
argumentele utilizate la apelare i parametrii funciei (tipurile i numrul acestora).
Folosirea numelor parametrilor este obional. Utilizarea lor este ns recomandat,
deoarece acetia pot fi utilizai de compilator n cadrul mesajelor de ereoare.
Exemple de prototipuri de funci, fr specificarea numelor parametrilor:
int f(int,int,float);
void g(int *,int *);
n C, lipsa parametrilor se specific prin utilizarea cuvntului void. n C++, lista vid
indic faptul c funcia nu are parametrii i nu este necesar inserarea cuvntului void.
Pentru funcia main nu este necesar un prototip, iar lipsa parametrilor nu se mai indic
prin cuvntului void.
Prototipul trebuie inserat n programn (de regul, la nceputul programului) naintea
oricrui apel al funciei.
59

Revenirea dintr-o funcie


Instruciunea return
Exist dou ci de ncheiere a execuiei unei funcii i de revenire n programul
apelant: prima variant de revenire are loc dup ce se execut ultima instruciune a funciei
(dup care urmeaz acolada de sfrit), iar a doua variant de revenire are loc la ntlnirea
instruciunii return.
Sintaxa instruciunii return este urmtoarea:
return expresie;
unde expresie reprezint rezultatul ntors de funcie, deci acesta trebuie s fie compatibil cu
tipul indicat n prototipul funciei.
Exceptnd funciile de tip void, toate funciile returneaz o valoare. Aceast valoare
este specificat explicit de ctre instruciunea return.
Transferul parametrilor
La apelul unei funcii, transferul parametrilor se poate face prin valoare sau prin referin.
Transferul prin valoare
Valorile parametrilor i altor variabile locale ale funciei sunt memorate n stiv sau n
registrele microprocesorului.
n cazul transferului prin valoare, valoarea unui argument se copiaz n zona de
memorie rezervat parametrului formal corespunztor. Dac argumentul este o variabil, orice
operaie efectuat asupra parametrului formal nu afecteaz variabila, ceea ce poate constitui o
protecie util.
Transferul unei valori poate fi nsoit i de eventuale conversii de tip, corespunztor
informaiilor pe care compilatorul le are despre funcie. Pentru conversii explicite , se poate
utiliza operatorul cast.
n programul Combinari din n luate cate k, se utilizeaz funcia f() cu un parametru cu
transmitere prin valoare:
/* Combinari din n luate cate k */
#include <stdio.h>
#include <conio.h>
unsigned long int f(int n); /* prototip functie */
void main()
{
int n,k;
clrscr();
printf("n=");scanf("%d",&n);
printf("k=");scanf("%d",&k);
printf("cnk=%d",f(n)/f(k)/f(n-k));
getch();
}

60

unsigned long int f(int n) /* definire functie */


{
int i;
unsigned long int nf=1;
for(i=1;i<=n;) nf*=i++;
return nf;
}
Transferul prin referin
Cnd o funcie trebuie s modifice valoarea unei variabile indicate ca parametru,
parametru formal corespunztor variabilei trebuie declarat ca pointer. n acest mod, la apelare,
se ofer explicit adresa variabilei.
De exemplu, programul Combinari din n luate cate k (cu pointeri) utilizeaz transferul
prin referin.
/* Combinari din n luate cate k (cu pointeri) */
#include <stdio.h>
#include <conio.h>
void f(int n, unsigned long int *nf);
void main()
{
int n,k;
unsigned long int *nf,*kf,*n_kf;
clrscr();
printf("n=");scanf("%d",&n);
printf("k=");scanf("%d",&k);
f(n,nf);
f(k,kf);
f(n-k,n_kf);
printf("cnk=%d",(*nf)/(*kf)/(*n_kf));
getch();
}
void f(int n, unsigned long int *nf)
{
int i;
*nf=1;
for(i=1;i<=n;) *nf*=i++;
}
Transmiterea tablourilor ca argumente
Cnd un tablou este utilizat ca argument, aceasta constitue o excepie de la regula de
transfer prin valoare, deoarece se transmite adresa tabloului. Astfel, codul funciei poate opera
asupra coninutului elementelor tabloului i poate s-l modifice. n cazul transmiterii unui sir,
parametrul se poate declar pointer (vezi programele Functie care returneaza pointer i
Radacina polinom), iar n cazul matricelor, parametrul se declar ca o matrice (vezi
programul Patratul unei matrice).

61

/* Radacina polinom */
#include <stdio.h>
#include <conio.h>
#include <math.h>
float cit_nr(char c);
void cit_sir(int n, float *p);
float val_pol(int n, float *p, float x);
void calc_rad(int n,float *a,float p,float q);
void main(void)
{
int n;
float a[50];
float p,q;
clrscr();
n=(int)cit_nr('n');
cit_sir(n,a);
p=cit_nr('p');
q=cit_nr('q');
calc_rad(n,a,p,q);
getch();
}
float cit_nr(char c)
{
float x;
printf("%c=",c);
scanf("%f",&x);
return x;
}
void cit_sir(int n, float *p)
{
int i;
float x;
printf("Coeficientii polinomului:\n");
for (i=0;i<=n;)
{
printf("a[%d]=",i++);
scanf("%f",&x);
*p++=x;
}
}

62

float val_pol(int n, float *p, float x)


{
int i;
float v;
for (i=0,v=0;i++<=n;) v=v*x+*p++;
return v;
}
void calc_rad(int n, float *a, float p, float q)
{
float m,fp,fq,fm;
const float delta=0.00001;
fp=val_pol(n,a,p);
fq=val_pol(n,a,q);
if (fp*fq>0) printf("Polinomul nu schimba semnnul"
" in intervalul (%f;%f)",p,q);
else
{
m=(p+q)/2;
fm=val_pol(n,a,m);
while (abs(fm)>delta)
{
if (fp*fm>0) { p=m; fp=fm; }
else
{ q=m; fq=fm; };
m=(p+q)/2;
fm=val_pol(n,a,m);
}
printf("Radacina este: %f",m);
}
}
/* Patratul unei matrice */
#include <stdio.h>
#include <conio.h>
int cit_nr(char c);
void cit_mat(char c, int n, float p[10][10]);
void afis_mat(int n, float p[10][10]);
void prod_mat(int n, float a[10][10], float b[10][10]);
void main(void)
{
int n;
float a[10][10],b[10][10];
clrscr();
n=cit_nr('n');
cit_mat('a',n,a);
prod_mat(n,a,b);
afis_mat(n,b);
63

getch();
}
int cit_nr(char c)
{
int i;
printf("%c=",c);
scanf("%d",&i);
return i;
}
void cit_mat(char c, int n,float p[10][10])
{
int i,j;
float x;
for (i=0;i<n;i++)
for (j=0;j<n;j++)
{
printf("%c[%d,%d]=",c,i,j); scanf("%f",&x);
p[i][j]=x;
}
}
void afis_mat(int n, float p[10][10])
{
int i,j;
for (i=0;i<n;)
{
for (j=0;j<n-1;) printf("%f ",p[i][j++]);
printf("%f\n",p[i++]j[]);
}
}
void prod_mat(int n, float a[10][10], float b[10][10])
{
int i,j,k;
for (i=0;i<n;i++)
for (j=0;j<n;j++)
{
b[i][j]=0;
for (k=0;k<n;k++)
b[i][j]+=a[i][k]*a[k][j];
};
}
Funcii care returneaz pointeri
Pointerii sunt adrese de memorie ale anumitor tipuri de date. Deoarece fiecare tip de
date are o anumit lungime i aritmetica pointerilor se bazeaz pe tipul de date ctre care
indic acetia, trebuie cunoscut tipul de date ctre care indic un pointer. Din acest motiv,

64

pentru o funcie care returneaz un pointer, trebuie s se declare explicit tipul acestuia. Forma
general de declarare a unei astfel de funcii este urmtoarea:
tip_rezultat *nume_funcie ( lista_tip_parametrii );
De exemplu, programul Functie care returneaza pointer utilizeaz fincia *cauta_nr()
care returneaz un pointer de tip float care este adresa elementului unui ir, dac acesta
coincide cu o valoare cutat x, sau valoarea NULL, n caz contrar.
/* Functie care returneaza pointer */
#include <stdio.h>
#include <conio.h>
float cit_nr(char c);
void cit_sir(char c, int n, float *p);
float *cauta_nr(int n, float *p, float x);
void afis_sir(int n, float *p);
void main()
{
int n;
float a[100],x,*p;
clrscr();
n=(int)cit_nr('n');
cit_sir('a',n,a);
x=cit_nr('x');
p=cauta_nr(n,a,x);
if (p) afis_sir(n-(int)(p-a),p);
else printf("Numarul %f nu face parte din sir",x);
getch();
}
float cit_nr(char c)
{
float x;
printf("%c=",c);
scanf("%f",&x);
return x;
}
void cit_sir(char c, int n, float *p)
{
int i;
float x;
for (i=0;i<n;)
{
printf("%c[%d]=",c,i++);
65

scanf("%f",&x);
*p++=x;
}
}
float *cauta_nr(int n, float *p, float x)
{
int i;
for (i=0;i++<n;) if (*p==x) return p;
else p++;
return NULL;
}
void afis_sir(int n, float *p)
{
int i;
for (i=0;i++<n;)
printf("%f ",*p++);
}
Pointeri ctre funcii
Limbajul C permite operarea cu variabile de tip pointer care conin adresa de nceput a
codului executabil al unei funcii. Forma general de declarare a unui astfel de pointer ctre o
funcie este urmtoarea:
tip_rezultat (*nume_pointer) ( lista_tip_parametrii );
Observaie: La declararea unei funcii care returneaz un pointer, spre deosebire de
declararea unui pointer care ctre o funcie, nu se utilizeaz paranteze rotunde. De exemplu:
float *f (float a, float b); /* functie */
float (*p)(float a, float b); /* pointer */
Adresa unei funcii se obine dac unui pointer de funcii, compatibil ca tip i
parametrii cu funcia, i se atribuie numele funciei, fr ca acesta s fie urmat de paranteze. De
exemplu, pentru funcia f i pointerul de funcie p, din declaratia anterioar, se poate face
atribuirea:
p=f; /* atribuire de functie catre un pointer compatibil */
Apelul funciei se face specificnd, ntre paranteze rotunde, operatorul * urmat de
numele funciei i parametrii actuali. n cazul exemplului de mai sus, un apel este urmtorul:
float a,b,c;
c=(*p)(a,b); /* apel de functie */
Programul Pointeri catre o functie afieaz suma, diferena, produsul sau ctul a dou
numere reale a i b, utiliznd pointerul de funcie p cruia, succesiv, i se atribuie adresele unor
funcii compatibile: suma, dif, prod i cat.

66

/* Pointeri catre o functie */


#include <stdio.h>
#include <conio.h>
void afis_rez(char c, float a, float b, float
(*p)(float a, float b));
/* sau
(*p)(float, float));
*/
float cit_nr(char c);
float suma(float a, float b);
float dif(float a, float b);
float prod(float a, float b);
float cat(float a, float b);
void main (void)
{
float a,b;
float (*p)(float a, float b); /* sau
float (*p)(float, float);
*/
clrscr();
a=cit_nr('a');
b=cit_nr('b');
p=suma;
afis_rez('+',a,b,p);
afis_rez('-',a,b,dif);
afis_rez('*',a,b,prod);
afis_rez('/',a,b,cat);
getch();
}
float cit_nr(char c)
{
float x;
printf("%c=",c);
scanf("%f",&x);
return x;
}
float suma(float a, float b)
{
return a+b;
}
float dif(float a, float b)
{
return a-b;
}

67

float prod(float a, float b)


{
return a*b;
}
float cat(float a, float b)
{
return a/b;
}
void afis_rez(char c, float a, float b,
float (*p)(float, float))
/* sau
float (*p)(float a, float b))*/
{
float x;
x=(*p)(a,b);
printf("%f%c%f=%f\n",a,c,b,x);
/* sau
printf("%f%c%f=%f\n",a,c,b,(*p)(a,b));
*/
}
Funcii recursive
Se spune c o funcie este recursiv atunci cnd n blocul ei exist o instruciune care
apeleaz funcia respectiv. Cu alte cuvinte, o funcie este recursiv dac se apeleaz pe sine.
Practic, pentru a se asigura ieirea din recursivitate, este necesar ca apelul recursiv s
apar n blocul unei instruciuni de decizie sau ciclare, a crei condiie s fie modificat de
funcie, astfel nct s se opreasc seria de apeluri.
Un exemplu de apel recursiv al unei funcii este programul Factorial recursiv, n care
funcia fact este recursiv:
/* Factorial recursiv */
#include <stdio.h>
#include <conio.h>
typedef unsigned long int uli;
typedef unsigned int ui;
typedef unsigned char uc;
ui cit_nr(char c);
uli fact(int n);
void main()
{
clrscr();
uc n;
n=cit_nr('n=');
printf("n!=%u",fact(n));
getch();
}

68

ui cit_nr(char c)
{
ui x;
printf("%c=",c);
scanf("%u",&x);
return x;
}
uli fact(int n)
{
uli f=1;
if (n) f= n*fact(n-1);
return f;
}
Modificatorul const cu parametrii de funcii
Cnd un pointer este transmis ca parametru unei funcii, funcia poate s modifice
valoarea variabilei indicate de pointer. n anumite cazuri, este necesar ca funcia s nu
modifice valoarea indicat de un argument pointer. O asemenea situaie apare n cazul
tablourilor, situaie n care transferul se face n mod obligatoriu prin referin. Pentru ca
anumite obiecte, indicate de argumentele unei funcii, s nu fie modificate de funcia
respectiv, se utilizeaz modificatorul const.
Aceste aspecte sunt evideniate n urmtorul program:
/* Functiile si modificatorul const */
#include <stdio.h>
#include <conio.h>
#include <string.h>
void modif_sir(char *p1, char const *p2);
void main()
{
clrscr();
char s1[50],s2[50];
printf("Introduceti s1:");gets(s1);
printf("Introduceti s2:");gets(s2);
printf("\nInainte de apel functie:\n");
printf("s1=%s\ns2=%s\n",s1,s2);
modif_sir(s1,s2);
printf("\nDupa apel functie\n");
printf("s1=%s\ns2=%s\n",s1,s2);

69

getch();
}
void modif_sir(char *p1, char const *p2)
{
char *p;
p=p1;
for (; *p1;++p1) if (*p1==' ') *p1='+';
printf("\nApel functie\n");
printf("p1=%s\np2=",p);
/*

for (; *p2;++p2) if (*p2==' ') *p2='-'; EROARE


for (; *p2;++p2) if (*p2==' ') printf("%c",'-');
else printf("%c",*p2);
}

70

*/

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