POINTERI SPRE FUNCŢII

 

      Numele unei funcţii este un pointer spre funcţia respectivă. El poate fi folosit ca parametru efectiv la apeluri de funcţii. În felul acesta, o funcţie poate transfera funcţiei apelate un pointer spre o funcţie. Aceasta, la rândul ei, poate apela funcţia care i-a fost transferată în acest fel. 

Exemplu:

Un exemplu matematic în care este nevoie de un astfel de transfer este cel cu privire la calculul aproximativ al integralelor definite. Să presupunem că dorim să calculăm integrala definită din funcţia f(x), între limitele a şi b, folosind formula trapezului:

I= h((f(a)+f(b))/2 +f(a+h)+f(a+2h)+. . . +f(a+(n-1)h)

unde 

h=(b-a)/h. 

      În continuare construim o funcţie care calculează partea dreaptă a acestei relaţii. Numim aria_trapez această funcţie.

Observaţii:

1o. Deoarece funcţia f(x) din relaţia de mai sus nu este definită în acest moment, ea trebuie să figureze printre parametrii funcţiei aria_trapez, împreună cu limitele de integrare şi valoarea lui n.

2o. Funcţia aria_trapez returnează valoarea aproximativă a integralei şi ea se va apela printr-o expresie de atribuire, de exemplu:

aria=aria_trapez (a, b, n, f);

3o. Funcţia aria_trapez returnează o valoare flotantă în dublă precizie. De asemenea, şi funcţia f(x) returnează o valoare flotantă în dublă precizie. De aici rezultă că prototipul funcţiei aria_trapez este următorul:

double aria_trapez (double a, double b, int n, double (*f)());

sau

double aria_trapez (double, double, int , double (*)());

4o. Este necesar ca înaintea apelului funcţiei aria_trapez funcţia f(x) să fie definită sau să fie prezent prototipul ei , de exemplu:

double f();

5o. Construcţia double (*f) () se interpretează în felul următor:

- *f        înseamnă că f este un pointer;

- (*f)()          înseamnă că f este un pointer spre o funcţie;

- double (*f) () înseamnă că f este un pointer spre o funcţie care returnează o valoare flotantă în dublă precizie.

6o. Trebuie să se includă *f între paranteze, deoarece construcţia double *f(); este corectă, dar înseamnă altceva, parantezele rotunde fiind prioritare operatorului unar *. În acest caz, se declară f ca o funcţie ce returnează un pointer spre o valoare flotantă în dublă precizie.

7o. Ultimul parametru formal al funcţiei aria_trapez corespunde parametrului efectiv f şi deci el trebuie declarat ca şi pointer spre o funcţie ce returnează o valoare flotantă în dublă precizie. Conform observaţiei 5), dacă p este numele parametrului formal ce corespunde parametrului efectiv f, atunci p se declară astfel:

double (*p)();

8o. În corpul funcţiei aria_trapez va trebui să apelăm funcţia f(x) pentru a calcula valorile:

f(a), f(b), f(a+h), . . . , f(a+(n-1)h).

În momentul programării funcţiei aria_trapez, nu se cunoaşte numele funcţiei concrete, ci numai pointerul p spre ea. De aceea, vom înlocui numele funcţiei prin *p, deci vom folosi apelurile:

(*p)(a), (*p)(b), (*p)(a+h), . . . ,(*p)(a+(n-1)h) 

double aria_trapez(double x, double y, int m, double(*p)());

            {           double h,s;

                       int i;

                       h=(y-x)/m;

                       for (i=1, s=0.0; i<m; i++) s+=(*p)(x+i*h);

                       s+=((*p)(x) + (*p)(y))/2;

                       s=h*s;

                       return s;

Vom utiliza funcţia aria_trapez pentru a calcula integrala definită din funcţia sin(x2) pe intervalul [0,1], cu o eroare mai mică decât 10-8. Vom nota cu In următoare sumă: 

In= h((f(a)+f(b))/2 +f(a+h)+f(a+2h)+. . . +f(a+(n-1)h) 

Paşii algoritmului sunt următorii:

Pasul 1. Se alege o valoare iniţială pentru n, de exemplu 10.

Pasul 2. Se calculează In.

Pasul 3. Se calculează I2n prin dublarea lui n.

Pasul 4. Dacă |In-I2n| < 10-8, algoritmul se întrerupe şi valoarea integralei, cu precizia admisă, este I2n; altfel se dublează n, se pune In=I2n; n, şi se trece la pasul 3. 

#define A 0.0

#define B 1.0

#define N 10

#define EPS 1e-8

#include <stdio.h>

#include <math.h>

double sinxp(double);              // prototipul functiei sin(x*x)

double aria_trapez(double, double, int, double (*)());

void main (void)                                   // functia principala

{ int n=N;

 double in, i2n, vabs;

 in=aria_trapez (A, B, n, sinxp);

 do {

n=n*2;

i2n=aria_trapez(A, B, n, sinxp);

if ((vabs= in-i2n) < 0)    vabs = -vabs;

in=i2n;

 } while (vabs >= EPS);

 printf (“valoarea integralei este : %g.10\n”,i2n);

}

double aria_trapez(double x, double y, int m, double(*p)());

{           double h,s;

            int i;

            h=(y-x)/m;

            for (i=1, s=0.0; i<m; i++)           s+=(*p)(x+i*h);

            s+=((*p)(x) + (*p)(y))/2;

            s=h*s;

            return s;

double sinxp (double x)

{ return sin (x*x); }