Sunteți pe pagina 1din 6

Pointeri la funcţii

Putem declara pointeri către orice tip de date, atât către tipurile standard C, cât şi către tipurile pe care
le definim noi. În plus, limbajul C ne permite să declarăm pointeri la funcţii.

Numele unei funcţii reprezintă adresa de memorie la care începe funcţia. Numele functiei este, de fapt,
un pointer la funcţie.
Se poate stabili o corespondenţă între variabile şi funcţii prin intermediul pointerilor la funcţii. Ca şi
variabilele, aceşti pointeri:
• pot primi ca valori funcţii;
• pot fi transmişi ca parametrii altor funcţii
• pot fi intorşi ca rezultate de către funcţii

La declararea unui pointer către o funcţie trebuiesc precizate toate informaţiile despre funcţie, adică:

• tipul funcţiei
• numărul de parametri
• tipul parametrilor
care ne vor permite să apelăm indirect funcţia prin intermediul pointerului.
Declararea unui pointer la o funcţie se face prin:
tip (*pf)(listă_parametri_formali);
Dacă nu s-ar folosi paranteze, ar fi vorba de o funcţie care întoarce un pointer.

Apelul unei funcţii prin intermediul unui pointer are forma:


(*pf)(listă_parametri_actuali);
Este permis şi apelul fără indirectare:
pf(listă_parametri_actuali);

Cu pointerii la funcţii se lucrează la fel ca şi cu pointerii la orice tip de date. Se foloseşte operatorul &
pentru a obţine adresa de memorie a unei funcţii. Se foloseşte operatorul * pentru a obţine funcţia spre
care indică un pointer.

#include <stdio.h>

/* Definim doua functii cu doi parametri de tip int si care


returneaza void. */
void o_functie(int a, int b)
{
printf("O functie cu doi parametri de tip int: %d si %d.\n",a, b);
}
1
void alta_functie(int c, int d)
{
printf
("Alta functie cu doi parametri de tip int: %d si %d.\n",c, d);
}

