DOMANDA Puntatori A Funzione Dubbi

Robert T.

Utente Attivo
Qualcuno potrebbe delucidarmi alcuni dubbi sui puntatori a funzione?

1)qual'è la loro utilità.
2) come mai riesco a chiamare "compare" nel main anche senza i parametri?
3) cos'è quella cosa arcana fatta con compare nel prototipo di bubble?
4)Che processi svolge di diverso rispetto ad un esercizio senza puntatori a funzione?

Grazie mille. Sono alquanto tosti sti puntatori a funzione :suicidio:



Codice:
// fig07_26.cpp : definisce il punto di ingresso dell'applicazione console.
// Programma di ordinamente multifunzione che fa uso dei puntatori a funzioni

#include <stdio.h>
#define SIZE 10

//Prototipi di funzione

void bubble(int work[], const int size, int(*compare) (int a, int b));
int ascending(int a, int b);
int descending(int a, int b);


int main()
{

    int order; // 1 per ordinamento ascendente 2 per quello discendente
    int counter; // contatore

    // inizializza il vettore a

    int a[SIZE] = { 2,5,3,6,1,5,8,0,6,1 };

    printf("Enter 1 to sort ascending order\n" "Enter 2 to sort descending order: \n");
        scanf_s("%d", &order);

        printf("\nData items printed in original order");

        for (counter = 1; counter < SIZE; counter++) {
            printf("%5d", a[counter]);
        }

        // Ordina il vettore in ordine ascendente; passa la funzione ascending
        // come argomento per specificare l'ordinamento ascendente
    
        if (order == 1) {
            bubble(a, SIZE, ascending);
            printf("\nData items in ascending order");
        }

        else
        {
            bubble(a, SIZE, descending);
            printf("\nData items in descending order");
        }

        // visualizza il vettore ordinato

        for (counter = 0; counter < SIZE; counter++) {
            printf("%5d", a[counter]);
        }

        printf("\n");

    return 0;
}

/** Bubble sort multifunzione: Il parametro compare è un puntatore a una funzione di comparazione che determina il senso
dell'ordinamento **/

void bubble(int work[], const int size, int (*compare) (int a, int b)) {

    int pass; //contatore dei passaggi
    int count; //contatore dei confronti

    void swap(int *element1Ptr, int *element2Ptr); // prototipo

    // ciclo per controllare i passaggi

    for (pass = 1; pass < size; pass++) {

        // ciclo per controllare i confronti

        for (count = 0; count < size; count++)
        {
            // Scambia gli elementi adicenti se non sono in ordine

            if ( (*compare) (work[count], work[count + 1]) ) {
                swap(&work[count], &work[count + 1]);
            }
        }
    }
}

// Scambia i valori nelle locazioni di memoria puntate da element1Ptr e element2Ptr

void swap(int *element1Ptr, int *element2Ptr) {
 
    int hold; // variabile temporanea

    hold = *element1Ptr;
    *element1Ptr = *element2Ptr;
    *element2Ptr = hold;
}


// Determina se gli elementi non sono in ordine rispetto a un ordinamento ascendente

int ascending(int a, int b) {
    return b < a; // effettua uno scambio se b è minore di a
}

// Determina se gli elementi sono in ordine rispetto a un ordinamento discendente

int descending(int a, int b) {
    return b > a;
}
 

1nd33d

Utente Attivo
652
279
Hardware Utente
CPU
Intel i5 3570K @ 4,5Ghz
Dissipatore
Scythe Mugen 2
Scheda Madre
Gigabyte Z77X-UD3H
Hard Disk
Samsung 840 PRO 256GB + Sandisk Ultra 250GB + Sandisk Plus 960GB
RAM
2x8GB Crucial Ballistix Tactical @2000Mhz CL9
Scheda Video
XFX RX480 GTR Black Edition
Scheda Audio
Auzentech X-Fi Forte
Monitor
AOC i2369VW
Alimentatore
Seasonic P660
Case
eh?
Periferiche
Razer Naga HEX v2
Sistema Operativo
Windows 10 64bit - Linux Mint 18
1)3)4) In realtà sono abbastanza semplici, è più difficile spiegarle che altro...
In generale serve per separare un blocco di codice da un altro che lo utilizza. Nel caso particolare l'utilità è che se non usassi i puntatori a funzione, ad ogni ciclo for di bubble dovresti fare un check sul fatto che l'ordinamento sia crescente o decrescente. Con il puntatore a funzione invece gli passi direttamente il codice che esegue il confronto (che è già quello giusto scelto nel main) e la funzione bubble non deve controllare nulla.
Codice:
(*compare) (work[count], work[count + 1])
non fa altro che chiamare la funzione puntata da "compare" passandogli quei due parametri.

