Sunteți pe pagina 1din 23

Pointeri la funcii

Prof. dr. ing. Daniela Saru

Curs - Programarea Calculatoarelor Anul I A

Facultatea Automatica si Calculatoare - UPB

Particulariti ale limbajului C


Reamintire:
numele unui tablou pointer constant - indic adresa de nceput a tabloului
(adresa primului element)
int a [4];
este pointer de tip int *

Similar
numele unei funcii pointer constant - indic adresa de nceput a funciei
int functie ( float x);
este pointer de tip adres a unei funcii cu:
- rezultat de tip int
- un singur parametru de tip float
Prof. dr. ing. Daniela Saru

Curs - Programarea Calculatoarelor Anul I A

Facultatea Automatica si Calculatoare - UPB

Declararea variabilelor de tip pointer la funcie


int f (float);

/* prototipul funciei f , cu rezultat de tip int i un singur


parametru de tip float */

int (*adr_f) (float); /* declararea variabilei adr_f ca pointer de tip adres a unei
funcii cu rezultat de tip int i un singur parametru de tip float */
float x;
..
adr_f = f;

/*corect, f este o valoare pointer constant (nume de funcie)*/

adr_f = f(x);

/*greit, rezultatul funciei este o valoare de tip int */

adr_f = &f(x);

/*gresit, &f(x) este adresa rezultatului funciei (adresa unui int)*/

Prof. dr. ing. Daniela Saru

Curs - Programarea Calculatoarelor Anul I A

Facultatea Automatica si Calculatoare - UPB

Folosirea variabilelor de tip pointer la funcie


long factorial (int k);

/*prototipul funciei factorial*/

long (*adr_f) (int);

/*pointer la funcie*/

long fact;

int n = 3;
adr_f = factorial;

/*atribuire de valoare variabilei pointer la funcie*/

............
fact = (*adr_f) (n);

/*Apelarea funciei factorial cu ajutorul pointerului la


funcie;
Are efect similar cu: fact = factorial(n);
*/

Prof. dr. ing. Daniela Saru

Curs - Programarea Calculatoarelor Anul I A

Facultatea Automatica si Calculatoare - UPB

OBSERVATIE:
Trebuie avuta in vedere concordana dintre tipul funciei i tipul
variabilei pointer la funcie
La compilare - concordana se refer doar la tipul rezultatului
funciei
DAR
n faza de execuie - dac numrul i tipul parametrilor precizai
pentru funcie i pentru variabila pointer nu sunt identice, vor fi
semnalate erori

Prof. dr. ing. Daniela Saru

Curs - Programarea Calculatoarelor Anul I A

Facultatea Automatica si Calculatoare - UPB

Utilitatea variabilelor de tip pointer la funcie


Variabilele de tip pointer la funcie permit scrierea de funcii
i programe cu grad mare de generalitate.
Exemple:
Tablouri de pointeri la functii ce permit apelarea
indirecta a acestora

Functii polimorfice

Prof. dr. ing. Daniela Saru

Curs - Programarea Calculatoarelor Anul I A

Facultatea Automatica si Calculatoare - UPB

Tablouri de pointeri la functii ce permit apelarea indirecta a acestora


#include <stdio.h>
#include <math.h>
void main (void)
{ int i, nr;
double x;
double (* tablou [6] ) (double)= {sin, cos, tan, exp, log, log10};
nr = sizeof(tablou)/sizeof(tablou[0]);
for (x=0.01; x<1.01; x+=0.01)
{ for (i=0; i<nr; i++)
printf(%lf , (* tablou[i])(x));
printf(\n);
}
}

Obs:
tablou[i] este element al tabloului, deci este pointer la functie de tipul specificat;
(*tablou[i]) este chiar functia asociata;
(*tablou[i])(x) are acelasi efect ca apelarea functiei asociate.
De exemplu, (*tablou[0])(x) produce aceeasi valoare ca sin(x)

Prof. dr. ing. Daniela Saru

Curs - Programarea Calculatoarelor Anul I A

Facultatea Automatica si Calculatoare - UPB

Functii polimorfice exemplul nr. 1


Funcie de ordonare cresctoare:
void ord_cresc (int t[ ], int nr)
{ int i, aux, ordonat=0;
while ( ! ordonat )
{ ordonat=1;
for (i=0; i<nr-1; i++)
if (t[i] > t[i+1])
{aux = t[i];
t[i] = t[i+1];
t[i+1] = aux;
ordonat=0;
}
}
}

Funcie de ordonare descresctoare:


void ord_descresc (int t[ ], int nr)
{ int i, aux, ordonat=0;
while ( ! ordonat )
{ ordonat=1;
for (i=0; i<nr-1; i++)
if (t[i] < t[i+1])
{aux = t[i];
t[i] = t[i+1];
t[i+1] = aux;
ordonat=0;
}
}
}

