Sunteți pe pagina 1din 23

Pointeri la funcţii

Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / eslides rev. 2021 108
Particularităţi 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 funcţii ≡ pointer constant - indică adresa de început a funcţiei


int functie ( float x);
este pointer de tip adresă a unei funcţii cu:
- rezultat de tip int
- un singur parametru de tip float

Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 108 bis
Declararea variabilelor de tip pointer la funcţie

int f (float); /* prototipul funcţiei 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
funcţii 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 funcţie)*/
adr_f = f(x); /*greşit, rezultatul funcţiei este o valoare de tip int */
adr_f = &f(x); /*gresit, &f(x) este adresa rezultatului funcţiei (adresa unui int)*/

Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 109
Folosirea variabilelor de tip pointer la funcţie

long factorial (int k); /*prototipul funcţiei factorial*/


long (*adr_f) (int); /*pointer la funcţie*/
long fact;
int n = 3;
adr_f = factorial; /*atribuire de valoare variabilei pointer la funcţie*/
............
fact = (*adr_f) (n); /*Apelarea funcţiei factorial cu ajutorul pointerului la
funcţie;
Are efect similar cu: fact = factorial(n);
*/

Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 109
OBSERVATIE:

Trebuie avuta in vedere concordanţa dintre tipul funcţiei şi tipul


variabilei pointer la funcţie

La compilare - concordanţa se referă doar la tipul rezultatului


funcţiei

DAR…

În faza de execuţie - dacă numărul şi tipul parametrilor precizaţi


pentru funcţie şi pentru variabila pointer nu sunt identice, vor fi
semnalate erori

Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 110
Utilitatea variabilelor de tip pointer la funcţie

Variabilele de tip pointer la funcţie permit scrierea de funcţii


şi programe cu grad mare de generalitate.

Exemple:

Tablouri de pointeri la functii ce permit apelarea


indirecta a acestora

Functii polimorfice

Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 110
Tablouri de pointeri la functii ce permit apelarea indirecta a acestora
#include <stdio.h> Tabl_Point_Fct.c
#include <math.h>
int 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”);
}
return 0;
}

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)

Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 111
Functii polimorfice – exemplul nr. 1
Funcţie de ordonare crescătoare: Funcţie de ordonare descrescătoare:
void ord_cresc (int t[ ], int nr) void ord_descresc (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 (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;
} }
} }
} }

??? Putem scrie:


 o singură funcţie care să realizeze ambele operaţii de ordonare;
 două funcţii ajutătoare care să compare câte două valori şi să dea ca rezultat:
 valoarea 1 dacă valorile comparate nu se află în relaţia dorită
 valoarea 0, în caz contrar

Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 111
/*funcţia de comparare a două valori pentru ordonare crescătoare*/
int comp_cresc (int a, int b)
{ return a>b;
}

/*funcţia de comparare a două valori pentru ordonare descrescătoare*/


int comp_descresc (int a, int b)
{ return a<b;
}

/*funcţia de ordonare – conţine un parametru care arată ce tip de ordonare se


realizează. Parametrul va fi pointer la una dintre funcţiile 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 ( (*compar) (t[i], t[i+1]) ) if (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;
}
} }
} }
}

Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 112
/*funcţia main() cu utilizarea funcţiei de ordonare*/
int main (void)
{ int a[100], n,k;

/* ..... instrucţiunile pentru citirea de la tastatură a valorilor:


- n – numărul de elemente din tabloul a;
- a[i], cu i=0, 1, ... n-1 */

printf(”Valorile iniţiale sunt:\n”);


/* ..... instrucţiunile pentru afişarea valorilor a[i], cu i=0, 1, ... n-1*/

ordonare(a, n, comp_cresc);
printf(”Valorile ordonate crescător sunt:\n”);
/* ..... instrucţiunile pentru afişarea valorilor a[i], cu i=0, 1, ... nr-1*/

ordonare(a, n, comp_descresc);
printf(”Valorile ordonate descrescător sunt:\n”);
/* ..... instrucţiunile pentru afişarea valorilor a[i], cu i=0, 1, ... n-1*/
}

