laborator 12 - pointeri la functii

Upload: dima-zaharia

Post on 05-Apr-2018

216 views

Category:

Documents


0 download

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.