??? Putem scrie:


o singur funcie care s realizeze ambele operaii de ordonare;
dou funcii ajuttoare care s compare cte dou valori i s dea ca rezultat:
valoarea 1 dac valorile comparate nu se afl n relaia dorit
valoarea 0, n caz contrar

Prof. dr. ing. Daniela Saru

Curs - Programarea Calculatoarelor Anul I A

Facultatea Automatica si Calculatoare - UPB

/*funcia de comparare a dou valori pentru ordonare cresctoare*/


int comp_cresc (int a, int b)
{ return a>b;
}
/*funcia de comparare a dou valori pentru ordonare descresctoare*/
int comp_descresc (int a, int b)
{ return a<b;
}
/*funcia de ordonare conine un parametru care arat ce tip de ordonare se
realizeaz. Parametrul va fi pointer la una dintre funciile de comparare scrise
anterior*/
void ordonare (int t[ ], int nr, int (*compar) (int, int))
void ord_cresc (int t[ ], int nr)
{ int i, aux, ordonat=0;
{ int i, aux, ordonat=0;
while ( ! ordonat )
while ( ! ordonat )
{ordonat=1;
{ ordonat=1;
for (i=0; i<nr-1; i++)
for (i=0; i<nr-1; i++)
if (t[i] > t[i+1])
if ( (*compar) (t[i], t[i+1]) )
{aux = t[i];
{aux = t[i];
t[i] = t[i+1];
t[i] = t[i+1];
t[i+1] = aux;
t[i+1] = aux;
ordonat=0;
ordonat=0;
}
}
}
}
}
}

Prof. dr. ing. Daniela Saru

Curs - Programarea Calculatoarelor Anul I A

Facultatea Automatica si Calculatoare - UPB

/*funcia main() cu utilizarea funciei de ordonare*/


void main (void)
{ int a[100], n,k;
/* ..... instruciunile pentru citirea de la tastatur a valorilor:
- n numrul de elemente din tabloul a;
- a[i], cu i=0, 1, ... n-1 */
printf(Valorile iniiale sunt:\n);
/* ..... instruciunile pentru afiarea valorilor a[i], cu i=0, 1, ... n-1*/
ordonare(a, n, comp_cresc);
printf(Valorile ordonate cresctor sunt:\n);
/* ..... instruciunile pentru afiarea valorilor a[i], cu i=0, 1, ... nr-1*/
ordonare(a, n, comp_descresc);
printf(Valorile ordonate descresctor sunt:\n);
/* ..... instruciunile pentru afiarea valorilor a[i], cu i=0, 1, ... n-1*/
}

Prof. dr. ing. Daniela Saru

Curs - Programarea Calculatoarelor Anul I A

Facultatea Automatica si Calculatoare - UPB

Functii polimorfice exemplul nr. 2


numarul de elemente din tablou
tabloul ce trebuie sortat
dimensiunea in numar de octeti a unui element
void qsort (void* tab, size_t n, size_t dim, int (*compar)(const void*, const void*));
1
2
pointer la o functie ce are ca
parametri adresele a 2 elemente din tablou (1 si 2) si trebuie sa returneze un
rezultat de tip int cu valoarea:
<0 dac 1 < 2
0 dac 1==2
>0 dac 1 > 2

Functie din biblioteca descrisa de stdlib.h


Implementeaza metoda QUICKSORT pentru sortarea (ordonarea) crescatoare a valorilor
unui tablou
Poate fi utilizata indiferent de tipul elementelor tabloului si de semnificatia notiunii de
relatie de ordine careia i se supun
Programatorul trebuie sa expliciteze intr-o functie scrisa de el insusi relatia de ordine
dorita, respectand restrictiile impuse de prototipul functiei
Prof. dr. ing. Daniela Saru

Curs - Programarea Calculatoarelor Anul I A

Facultatea Automatica si Calculatoare - UPB

De exemplu
numarul de elemente din tablou
tabloul ce trebuie sortat
dimensiunea in numar de octeti a unui element
void qsort (void* tab, size_t n, size_t dim, int (*compar)(const void*, const void*));
1
2
pointer la o functie ce are ca
parametri adresele a 2 elemente din tablou (1 si 2) si trebuie sa returneze un rezultat
de tip int cu valoarea:
<0 dac 1 < 2
0 dac 1==2
>0 dac 1 > 2

pentru sortarea crescatoare a unui tablou de valori intregi pozitive, functia de comparare a valorilor ar putea fi scrisa astfel:
int compar_numere (const void* a, const void* b)
{ return *((int*)a) - *((int*)b);
}
Sortarea unui tablou int t[100] cu nr elemente poate fi apoi realizata astfel:
qsort(t, nr, sizeof(int), compar_numere);

