Visualizzazione dei risultati da 1 a 10 su 10
  1. #1

    [C] Differenza tra due dichiarazioni di funzione

    Salve,
    qualcuno saprebbe dirmi nello specifico cosa fanno ambedue le dchiarazioni e quindi la differenza tra una e l'altra funzione?

    codice:
    int ( *compare )( int a, int b )
    int *compare( int a, int b )
    Vi ringrazio in anticipo,
    Neptune.
    "Estremamente originale e fantasioso" By darkiko;
    "allora sfiga crepuscolare mi sa che e' meglio di atmosfera serale" By NyXo;
    "per favore, già è difficile con lui" By fcaldera;
    "se lo apri te e invece di "amore" ci metti "lavoro", l'effetto è lo stesso" By fred84

  2. #2
    Tra l'altro nell'esercizio lo utilizza in questo modo:

    Questi sono i prototipi delle funzioni:
    codice:
    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 );

    Questa è invece una chiamata a funzione:

    codice:
    bubble( a, SIZE, ascending );
    Questa è la dichiarazione delle funzioni ma credo che sia "marginale" come vengono dichiarate a questo punto:

    codice:
    void bubble( int work[], const int size, 
                 int (*compare)( int a, int b ) )
    {
       int pass;  /* pass counter */
       int count; /* comparison counter */
    
       void swap( int *element1Ptr, int *element2ptr ); /* prototype */
    
       /* loop to control passes */
       for ( pass = 1; pass < size; pass++ ) {
    
          /* loop to control number of comparisons per pass */
          for ( count = 0; count < size - 1; count++ ) {
    
             /* if adjacent elements are out of order, swap them */
             if ( (*compare)( work[ count ], work[ count + 1 ] ) ) {
                swap( &work[ count ], &work[ count + 1 ] );
             } /* end if */
    
          } /* end for */
    
       } /* end for */
    
    } /* end function bubble */
    
    /* swap values at memory locations to which element1Ptr and 
       element2Ptr point */
    void swap( int *element1Ptr, int *element2Ptr )
    {
       int hold; /* temporary holding variable */
    
       hold = *element1Ptr;
       *element1Ptr = *element2Ptr;
       *element2Ptr = hold;
    } /* end function swap */
    
    /* determine whether elements are out of order for an ascending
       order sort */
    int ascending( int a, int b )
    {
       return b < a;   /* swap if b is less than a */
    
    } /* end function ascending */
    
    /* determine whether elements are out of order for a descending
       order sort */
    int descending( int a, int b )
    {
       return b > a;   /* swap if b is greater than a */
    
    }
    "Estremamente originale e fantasioso" By darkiko;
    "allora sfiga crepuscolare mi sa che e' meglio di atmosfera serale" By NyXo;
    "per favore, già è difficile con lui" By fcaldera;
    "se lo apri te e invece di "amore" ci metti "lavoro", l'effetto è lo stesso" By fred84

  3. #3
    Utente di HTML.it L'avatar di oregon
    Registrato dal
    Jul 2005
    residenza
    Roma
    Messaggi
    36,462

    Re: [C] Differenza tra due dichiarazioni di funzione

    codice:
    int ( *compare )( int a, int b )
    Puntatore ad una funzione che restituisce un int e accetta due int

    codice:
    int *compare( int a, int b )
    Funzione che restituisce un puntatore ad int e accetta due int
    No MP tecnici (non rispondo nemmeno!), usa il forum.

  4. #4

    Re: Re: [C] Differenza tra due dichiarazioni di funzione

    Originariamente inviato da oregon
    codice:
    int ( *compare )( int a, int b )
    Puntatore ad una funzione che restituisce un int e accetta due int

    codice:
    int *compare( int a, int b )
    Funzione che restituisce un puntatore ad int e accetta due int
    Cioè il secondo caso, ovvero questo:
    codice:
    int *compare( int a, int b )
    Mi sembra il più banale, ovvero è una semplice funzione che, passandogli due interi, restituisce come risultato un puntatore, ovvero ci sarà come ritorno un

    codice:
    return *puntatore;
    Giusto?

    Il secondo caso invece non mi è molto chiaro, come fa un puntatore a puntare ad una funzione, a cosa punta? potresti farmi un esempio pratico?
    "Estremamente originale e fantasioso" By darkiko;
    "allora sfiga crepuscolare mi sa che e' meglio di atmosfera serale" By NyXo;
    "per favore, già è difficile con lui" By fcaldera;
    "se lo apri te e invece di "amore" ci metti "lavoro", l'effetto è lo stesso" By fred84

  5. #5
    Un puntatore a funzione è una variabile che contiene l'indirizzo di una funzione, che tramite esso può essere richiamata. È utilizzato dal codice che hai riportato per permettere al chiamante di fornire una sua funzione di confronto personalizzata; la chiamata della funzione in questione la trovi alla riga
    codice:
             if ( (*compare)( work[ count ], work[ count + 1 ] ) ) {
    dalla sintassi apparentemente contorta ma coerente con la sintassi solita dei puntatori: il puntatore a funzione viene dereferenziato, consentendo così la chiamata a funzione.
    Tendenzialmente comunque si cerca di evitare di specificare i parametri di tipo puntatore a funzione in quella maniera perché sono abbastanza illeggibile; di solito infatti si usano dei typedef per renderli un po' meno ostici.
    I puntatori a funzione, oltre che per situazioni come questa, si usano moltissimo per consentire al chiamante di specificare una funzione di callback, per esempio per notificarlo dell'avanzamento di un'operazione o del verificarsi di un evento.
    Amaro C++, il gusto pieno dell'undefined behavior.

  6. #6
    Originariamente inviato da MItaly
    Un puntatore a funzione è una variabile che contiene l'indirizzo di una funzione, che tramite esso può essere richiamata. È utilizzato dal codice che hai riportato per permettere al chiamante di fornire una sua funzione di confronto personalizzata; la chiamata della funzione in questione la trovi alla riga
    codice:
             if ( (*compare)( work[ count ], work[ count + 1 ] ) ) {
    dalla sintassi apparentemente contorta ma coerente con la sintassi solita dei puntatori: il puntatore a funzione viene dereferenziato, consentendo così la chiamata a funzione.
    Tendenzialmente comunque si cerca di evitare di specificare i parametri di tipo puntatore a funzione in quella maniera perché sono abbastanza illeggibile; di solito infatti si usano dei typedef per renderli un po' meno ostici.
    I puntatori a funzione, oltre che per situazioni come questa, si usano moltissimo per consentire al chiamante di specificare una funzione di callback, per esempio per notificarlo dell'avanzamento di un'operazione o del verificarsi di un evento.
    Riguardando il codice effettivamente ero riuscito a capirlo, particamente così facendo puoi passare nel parametro "puntatore" una funzione, e magari, scegliere di volta in volta che funzione passargli come parametro.

    Ho visto un esempio, molto più capibile, che implementavano questo passaggio di puntatore a funzione per l'utilizzo in un menù:

    Praticamente era il classico ciclo while che a seconda della scelta del menù richiamava una funzione, però in realtà si richiamava "un vettore di puntatori a funzione" e la scelta del menù era l'indice di questo vettore.

    Nel caso citato prima invece non riuscivo a capirne il nesso perchè aveva veramente poco senso la cosa. Secondo me bisognerebbe spiegare le potenzialità di una funzione mostrandone l'utilizzo per "un azione" che non si potrebbe fare in altro modo. Mostrare la via più complicata di una cosa semplice diventa illogico e quindi difficile da capire.
    "Estremamente originale e fantasioso" By darkiko;
    "allora sfiga crepuscolare mi sa che e' meglio di atmosfera serale" By NyXo;
    "per favore, già è difficile con lui" By fcaldera;
    "se lo apri te e invece di "amore" ci metti "lavoro", l'effetto è lo stesso" By fred84

  7. #7
    Originariamente inviato da Neptune
    Nel caso citato prima invece non riuscivo a capirne il nesso perchè aveva veramente poco senso la cosa. Secondo me bisognerebbe spiegare le potenzialità di una funzione mostrandone l'utilizzo per "un azione" che non si potrebbe fare in altro modo. Mostrare la via più complicata di una cosa semplice diventa illogico e quindi difficile da capire.
    Ha così poco senso che anche la funzione di libreria C per l'ordinamento (qsort) usa lo stesso approccio...
    Seriamente, nelle operazioni di ordinamento è fondamentale consentire al chiamante di specificare una funzione di confronto: l'algoritmo infatti è sempre lo stesso, indifferentemente dal criterio scelto per l'ordinamento, e in questa maniera anche se voglio ordinare il mio insieme per qualche criterio strano (ordine ascendente, discendente, distanza da un certo numero, ...) posso farlo.
    Amaro C++, il gusto pieno dell'undefined behavior.

  8. #8
    Originariamente inviato da MItaly
    Ha così poco senso che anche la funzione di libreria C per l'ordinamento (qsort) usa lo stesso approccio...
    Seriamente, nelle operazioni di ordinamento è fondamentale consentire al chiamante di specificare una funzione di confronto: l'algoritmo infatti è sempre lo stesso, indifferentemente dal criterio scelto per l'ordinamento, e in questa maniera anche se voglio ordinare il mio insieme per qualche criterio strano (ordine ascendente, discendente, distanza da un certo numero, ...) posso farlo.
    Allora devo prenderci la mano, perchè devo ammettere di non aver mai fatto un puntatore ad una funzione.
    "Estremamente originale e fantasioso" By darkiko;
    "allora sfiga crepuscolare mi sa che e' meglio di atmosfera serale" By NyXo;
    "per favore, già è difficile con lui" By fcaldera;
    "se lo apri te e invece di "amore" ci metti "lavoro", l'effetto è lo stesso" By fred84

  9. #9
    Utente di HTML.it
    Registrato dal
    Jul 2008
    Messaggi
    1,326
    Originariamente inviato da MItaly
    Ha così poco senso che anche la funzione di libreria C per l'ordinamento (qsort) usa lo stesso approccio...
    Seriamente, nelle operazioni di ordinamento è fondamentale consentire al chiamante di specificare una funzione di confronto: l'algoritmo infatti è sempre lo stesso, indifferentemente dal criterio scelto per l'ordinamento, e in questa maniera anche se voglio ordinare il mio insieme per qualche criterio strano (ordine ascendente, discendente, distanza da un certo numero, ...) posso farlo.
    E' anche vero però che la funzione qsort() utilizza i puntatori a void per rendere *effettivamente* generico l'algoritmo di ordinamento, cioè tale da poter ordinare array di qualsiasi tipo (anche array di strutture definite dall'utente) semplicemente passando come parametro una funzione che "istruisca" la qsort() su come operare i confronti.

    Nell'esempio postato dal nostro amico questo viene a mancare perché la funzione parametro riceve in input due interi, e non genericamente due puntatori void. La cosa vuole semplicemente servire a far scegliere all'utente il tipo di ordinamento (crescente o decrescente) ma in effett in quel caso i puntatori a funzione non sono poi tanto utili... magari con un semplice parametro booleano si poteva risolvere la cosa: 0 -> ordinamento crescente; 1 -> ordinamento decrescente. Poi sarebbe bastato differenziare i casi all'interno della funzione stessa. Voleva essere forse solo un semplice esempio di utilizzo dei puntatori a funzione, sebbene in una situazione in cui potevano essere evitati.
    every day above ground is a good one

  10. #10
    Certo, infatti a questo punto la possibilità è limitata a diversi generi di ordinamento tra interi, per cui tra gli esempi che ho citato se noti ho messo giusto ordine ascendente, discendente e (un po' più esoterico) ordine di distanza da un altro numero; potrei aggiungere, che so, un ordinamento che metta prima i numeri pari e poi i dispari, oppure un ordinamento che confronti il valore assoluto dei numeri; un callback di questo genere ti dà comunque una certa flessibilità (che ovviamente non è quella della generica funzione qsort).

    Per inciso, per questo genere di cose è comunque stato dimostrato che i template C++ e i suoi functori battono i puntatori a funzioni C in grande stile, sia per eleganza (dal momento che il functore può accettare direttamente il tipo corretto senza bisogno di fare mille cast da void *) che per velocità. Infatti il codice di un functore passato come argomento template può essere messo inline dal compilatore all'interno dell'algoritmo di ordinamento, tagliando sull'overhead della chiamata a funzione mediante puntatore, il che sui grandi numeri si sente, visto che spesso la funzione di confronto è composta praticamente da una singola istruzione.
    Amaro C++, il gusto pieno dell'undefined behavior.

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2024 vBulletin Solutions, Inc. All rights reserved.