Senza puntatori a funzione dovresti scrivere qualcosa del genere (non testato)
Codice:
if ((order == 1 && work[count] > work[count + 1]) or (order != 1 && work[count] < work[count + 1]) ) {
   swap(&work[count], &work[count + 1]);
}
e quindi fai da uno a 3 check in più per ogni iterazione for.
Oppure
Codice:
if (order == 1){
   for (pass = 1; pass < size; pass++) {
        // ciclo per controllare i confronti
        for (count = 0; count < size; count++)
        {
            // Scambia gli elementi adicenti se non sono in ordine
            if ( work[count] > work[count + 1]) {
                swap(&work[count], &work[count + 1]);
            }
        }
    }
}else{
   for (pass = 1; pass < size; pass++) {
        // ciclo per controllare i confronti
        for (count = 0; count < size; count++)
        {
            // Scambia gli elementi adicenti se non sono in ordine
            if ( work[count] < work[count + 1]) {
                swap(&work[count], &work[count + 1]);
            }
        }
    }
}
che è lunga il doppio (tra order == 1 e order != 1 cambia solo il < con > ) ma forse più veloce, in quanto ti risparmi l'invocazione di *compare ad ogni iterazione.

2) nel main non stai chiamando "compare", stai solo passando il suo indirizzo, cioè la sua "chiusura" (un record di attivazione)

L'utilità è relativa... io le eviterei se non strettamente necessario (spesso non lo è).
 
Ultima modifica:

Robert T.

Utente Attivo
1)3)4) In realtà sono abbastanza semplici, è più difficile spiegarle che altro...
In generale serve per separare un blocco di codice da un altro che lo utilizza. Nel caso particolare l'utilità è che se non usassi i puntatori a funzione, ad ogni ciclo for di bubble dovresti fare un check sul fatto che l'ordinamento sia crescente o decrescente. Con il puntatore a funzione invece gli passi direttamente il codice che esegue il confronto (che è già quello giusto scelto nel main) e la funzione bubble non deve controllare nulla.
Codice:
(*compare) (work[count], work[count + 1])
non fa altro che chiamare la funzione puntata da "compare" passandogli quei due parametri.

Senza puntatori a funzione dovresti scrivere qualcosa del genere (non testato)
Codice:
if ((order == 1 && work[count] > work[count + 1]) or (order != 1 && work[count] < work[count + 1]) ) {
   swap(&work[count], &work[count + 1]);
}
e quindi fai da uno a 3 check in più per ogni iterazione for.
Oppure
Codice:
if (order == 1){
   for (pass = 1; pass < size; pass++) {
        // ciclo per controllare i confronti
        for (count = 0; count < size; count++)
        {
            // Scambia gli elementi adicenti se non sono in ordine
            if ( work[count] > work[count + 1]) {
                swap(&work[count], &work[count + 1]);
            }
        }
    }
}else{
   for (pass = 1; pass < size; pass++) {
        // ciclo per controllare i confronti
        for (count = 0; count < size; count++)
        {
            // Scambia gli elementi adicenti se non sono in ordine
            if ( work[count] < work[count + 1]) {
                swap(&work[count], &work[count + 1]);
            }
        }
    }
}
che è lunga il doppio (tra order == 1 e order != 1 cambia solo il < con > ) ma forse più veloce, in quanto ti risparmi l'invocazione di *compare ad ogni iterazione.

2) nel main non stai chiamando "compare", stai solo passando il suo indirizzo, cioè la sua "chiusura" (un record di attivazione)

L'utilità è relativa... io le eviterei se non strettamente necessario (spesso non lo è).
Per lo più il codice mio sopra non funziona, non capisco il perchè?
 

1nd33d

Utente Attivo
652
279
Hardware Utente
CPU
Intel i5 3570K @ 4,5Ghz
Dissipatore
Scythe Mugen 2
Scheda Madre
Gigabyte Z77X-UD3H
Hard Disk
Samsung 840 PRO 256GB + Sandisk Ultra 250GB + Sandisk Plus 960GB
RAM
2x8GB Crucial Ballistix Tactical @2000Mhz CL9
Scheda Video
XFX RX480 GTR Black Edition
Scheda Audio
Auzentech X-Fi Forte
Monitor
AOC i2369VW
Alimentatore
Seasonic P660
Case
eh?
Periferiche
Razer Naga HEX v2
Sistema Operativo
Windows 10 64bit - Linux Mint 18
Non l'ho proprio provato... ma ti da un errore in compilazione o a runtime? Che errore? Oppure non fa quel che ti aspetti?
 

