DOMANDA Puntatori A Funzione Dubbi

Robert T.

Utente Attivo
134
11
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
653
279
CPU
Intel i5 3570K @ 4,5Ghz
Dissipatore
Scythe Mugen 2
Scheda Madre
Gigabyte Z77X-UD3H
HDD
Samsung 840 PRO 256GB + Sandisk Ultra 250GB + Sandisk Plus 960GB
RAM
2x8GB Crucial Ballistix Tactical @2000Mhz CL9
GPU
XFX RX480 GTR Black Edition
Audio
Auzentech X-Fi Forte
Monitor
AOC i2369VW
PSU
Seasonic P660
Case
eh?
Periferiche
Razer Naga HEX v2
OS
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
134
11
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
653
279
CPU
Intel i5 3570K @ 4,5Ghz
Dissipatore
Scythe Mugen 2
Scheda Madre
Gigabyte Z77X-UD3H
HDD
Samsung 840 PRO 256GB + Sandisk Ultra 250GB + Sandisk Plus 960GB
RAM
2x8GB Crucial Ballistix Tactical @2000Mhz CL9
GPU
XFX RX480 GTR Black Edition
Audio
Auzentech X-Fi Forte
Monitor
AOC i2369VW
PSU
Seasonic P660
Case
eh?
Periferiche
Razer Naga HEX v2
OS
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

Moderatore
Staff Forum
Utente Èlite
2,208
1,845
CPU
Intel I9-10900KF 3.75GHz 10x 125W
Dissipatore
Gigabyte Aorus Waterforce X360 ARGB
Scheda Madre
Asus 1200 TUF Z590-Plus Gaming ATX DDR4
HDD
1TB NVMe PCI 3.0 x4, 1TB 7200rpm 64MB SATA3
RAM
DDR4 32GB 3600MHz CL18 ARGB
GPU
Nvidia RTX 3080 10GB DDR6
Audio
Integrata 7.1 HD audio
Monitor
LG 34GN850
PSU
Gigabyte P850PM
Case
Phanteks Enthoo Evolv X ARGB
Periferiche
MSI Vigor GK30, mouse Logitech
Net
FTTH Aruba, 1Gb (effettivi: ~950Mb / ~480Mb)
OS
Windows 10 64bit / OpenSUSE Tumbleweed
Vedo due errori: il for esterno di bubble, ed il for del main. Entrambi devono essere inizializzati a 1, altrimenti ti perdi un valore.
 

Robert T.

Utente Attivo
134
11
Vedo due errori: il for esterno di bubble, ed il for del main. Entrambi devono essere inizializzati a 1, altrimenti ti perdi un valore.

Grazie mille, alla fine ho trovato l'errore che impallava il tutto.

Praticamente nella funzione bubble non ho messo size - 1. Il che richiamava una posizione inesistente cioè la 10.
 

DispatchCode

Moderatore
Staff Forum
Utente Èlite
2,208
1,845
CPU
Intel I9-10900KF 3.75GHz 10x 125W
Dissipatore
Gigabyte Aorus Waterforce X360 ARGB
Scheda Madre
Asus 1200 TUF Z590-Plus Gaming ATX DDR4
HDD
1TB NVMe PCI 3.0 x4, 1TB 7200rpm 64MB SATA3
RAM
DDR4 32GB 3600MHz CL18 ARGB
GPU
Nvidia RTX 3080 10GB DDR6
Audio
Integrata 7.1 HD audio
Monitor
LG 34GN850
PSU
Gigabyte P850PM
Case
Phanteks Enthoo Evolv X ARGB
Periferiche
MSI Vigor GK30, mouse Logitech
Net
FTTH Aruba, 1Gb (effettivi: ~950Mb / ~480Mb)
OS
Windows 10 64bit / OpenSUSE Tumbleweed
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
134
11
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

Moderatore
Staff Forum
Utente Èlite
2,208
1,845
CPU
Intel I9-10900KF 3.75GHz 10x 125W
Dissipatore
Gigabyte Aorus Waterforce X360 ARGB
Scheda Madre
Asus 1200 TUF Z590-Plus Gaming ATX DDR4
HDD
1TB NVMe PCI 3.0 x4, 1TB 7200rpm 64MB SATA3
RAM
DDR4 32GB 3600MHz CL18 ARGB
GPU
Nvidia RTX 3080 10GB DDR6
Audio
Integrata 7.1 HD audio
Monitor
LG 34GN850
PSU
Gigabyte P850PM
Case
Phanteks Enthoo Evolv X ARGB
Periferiche
MSI Vigor GK30, mouse Logitech
Net
FTTH Aruba, 1Gb (effettivi: ~950Mb / ~480Mb)
OS
Windows 10 64bit / OpenSUSE Tumbleweed
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
134
11
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

Moderatore
Staff Forum
Utente Èlite
2,208
1,845
CPU
Intel I9-10900KF 3.75GHz 10x 125W
Dissipatore
Gigabyte Aorus Waterforce X360 ARGB
Scheda Madre
Asus 1200 TUF Z590-Plus Gaming ATX DDR4
HDD
1TB NVMe PCI 3.0 x4, 1TB 7200rpm 64MB SATA3
RAM
DDR4 32GB 3600MHz CL18 ARGB
GPU
Nvidia RTX 3080 10GB DDR6
Audio
Integrata 7.1 HD audio
Monitor
LG 34GN850
PSU
Gigabyte P850PM
Case
Phanteks Enthoo Evolv X ARGB
Periferiche
MSI Vigor GK30, mouse Logitech
Net
FTTH Aruba, 1Gb (effettivi: ~950Mb / ~480Mb)
OS
Windows 10 64bit / OpenSUSE Tumbleweed
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
Discord Ufficiale Entra ora!