laborator 12 - pointeri la functii
TRANSCRIPT
-
7/31/2019 Laborator 12 - Pointeri La Functii
1/10
PROGRAMAREA CALCULATOARELOR Lucrarea nr. 12
1
POINTERI LA FUNCII
1. Declararea unui pointer la o funcie
Pointerii folosii pn acum au fost pointeri la diferite tipuri de date, dar este posibil
s avem i pointeri la funcii. Pointerii la funcii sunt folosii din aceleai motive ca i
pointerii la date: atunci cnd se dorete un alt nivel de indirectare, cnd dorim ca aceeai
secven de cod s apeleze funcii diferite depinznd de condiiile concrete ale
programului.
Ca i n cazul pointerilor la date, pentru utilizarea pointerilor la func ii trebuie s
declarm o variabil care s conin un pointer la funcie. Un pointer la o funcie se
declar astfel:
tip (*pf)(tip1 p1, tip2 p2, ..., tipn pn);
unde
tip este tipul funciei (tipul valorii returnate de funcie)
tip1 p1, tip2 p2, ..., tipn pn este lista parametrilor funciei care va fi accesat prin
intermediul pointerului. Numele parametrilor, adicp1, p2, ..., pnpot lipsi.
Exemplu, dac scriem
int (*pfi)(float a, int b);
se declar pfi ca fiind un pointer la o funcie care va returna un ntreg. Ca i n altedeclaraii * indic faptul c avem un pointer, iar( ) arat c avem de a face cu o funcie.
Parantezele din (*pfi) sunt necesare deoarece i n declaraii exist o anumit preceden
a operatorilor (o anumit ordine de evaluare interpretare) ca i n expresii i cnd
ordinea implicit nu este cea dorit, trebuie s o schimbm folosind parantezele de
explicitare. n declaraii, ( ) - operatori de funcie i [ ] - operatorii de indexare sunt mai
prioritari dect * indicnd pointerii. Fr parantezele menionate, declaraia de mai sus
arat astfel:
int *pfi(float a, int b);i declar o funcie pfi care va returna un pointer la ntreg. Cu parantezele explicite, int
(*pfi)() ne spune cpfi este mai nti un pointer, c acest pointer indic o funcie i mai
apoi c funcia respectiv returneaz un ntreg.
Pointerii la funcii se pot defini i ca noi tipuri de date prin utilizarea declaraiei de tip
typedef. De exemplu, putem scrie
typedef int (*FPTR)(float a, int b);
-
7/31/2019 Laborator 12 - Pointeri La Functii
2/10
PROGRAMAREA CALCULATOARELOR Lucrarea nr. 12
2
i identificatorul FPTR este un sinonim pentru tipul de dat pointer la o funcie care
returneaz un ntreg, astfel nct declaraia
FPTR pfi;
este echivalent cu
int (*pfi)(float a, int b);
O dat declarat, unui pointer la funcie i se poate atribui valoarea adresei de nceput
a funciei dorite. Dac avem prototipurile urmtoarelor funcii
int f1(float a, int b);
int f2(float a, int b);
int f3(float a, int b);
atunci putem scrie:
pfi = &f1;
sau
if (conditie)
pfi = &f2;
else
pfi = &f3;
Bineneles, nu vom fi restrni la aceste dou forme, putem asigna pointeri la funcii
n orice condiii dorim. Al doilea exemplu poate fi scris mai compact:
pfi = conditie ? &f2 : &f3;
n aceste exemple am folosit operatorul &, aa cum am fcut pn acum pentru a
genera un pointer. Totui cnd generm pointeri la funcii, operatorul & este opional,
deoarece atunci cnd menionm numele unei funcii fr s o apelm menionm de fapt
adresa funciei respective, numele unei funcii fiind de fapt un pointer la funcia dat. Astfel
se poate scrie:
pfi = f1;
sau
if (conditie)
pfi = f2;else
pfi = f3;
sau
pfi = conditie ? f2 : f3;
-
7/31/2019 Laborator 12 - Pointeri La Functii
3/10
PROGRAMAREA CALCULATOARELOR Lucrarea nr. 12
3
Faptul c un pointer la o funcie este generat automat cnd o funcie apare ntr-o
expresie, dar nu este apelat este asemntor, i de fapt este de legat de faptul c un
pointer la primul element al unui vector este generat automat atunci cnd un vector apare
ntr-o expresie.
Avnd o variabil pointer la o funcie care conine adresa unei funcii, putem apela
(folosi) funcia respectiv astfel:
1. scriem numele variabilei pointer la funcie
pfi
2. se folosete operatorul * n fa pentru "a accesa coninutul acelui pointer"
*pfi
Aceast expresie reprezint tocmai funcia pe care dorim s o folosim.
3. adugm lista de parametri n paranteze mpreun cu un set de paranteze
pentru a avea precedena dorit a operaiilor:
(*pfi)(arg1, arg2)
Formm astfel apelul la funcie.
Parantezele din expresia (*pfi) au aceeai explicaie ca la declararea pointerului la o
funcie. Dac scriem
*pfi(arg1, arg2)
interpretarea este: apeleaz funcia pfi (care va returna un pointer), transfer-i
argumentele arg1 i arg2 i ia coninutul de la adresa indicat de variabila pointer la
ntoarcere. Totui ceea ce dorim s facem este urmtorul lucru: ia coninutul lui pfi (care
este un pointer la o funcie), apeleaz funcia spre care pointeaz, transmindu-i
argumentele arg1 i arg2. Din nou, parantezele explicite schimb precedena implicit,
astfel nct se aplic mai nti operatorul *i apoi se apeleaz funcia.
Expresia
pfi(arg1, arg2)
este echivalent cu
(*pfi)(arg1, arg2).
Atunci cnd apelm o funcie indicat de un pointer la funcie, operatorul * esteopional. Este recomandabil folosirea lui pentru a scoate n evidena faptul c folosim un
pointer la funcie i nu funcia propriu-zis.
Pentru fiecare funcie folosit trebuie s avem un prototip pentru a permite
compilatorului s genereze corect codul pentru apelul funciilori s verifice dac funcia
este apelat cu numrul i tipul adecvat pentru argumente.
-
7/31/2019 Laborator 12 - Pointeri La Functii
4/10
PROGRAMAREA CALCULATOARELOR Lucrarea nr. 12
4
n general nu se va ti dect n momentul rulrii programului care este funcia
pointat de pfi, astfel nct compilatorul nu poate verifica dac apelul s-a fcut corect. Pe
de alt parte, atunci cnd am declarat un pointer la funcie a trebuit s declarm tipul
valorii returnate de funcia respectiv. De asemenea, putem declara prototipul
argumentelor folosite de funcie, adic putem scrie:
int (*pfi)(float a, int b);
Acum tim cpfi este un pointer la o funcie care accept dou argumente i care
returneaz un ntreg. Avnd toate acestea specificate, compilatorul va putea s verifice
corectitudinea anumitor apeluri pentru funcia respectiv. De exemplu, dac scriem:
(*pfi)(1, 2, 3)
compilatorul va semnaliza eroare, pentru c el tie c funcia nu poate accepta dect dou
argumente. De asemenea, compilatorul va verifica dac funciile spre care pointeaz
variabila pointer la funcie au lista de argumente i valoarea de retur n concordan cu
declaraia pentru pointer.
Deci pentru o variabil pointer la funcie trebuie s declar att tipul valorii returnate,
ct i tipul argumentelor din lista de argumente.
Alte exemple de construire a pointerilor la funcii:
double (*a)(int);
float (*b)(char *);
int * (*f1)(double, int);
double *(*f2)(char *, int , double *);
2. Pointeri la funcii ca argumente n alte funcii
n continuare s presupunem c o funcie fare ca parametru o funcie g. Dac se
scrie:
f(g);
nseamn c lui fi se transmite un pointer la funcia g.
Dac prototipul funciei g este
tip_g g(lista_g);atunci prototipul funciei fn care g este parametru va fi
tip_f f(tip_g (*g)(lista_g));
sau
tip_f f(tip_g (*)(lista_g));
iar definiia funciei fva fi
tip_f f(tip_g (*p)(lista_g)) { .}
-
7/31/2019 Laborator 12 - Pointeri La Functii
5/10
PROGRAMAREA CALCULATOARELOR Lucrarea nr. 12
5
unde (*p) poate fi i (*g).
Exemple:
int g(double);
double f(int (*)(double));
22..11.. EExxeemmpplluu
2.1.1. Calculul ariei domeniului mrginit de graficul unei funcii
Valoarea ariei domeniului mrginit de graficul unei funcii este valoarea integralei
acelei funcii, valoare calculat lund ca limite capetele intervalului de reprezentare.
Fie funcia, considerat fr bucle:
[ ] Rbaf ,: (1)
Pentru calculul integralei se va folosi metoda trapezelor. Intervalul [a,b] va fi mprit
n n diviziuni, astfel c mrimea unei diviziuni va fi:
n
abdx
= (2)
Punctele xi se vor calcula cu expresia:
dxxdxiaxii
+=+= 1 cu 1,,1 = ni K (3)
iar aria corespunztoare unei diviziuni (aria parial) este:
( ) ( )( )
ii
ii
ixx
xfxfA
+= +
+1
1
2 (4)
Integrala se obine ca sum a ariilor pariale:
( ) ( )( )
+
+
==
=
=
1
1
1
0 2
n
i
i
n
i
inxf
bfaf
n
abAI (5)
Aceast modalitate de calcul a ariei este acelai, indiferent de expresia funciei f.
Dac vom lua n considerare de fiecare dat forma funciei f va trebui s scriem o funcie
care calculeaz integrala pentru fiecare funcie pe care trebuie s o utilizm. Pointerii la
funcii ne permit s transmitem ca parametru funcia pentru care vrem s calculm
integrala astfel nct vom lua n considerare urmtorul prototip:
double integralaTrapez(double a, double b, int n, double (*f)(double));n care:
a, b reprezint capetele intervalului de integrare
n numrul de diviziuni ale intervalului
f pointer la o funcie care primete un parametru de tip double i returneaz o
valoare de tip double. Aceast funcie calculeaz valorile funciei pentru care vrem s
-
7/31/2019 Laborator 12 - Pointeri La Functii
6/10
PROGRAMAREA CALCULATOARELOR Lucrarea nr. 12
6
calculm integrala ntr-un punct specificat ca parametru. Funcia poate fi o funcie proprie
sau o funcie din biblioteca matematic (de exemplu sin, sqrt, etc).
Funcia integralaTrapez implementeaz formula (5) i are forma:
double integralaTrapez(double a, double b, int n, double (*f)(double))
{
double val; // Valoarea integralei
double dx = (b-a)/n;
double x;
val = ((*f)(a) + (*f)(b))/2;
for(x=a+dx; x
-
7/31/2019 Laborator 12 - Pointeri La Functii
7/10
PROGRAMAREA CALCULATOARELOR Lucrarea nr. 12
7
Exemplu: s se scrie un program care tabeloeaz funciile trigonometrice sin, asin,
cos, acos, tan, atan ntre 0 i 1 rad cu pasul de 0.05.
#include
#include
int main(void)
{
double (*fm[])(double x) = {
sin, asin, cos, acos, tan, atan};
int i;
double x;
double dx = 0.05;
int nf = sizeof(fm)/sizeof(fm[0]);
puts("Tabelul");
for(x=0; x
-
7/31/2019 Laborator 12 - Pointeri La Functii
8/10
PROGRAMAREA CALCULATOARELOR Lucrarea nr. 12
8
struct S1 {
................ /* declaraii pentru ali membri */
FM f; /* echivalent cu double (*f) (double x); */
................ /* declaraii pentru ali membri */
};
Putem construi astfel o structur care s conin numele unei funcii i un pointer la
funcia respectiv. Exemplu:
struct functii {
char *nume;
double (*f) (double x);
};
n programul principal putem iniializa un tablou de astfel de structuri pentru a-l folosi
la construirea unui meniu. Exemplu:
struct functii tab_f[] = {
{"sinus", sinus},
{"cosinus", cos},
{"tangenta", tan} };
Definiia funciei pentru construirea meniului este:
void meniu(struct functii tab[], int nf, char *msg)
{
int i;
clrscr();
puts(msg);
for(i=0; i
-
7/31/2019 Laborator 12 - Pointeri La Functii
9/10
PROGRAMAREA CALCULATOARELOR Lucrarea nr. 12
9
TEMA
PPrroobblleemmaa nnrr.. 11
Folosind tablouri de pointeri la funcii, s se scrie un program care tabeleaz funciile
de bibliotec sinus, cosinus i tangent pentru valori cuprinse ntre 0 i cu un pas egal
cu /20.
PPrroobblleemmaa nnrr.. 22
S se calculeze urmtoarele integrale:
+1
1
2)3sin( dxxx
( ) ++2
0
24 dxexx
x
Indicaie:Se va folosi pentru calculul integralei funcia integralaTrapez prezentat la curs.
PPrroobblleemmaa nnrr.. 33
S se declare o structurnorme care conine ca membri un pointer la caracteri un
pointer la o funcie care returneaz un double i primete ca parametri un pointer la double
i un ntreg (dup modelul structurii functii dat mai sus).
S se scrie un program care calculeaz, pentru un tablou unidimensional (vector)
urmtoarele norme:
ixx max=
- norma infinit
nxxxx +++= ...211 - norma 1
22
2
2
12...
nxxxx +++= - norma 2
Programul definete i iniializeaz (dup modelul dat mai sus) un tablou de structuri
norme cu numele i funciile care calculeaz cele trei norme, afieaz un meniu care
folosete acest tablou de structuri, iar prelucrarea dorit se va face prin intermediul
pointerilor la funcii.
Se poate folosi, ca exemplu, funcia meniu dat mai sus.
PPrroobblleemmaa nnrr.. 44
S se defineasc o funcie generic de ordonare a unui ir de date (metoda folosit
este metoda bulelor). Funcia primete ca parametri adresa zonei de memorie unde se
-
7/31/2019 Laborator 12 - Pointeri La Functii
10/10
PROGRAMAREA CALCULATOARELOR Lucrarea nr. 12
10
gsete irul de date (un pointer generic), numrul de date care se ordoneaz,
dimensiunea unui element din ir, precum i un pointer la o funcie care realizeaz
compararea a dou elemente din ir.
S se defineasc o funcie generic de interschimbare a dou elemente dintr-un ir
de date (funcie ce poate fi folosit pe orice tip de date).
Folosind aceste funcii s se scrie un program care face ordonarea unor date citite
de la tastaturi afieazirul ordonat pe monitor. Aceste date pot fi: un ir de numere
reale n dubl precizie sau un text.
Atenie! Trebuie scris o singur funcie de ordonare (sortare) care va fi folosit
att pentru sortarea textului ct i a irului de date numerice i o singur funcie de
interschimbare.
PPrroobblleemmaa nnrr.. 55
Se reia Problema nr. 4 folosind funcia de bibliotecqsort.