DispatchCode

Utente Attivo
593
342
Hardware Utente
CPU
Intel i7 6700HQ, 2.60Ghz, 4 core 8 threads
Scheda Madre
Asustek
Hard Disk
Hitachi 7200 rpm, 1TB
RAM
16GB DDR4 (2 slot su 4)
Scheda Video
Nvidia Geforce GTX 960M, 4GB
Scheda Audio
Realtek
Sistema Operativo
Windows 10 64bit
Vedo due errori: il for esterno di bubble, ed il for del main. Entrambi devono essere inizializzati a 1, altrimenti ti perdi un valore.
 

DispatchCode

Utente Attivo
593
342
Hardware Utente
CPU
Intel i7 6700HQ, 2.60Ghz, 4 core 8 threads
Scheda Madre
Asustek
Hard Disk
Hitachi 7200 rpm, 1TB
RAM
16GB DDR4 (2 slot su 4)
Scheda Video
Nvidia Geforce GTX 960M, 4GB
Scheda Audio
Realtek
Sistema Operativo
Windows 10 64bit
C'è stato un mio lapsus nel mio post precedente...
Volevo dirti di inizializzare a 0 il primo for di stampa, ed avevo dubbi sul for innestato nella funzione bubble.

Comunque, per quanto riguarda la condizione di terminazione, se size=10 scorre le posizioni dalla 0 alla 9 (comprese), quindi posizioni esistenti.
 

Robert T.

Utente Attivo
C'è stato un mio lapsus nel mio post precedente...
Volevo dirti di inizializzare a 0 il primo for di stampa, ed avevo dubbi sul for innestato nella funzione bubble.

Comunque, per quanto riguarda la condizione di terminazione, se size=10 scorre le posizioni dalla 0 alla 9 (comprese), quindi posizioni esistenti.
No perchè poi c'è l'array[i + 1]
 

DispatchCode

Utente Attivo
593
342
Hardware Utente
CPU
Intel i7 6700HQ, 2.60Ghz, 4 core 8 threads
Scheda Madre
Asustek
Hard Disk
Hitachi 7200 rpm, 1TB
RAM
16GB DDR4 (2 slot su 4)
Scheda Video
Nvidia Geforce GTX 960M, 4GB
Scheda Audio
Realtek
Sistema Operativo
Windows 10 64bit
Vero, usi il +1.

Ad ogni modo il tuo vecchio codice l'ho provato, mi compila, e funziona. Probabilmente funziona proprio perchè va a leggere nell'indice successivo all'array e trova un'area sporca (che ha sicuramente un valore ben più grande di quelli settati nell'array), ma comunque accessibile.

Ps. ad ogni modo il ciclo è eseguito comunque 10 volte (è proprio quell'incremento a creare il problema). Potresti anche iniziare da 1, ed al posto di fare +1, fare un -1.
 

Robert T.

Utente Attivo
Vero, usi il +1.

Ad ogni modo il tuo vecchio codice l'ho provato, mi compila, e funziona. Probabilmente funziona proprio perchè va a leggere nell'indice successivo all'array e trova un'area sporca (che ha sicuramente un valore ben più grande di quelli settati nell'array), ma comunque accessibile.

Ps. ad ogni modo il ciclo è eseguito comunque 10 volte (è proprio quell'incremento a creare il problema). Potresti anche iniziare da 1, ed al posto di fare +1, fare un -1.
Non posso iniziare da 1 altrimenti salterei la posizione 0 del vettore.

Sarebbe tipo vettore 1 scambia con vettore 2 e non più 0 ed 1.
 

DispatchCode

Utente Attivo
593
342
Hardware Utente
CPU
Intel i7 6700HQ, 2.60Ghz, 4 core 8 threads
Scheda Madre
Asustek
Hard Disk
Hitachi 7200 rpm, 1TB
RAM
16GB DDR4 (2 slot su 4)
Scheda Video
Nvidia Geforce GTX 960M, 4GB
Scheda Audio
Realtek
Sistema Operativo
Windows 10 64bit
Per questo dicevo di fare poi -1 al posto di +1, così considereresti la posizione 0 e la posizione 1.
Alla fine è solo un modo diverso per fare la stessa cosa però. ;)
 

Entra

oppure Accedi utilizzando