Prof. dr. ing. Daniela Saru

Curs - Programarea Calculatoarelor Anul I A

Facultatea Automatica si Calculatoare - UPB

Funcii cu rezultat de tip pointer


NU scriei astfel de funcii:
int * exemplu1 (void)
{ int b;
/* variabil local */
........
return &b;
}

int * exemplu2 (int k)


{ .......
return &k; /* k este parametru !!! */
}

Principala utilitate a funciilor ce dau rezultat de tip


pointer este alocarea de spaiu n memorie pentru aanumitele variabile dinamice ale programelor scrise n
limbaj C

Prof. dr. ing. Daniela Saru

Curs - Programarea Calculatoarelor Anul I A

Facultatea Automatica si Calculatoare - UPB

Alocarea dinamic a memoriei


Variabile statice
alocare la momentul compilrii (tip asociat)
compilatorul calculeaz i aloc spaiul de memorie necesar
Variabile dinamice
alocare n timpul execuiei programului (alocare dinamic)
zona de memorie: memorie heap
programatorul specific numrul de octei i cere explicit
programului s i aloce

Prof. dr. ing. Daniela Saru

Curs - Programarea Calculatoarelor Anul I A

Facultatea Automatica si Calculatoare - UPB

Operatorul sizeof( ) - Reamintire


sizeof(float)

inseamna 4 (octei), adic nr. de octei necesari pt.


reprezentarea intern a tipului float

float x;
sizeof (x)

???

float a[10];
sizeof(a)

???

sizeof (a[5]+7) ???

Prof. dr. ing. Daniela Saru

Curs - Programarea Calculatoarelor Anul I A

Facultatea Automatica si Calculatoare - UPB

Funcii de bibliotec destinate alocrii dinamice de


memorie, descrise n stdlib.h
tip predefinit, similar int, descris n stddef.h, stdlib.h, alloc.h,
mem.h, stdio.h, string.h
void * malloc (size_t dim);
dim = numrul de octei alocai unul dup altul
(continuu) n memorie
rezultatul este un pointer ctre nceputul zonei alocate sau NULL n caz de eec
(alocarea nu s-a putut face corect; de exemplu, nu exist suficient spaiu liber)

void * calloc (size_t n, size_t dim);


dim = numrul de octei ai fiecrui element
n = numrul de elemente ce vor fi memorate unul dup altul
idem malloc()
Obs.: in plus fata de malloc(), iniializeaz cu valoarea 0 octeii alocai

Prof. dr. ing. Daniela Saru

Curs - Programarea Calculatoarelor Anul I A

Facultatea Automatica si Calculatoare - UPB

void * realloc (void * bloc, size_t dim);


bloc = adresa blocului de memorie
alocat anterior printr-un apel malloc(),
calloc() sau realloc()
Redimensioneaz blocul de memorie alocat anterior (n plus sau minus), la
dim octei (dim va fi noua dimensiune a zonei de memorie alocate n urma
apelului funciei)
Rezultatul = adresa de nceput a zonei de memorie alocate alocate (care nu
coincide neaprat cu cea veche) sau NULL, dac alocarea nu a putut fi fcut

void free (void * bloc);


Elibereaz zona de memorie indicat de pointerul bloc.
Se aplic numai pentru zone de memorie ce au fost alocate prin folosirea
funciilor malloc(), calloc() sau realloc()

Prof. dr. ing. Daniela Saru

Curs - Programarea Calculatoarelor Anul I A

Facultatea Automatica si Calculatoare - UPB

RECOMANDARE: este bine s se testeze valoarea pointerului returnat (aflm dac


alocarea s-a fcut corect). Altfel, pot aprea erori de execuie a cror cauz este greu
de depistat!
#include<stdio.h>
#include<stdlib.h>
/* pentru funciile de alocare dinamic */

int * p;
p = (int*) calloc (1000, sizeof(int));
if( p == NULL)
{ printf(alocare euat!);
exit(1);
}

int * q;
/* variabil ajuttoare */
..........
for (q=p; q < p+1000; q++)
*q = 1;
..........

???

Rolul variabilei ajuttoare

Prof. dr. ing. Daniela Saru

???

Curs - Programarea Calculatoarelor Anul I A

Facultatea Automatica si Calculatoare - UPB

Problema rezolvata
Scriei un program n care:
- s citii de la tastatur dimensiunile l (numr de linii) i c (numr de
coloane) pentru 2 matrice;
- s alocai dinamic spaiu de memorie pentru elementele celor 2 matrice
- s citii de la tastatur valorile matricelor
- s memorai valorile citite n spaiul alocat anterior
- s calculai i s afiai pe ecran valorile matricei sum a celor 2 matrice
void
void
void
void