int main()
{
/* Definim un pointer la functii cu doi parametri de tip int
si care returneaza void. */
void (*un_pointer) (int y, int z);

/* Atribuim pointerului adresa primei functii. */


un_pointer = &o_functie;

/* Invocam prima functie direct. */


o_functie(11, 22);

/* Invocam prima functie prin intermediul pointerului. In


loc de numele functiei folosim operatorul *. */
(*un_pointer) (12, 23);

un_pointer = &alta_functie;
alta_functie(33, 44);
(*un_pointer) (34, 45);

return 0;

În urma execuţiei acestui program se va afişa:


O functie cu doi parametri de tip int: 11 si 22.
O functie cu doi parametri de tip int: 12 si 23.
Alta functie cu doi parametri de tip int: 33 si 44.

Alta functie cu doi parametri de tip int: 34 si 45.

Vectori de pointeri la funcţii

O modalitate de folosire a pointerilor la funcţii este construirea de vectori de pointeri.

Este posibil să definim un tablou de pointeri la funcţii; apelarea funcţiilor, în acest caz, se face prin
referirea la componentele tabloului.

#include <stdio.h>

/* Definim patru functii fara parametru, care returneaza void.


Fiecare functie afiseaza cate un caracter pe ecran. */
2
void steluta()
{
printf("*");
}

void plus()
{
printf("+");
}

void minus()
{
printf("-");
}

void dolar()
{
printf("$");
}

int main()
{
int i;

/* Declaram un vector de pointeri la functie. */


void (*p[4]) (void);

/* Initializam vectorul cu adresele celor patru functii. */


p[0] = &steluta;
p[1] = &plus;
p[2] = &minus;
p[3] = &dolar;

/* Folosim vectorul de pointeri pentru a apela pe rand functiile. */


for (i = 0; i < 4; i++)
(*p[i]) ();

return 0;

Am definit patru functii care au aceeaşi semnătură (acelaşi număr/tip de parametri, şi acelaşi tip de
date returnat). Pe urmă am definit un vector de patru pointeri la funcţie şi am memorat în vectorul
respectiv adresele celor patru funcţii. Pe urmă putem apela într-un mod flexibil cele patru funcţii
folosindu-ne de vectorul definit şi de cicluri for.

Numele unei funcţii fiind un pointer către funcţie, poate fi folosit ca parametru în apeluri de funcţii.
În acest mod putem transmite în lista de parametri a unei funcţii – numele altei funcţii.
De exemplu, o funcţie care calculează integrala definită:
3
b
I = ∫ f(x) dx
a

va avea prototipul:
double integrala(double, double, double(*)(double));

Exemplu:

Definiţi o funcţie pentru calculul unei integrale definite prin metoda trapezelor,cu un număr fixat n de
puncte de diviziune:

b
 f(a) + f(b) n−1
 b − a
∫ f(x)dx = h + ∑ f(a + ih) cu h =
a  2 i=1  n

Folosiţi apoi această funcţie pentru calculul unei integrale definite cu o precizie dată ε. Această precizie
este atinsă în momentul în care diferenţa între două integrale, calculate cu n, respectiv 2n puncte de
diviziune este inferioară lui ε

#include <math.h>
double sinxp();
double trapez(double,double,int,double(*)());

double a=0.0, b=1.0, eps=1E-6;


int N=10;

int main()
{
int n=N;
double In,I2n,vabs;
In=trapez(a,b,n,sinxp);
do { n*=2;
I2n=trapez(a,b,n,sinxp);
if((vabs=In-I2n)<0) vabs=-vabs;
In=I2n;
} while(vabs > eps);
printf(“%6.2lf\n”, I2n);

return 0;
}

double trapez(double a,double b,int n,double(*f)())


{
double h,s;
int i;
h=(b-a)/n;

for(s=0.0,i=1;i<n;i++)
s+=(*f)(a+i*h);
4
s+=((*f)(a)+(*f)(b))/2.0;
s*=h;

return s;
}

Transmiterea prin adresă a parametrilor la funcţii

În C, transmiterea parametrilor la funcţii se face prin valoare. Când trimitem o variabilă ca parametru
unei funcţii, se trimite de fapt o copie a variabilei. Dacă în interiorul funcţiei se fac modificări asupra
parametrului, variabila originală nu este afectată. După încheierea apelului de funcţie variabila are
aceeaşi valoare ca şi înainte de apel.

Spre exemplu în următorul program avem o funcţie care modifică valoarea parametrului primit. Vom
observa că pe parcursul execuţiei funcţiei parametrul se modifica, dar imediat ce se iese din funcţie
variabila care a fost trimisă ca parametru revine la valoarea pe care o avea înainte de apel.

#include <stdio.h>

void o_functie(int parametru)


{
/* Afisam valoarea parametrului la inceputul functiei. */
printf("In functie, la inceput: %d.\n", parametru);

/* Modificam parametrul in interiorul functiei. */


parametru++;

/* Afisam inca o data parametrul la finalul functiei. */


printf("In functie, la final: %d.\n", parametru);
}

int main(void)
{
int variabila = 100;

/* Afisam variabila inainte de apelul functiei. */


printf("Inainte de apelul functiei: %d.\n", variabila);

/* Apelam functia. */
o_functie(variabila);

/* Afisam variabila dupa apelul functiei. */


printf("Dupa apelul functiei: %d.\n", variabila);

return 0;

5
Dacă dorim ca o variabilă să păstreze modificările făcute asupra ei într-o funcţie, trebuie să procedăm
astfel: trimitem ca parametru la funcţie un pointer care conţine adresa variabilei. În funcţie nu
modificăm pointerul primit, dar îl folosim pentru a accesa locaţia de memorie unde se afla variabila şi
a scrie noi valori la locaţia respectivă. În felul acesta modificăm de fapt valoarea variabilei. La
revenirea din funcţie vedem că modificările nu se mai pierd.

#include <stdio.h>

void inca_o_functie(int *parametru)


{
/* Afisam valoarea variabilei la inceputul functiei. */
printf("In functie, la inceput: %d.\n", *parametru);

/* Modificam variabila in interiorul functiei (prin


intermediul pointerului). */
(*parametru)++;

/* Afisam inca o data variabila la finalul functiei. */


printf("In functie, la final: %d.\n", *parametru);
}

int main(void)
{
int variabila = 100;

/* Afisam variabila inainte de apelul functiei. */


printf("Inainte de apelul functiei: %d.\n", variabila);

/* Apelam functia. Trimitem adresa variabilei ca parametru. */


inca_o_functie(&variabila);

/* Afisam variabila dupa apelul functiei. */


printf("Dupa apelul functiei: %d.\n", variabila);

return 0;
}

Acest mecanism de transmitere a parametrilor se numeşte transmitere prin adresă.