Fct_Polimorf.c

Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 112
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

Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 113
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 compa-
rare 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);

Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 113
Funcţii cu rezultat de tip pointer
NU scrieţi astfel de funcţii:

int * exemplu1 (void) int * exemplu2 (int k)


{ int b; /* variabilă locală */ { .......
........ return &k; /* k este parametru !!! */
return &b;
} }

Principala utilitate a funcţiilor ce dau rezultat de tip


pointer este alocarea de spaţiu în memorie pentru aşa-
numitele variabile dinamice ale programelor scrise în
limbaj C

Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 114
Alocarea dinamică a memoriei

Variabile statice
– alocare la momentul compilării (tip asociat)
– compilatorul calculează şi alocă spaţiul de memorie necesar

Variabile dinamice
– alocare în timpul execuţiei programului (alocare dinamică)
– zona de memorie: memorie heap
– programatorul specifică numărul de octeţi şi cere explicit
programului să îi aloce

Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 114
Operatorul sizeof( ) - Reamintire

sizeof(float) inseamna 4 (octeţi), adică nr. de octeţi necesari pt.


reprezentarea internă a tipului float

float x; ???
sizeof (x)

float a[10]; ???


sizeof(a)

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

Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 115
Funcţii de bibliotecă destinate alocării 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 = numărul de octeţi alocaţi unul după altul
(continuu) în memorie
rezultatul este un pointer către începutul zonei alocate sau NULL în caz de eşec
(alocarea nu s-a putut face corect; de exemplu, nu există suficient spaţiu liber)

void * calloc (size_t n, size_t dim);


dim = numărul de octeţi ai fiecărui element
n = numărul de elemente ce vor fi memorate unul după altul
idem malloc()

Obs.: in plus fata de malloc(), iniţializează cu valoarea 0 octeţii alocaţi

Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 115
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 octeţi (dim va fi noua dimensiune a zonei de memorie alocate în urma
apelului funcţiei)

Rezultatul = adresa de început a zonei de memorie alocate alocate (care nu


coincide neapărat cu cea veche) sau NULL, dacă alocarea nu a putut fi făcută

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
funcţiilor malloc(), calloc() sau realloc()

Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 116
RECOMANDARE: este bine să se testeze valoarea pointerului returnat (aflăm dacă
alocarea s-a făcut corect). Altfel, pot apărea erori de execuţie a căror cauză este greu
de depistat!
#include<stdio.h>
#include<stdlib.h> /* pentru funcţiile de alocare dinamică */
………
int * p;
p = (int*) calloc (1000, sizeof(int));
if( p == NULL)
{ printf(“alocare eşuată!”);
exit(1);
}
………

int * q; /* variabilă ajutătoare */


..........
for (q=p; q < p+1000; q++)
*q = 1;
..........

??? Rolul variabilei ajutătoare ???

Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 116
Problema rezolvata

Scrieţi un program în care:


- să citiţi de la tastatură dimensiunile l (număr de linii) şi c (număr de
coloane) pentru 2 matrice;
- să alocaţi dinamic spaţiu de memorie pentru elementele celor 2 matrice
- să citiţi de la tastatură valorile matricelor
- să memoraţi valorile citite în spaţiul alocat anterior
- să calculaţi şi să afişaţi pe ecran valorile matricei sumă a celor 2 matrice

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);

Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 117
#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);

int 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);
return 0;
}

Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 117
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);
a++; /*incrementam a in afara apelului printf(), ca sa nu apara efecte secundare!*/
}
}

void SumaMatrice(int * a, int * b, int * c, int n)


{ int *sfarsit=a+n;
while (a<sfarsit) SUMA_M_D.c

*c++=*a++ + *b++;
}
Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 118
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

Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 118
#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; heap.c
while (a<sfarsit)
{printf(((a-inceput)%n==n-1) ? "%6d\n" : "%6d", *a);
a++;
}
}

Daniela Saru - "Programarea calculatoarelor. Note de curs” – Ed. Printech, 2011 / slides rev. 2021 119

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