Testare(int * p);
CitesteMatrice(int * a, int n);
AfiseazaMatrice(int * a, int m, int n);
SumaMatrice(int * a, int * b, int * c, int n);

Prof. dr. ing. Daniela Saru

Curs - Programarea Calculatoarelor Anul I A

Facultatea Automatica si Calculatoare - UPB

#include <stdio.h>
#include <stdlib.h>
void Testare(int * p);
void CitesteMatrice(int * a, int n);
void AfiseazaMatrice(int * a, int m, int n);
void SumaMatrice(int * a, int * b, int * c, int n);
void main (void)
{ int l, c, *pa, *pb, *pc, dim;
printf("Cate linii? ");
scanf("%d", &l);
printf("Cate coloane? ");
scanf("%d", &c);
dim=l*c*sizeof(int);
pa=(int*)malloc(dim);
Testare(pa);
pb=(int*)malloc(dim);
Testare(pb);
pc=(int*)malloc(dim);
Testare(pc);
printf("Tastati valorile primei matrice:");
CitesteMatrice(pa,l*c);
printf("Tastati valorile celei de-a doua matrice:");
CitesteMatrice(pb,l*c);
SumaMatrice(pa,pb,pc,l*c);
AfiseazaMatrice(pc,l,c);
free(pa);
free(pb);
free(pc);
}
Prof. dr. ing. Daniela Saru

Curs - Programarea Calculatoarelor Anul I A

Facultatea Automatica si Calculatoare - UPB

void Testare(int * p)
{ if (p==NULL)
{printf("Alocare dinamica de memorie esuata\n");
exit(1);
}
}
void CitesteMatrice(int * a, int n)
{ int* sfarsit=a+n;
while (a<sfarsit)
scanf("%d", a++);
}
void AfiseazaMatrice(int * a, int m, int n)
{ int * inceput=a, *sfarsit=a+m*n;
while (a<sfarsit)
printf(((a-inceput)%n==n-1) ? "%6d\n" : "%6d", *a++);
}
void SumaMatrice(int * a, int * b, int * c, int n)
{ int *sfarsit=a+n;
while (a<sfarsit)
*c++=*a++ + *b++;
}

Prof. dr. ing. Daniela Saru

Curs - Programarea Calculatoarelor Anul I A

Facultatea Automatica si Calculatoare - UPB

OBSERVATIE FOARTE UTILA


Alocarea spatiului in heap face posibila folosirea valorilor
depuse in zona de catre orice functie a programului.
La limita, zona poate fi alocata de o functie, folosita de
alta si eliberata de alta.
Important este ca functiile respective sa cunoasca adresa
zonei din heap cu care se lucreaza.

ATENTIE !!! Pot sa apara erori greu de depistat in cazul


folosirii necorespunzatoare a acestei zone, la fel ca si in
cazul variabilelor globale

Prof. dr. ing. Daniela Saru

Curs - Programarea Calculatoarelor Anul I A

Facultatea Automatica si Calculatoare - UPB

#include <stdio.h>
#include <stdlib.h>
void Testare(int * p);
void CitesteMatrice(int * a, int n);
void AfiseazaMatrice(int * a, int m, int n);
void ModificaMatrice(int * a, int n);
void main (void)
{ int l, c, *pa, dim;
printf("Cate linii? "); scanf("%d", &l);
printf("Cate coloane? "); scanf("%d", &c);
dim=l*c*sizeof(int);
pa=(int*)malloc(dim);
Testare(pa);
printf("Tastati valorile matricei:");
CitesteMatrice(pa,l*c);
ModificaMatrice(pa,l*c);
printf("Valorile matricei modificate:\n");
AfiseazaMatrice(pa,l,c);
free(pa);
}
void Testare(int * p)
{ if (p==NULL)
{printf("Alocare din. de memorie esuata\n");
exit(1);
}
}
void CitesteMatrice(int * a, int n)
{ int* sfarsit=a+n;
while (a<sfarsit)
scanf("%d", a++);
}
void ModificaMatrice(int * a, int n)
{ int* sfarsit=a+n;
while (a<sfarsit)
{ * a = 55;
a += 2;
}
}
void AfiseazaMatrice(int * a, int m, int n)
{ int * inceput=a, *sfarsit=a+m*n;
while (a<sfarsit)
printf(((a-inceput)%n==n-1) ? "%6d\n" : "%6d", *a++);
}

Prof. dr. ing. Daniela Saru

Curs - Programarea Calculatoarelor Anul I A

Facultatea Automatica si Calculatoare - UPB