Friday, November 27, 2015

Limbajul C. Pointeri la functii. Un mic reminder al algoritmului GCD (Greatest Common Divisor)

O functie este stocata in memorie la o adresa, exact ca o variabila iar adresa functiei respective se obtine utilizand numele functiei, fara paranteze si parametri formali, exact cum utilizam numele unui tablou pentru a asigna adresa sa unui pointer la tipul elementelor tabloului. 

Faptul ca o functie este stocata (incarcata) de compilator la o anumita adresa permite utilizarea unui pointer la functia respectiva.

Sintaxa declararii unui pointer la functie:

tip_return_functie (* ptrf)( lista_de_parametri_formali_ai_functiei );

Prima pereche de paranteze este necesara intrucat, in absenta acestor paranteze, declaratia respectiva ar fi prototipul unei functii numite ptrf cu lista specificata de parametri si care intoarce un pointer la tip_return_functie.

Ex:
#include <stdio.h>
……
int i;
int  (* ptrf)(const char * s1, const char * s2);
ptrf = strcmp; // ptrf indica acum spre strcmp
……
i = (* ptrf)(s1, s2); // apelul functiei prin intermediul pointerului
// i = ptrf(s1, s2);

// Linia comentata anterior este varianta echivalenta de apel

In continuare un mic reminder al algoritmului GCD si codul care implementeaza o functie de calcul a GCD, apelata printr-un pointer.

Pentru a, b numere intregi pozitive nenule in relatia de ordine a >= b executam urmatoarea succesiune de operatii, folosind teorema impartirii cu rest (oricare a, b in conditiile de mai sus, exista si sunt unici intregii b1, r cu proprietatea ca a = b x b1 + r) si schimband deimpartitul cu impartitorul si impartitorul cu restul la fiecare iteratie

a = b x b1 + r

b = r x b2 + r1

r = r1 x b3 + r2
........

r_n = r_(n+1) x b_(n+3) // r_(n+2) = 0 adica oprim iteratiile cand restul devine nul

Pentru simplitate, presupunem ca obtinem rest nul la a treia iteratie, adica r2 = 0.

Atunci,

r = r1 x b3; b = r1 x b3 x b2 + r1 = r1 x (b3 x b2 + 1)

a = r1 x (b3 x b2 + 1) x b1 + r1 x b3 = r1 x (b3 x b2 x b1 + b1 + b3) 

Deci r1, ultimul rest nenul, este GCD.

Codul si printscreen-ul executiei:

#include <stdio.h>

unsigned GCD(unsigned, unsigned);

int main()

{
            unsigned a, b, c, temp;
            unsigned (* ptrf)(unsigned, unsigned);
            ptrf = GCD;
            puts("Dati doi intregi pozitivi nenuli a si b separati de virgula. Vom determina GCD.");
            scanf("%u, %u", &a, &b);
            _flushall();
            if(a <= b) {temp = a; a = b; b = temp;}
            c = (* ptrf)(a, b);
            printf("\nGCD al %u si %u este %u.\n", a, b, c);
            return 0;
}

unsigned GCD(unsigned a, unsigned b)

{
            unsigned temp;
            while(b)
            {
                        temp = b;
                        b = a%b;
                        a = temp;
            }
            return temp;
}


No comments:

Post a Comment