Puntatori a Funzione[C]

Linguaggi di programmazione: php, perl, python, C, bash e tutti gli altri.
Avatar utente
vbextreme
Entusiasta Emergente
Entusiasta Emergente
Messaggi: 1214
Iscrizione: domenica 12 gennaio 2014, 14:06
Desktop: lxde
Distribuzione: xubuntu 14.10

Re: Puntatori a Funzione[C]

Messaggio da vbextreme »

però ugualmente non capisco perchè non posso passare il puntatore a funzione come si fa nelle liste e poi usare il doppio **
e come no?
Ora te lo spiego alla mia maniera,che tecnicamente è errata ma praticamente fa capire molto:

Codice: Seleziona tutto

int* BETA;
void(*BETA)(void);
La prima riga dichiara un puntatore BETA e la seconda un puntatore a funzione BETA,teoricamente sarebbe stato piu semplice poter dichiarare un puntatore a funzione cosi:

Codice: Seleziona tutto

void()(void)* BETA;
Ovvero {TIPO NOMEVARIABILE} Ma non si può fare!
Il compilatore vuole la forma { RETURNTYPE( * NOMEVARIABILE)(PARAMETRI) }
Lo vedi l'asterisco? ecco è un puntatore e se fai & lo passi per indirizzo e quindi pttieni un puntatore a puntatore di funzione proprio come si fa con le variabili.
[EDIT]
Ora eccoti delle egualianze non per tipo di variabile creata ma per come si dichiarano:
Dichiarazioni equivalenti

Codice: Seleziona tutto

int BETA == void(BETA)(void) == void BETA(void) // variabile reale e quindi funzione reale
int* BETA == void(*BETA)(void) //puntatore
int** BETA == void(**BETA)(void) //puntatore puntatore
Spiegato?
[/EDIT]
Ora se io voglio Un puntatore a puntatore come dovrei fare?

Codice: Seleziona tutto

int** BETA;
e per il puntatore a funzione?

Codice: Seleziona tutto

void(**BETA)(void);
Eccoti un esempio col doppio puntatore che mostra anche come le typedef semplificano il codice e la sua lettura:

Codice: Seleziona tutto

typedef void(*PFNC)(void);

void stampaA()
{
    printf("a");
}

void stampaB()
{
    printf("b");
}

void cambia(PFNC* f)
{
    *f = stampaB;
}

void esteso( void(**f)(void) )
{
    *f = stampaB;
}

int main()
{
    PFNC z = stampaA;
    cambia(&z);
    z();

    void(*festesa)(void) = stampaA;
    esteso(&festesa);
    festesa();

    return 0;
}
Spero di essermi spiegato.
Ora per risolvere l'esercizio devi solo modificare un pochino la tua proposta didattica.Non devi fare altro che mettere il primo parametro a void,il secondo in modo da accettare la qsort ed il terzo per accettare la compare.
Easy framework per il linguaggio C.
vbextreme hack your life
gila75
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2739
Iscrizione: mercoledì 16 gennaio 2013, 17:28
Desktop: ubuntu-2d
Distribuzione: Ubuntu 12.04.2 LTS i686
Località: Airuno(Lecco)

Re: Puntatori a Funzione[C]

Messaggio da gila75 »

Grazie vbextreme. Non mi riusciva il fatto del puntatore a puntatore per un errore banale. Ora è ok.
Domanda, ma nel tuo esercizio, cosa intendi di preciso?
dal main passo l'array e il puntatore a funzione che contiene l'algoritmo di ordinamento (supponiamo qsort) e da quella funzione, sempre tramite puntatore a funzione
passo alla funzione di confronto?
Presumo che il risultato della funzione nel main dovrà tener traccia degli scambi, visto che il vettore viene ordinato da qsort.
E ti possino...e tu lo chiami esercizio semplice :D
Usare le define al posto di typedef può andare bene?

Codice: Seleziona tutto

#define CMP int (**cmp)(const void*, const void*)
....
int *quick (int *a,int *array,int n, int size, CMP) 
magari non raffinato come typedf, ma aumenta la leggibilità ,no?
Lo so che non sono la stessa cosa le macro e le typedf...
Mi sa che ci passerò parecchio su sto argomento.
Alla fine il casino del C sono i puntatori e le funzioni (saperle padroneggiare bene intendo) gira tutto li ho capito..quindi conviene soffermarsi un po'
Avatar utente
vbextreme
Entusiasta Emergente
Entusiasta Emergente
Messaggi: 1214
Iscrizione: domenica 12 gennaio 2014, 14:06
Desktop: lxde
Distribuzione: xubuntu 14.10

Re: Puntatori a Funzione[C]

Messaggio da vbextreme »

il problema del conteggio dei confronti lo affrontiamo sucessivamente.

Cosa sarebbe quella funzione quick e soprattutto perché**?

Procediamo per gradi.
Inanzitutto diamo un nome alla funzione che vogliamo creare, es 'dinamicsort' o 'dsort'
Ora io inizio il prototipo e tu lo continui seguendo le linee dell'esercizio,leggilo attentamente,ho sempre scritto puntatori a funzione e non puntatore a puntatore di funzione.

Codice: Seleziona tutto

int dsort(void* v, size_t n, size_t sz,?ptrfncsort?,?ptrfnccmp?);
Ora dove vedi i punti interrogativi devi metterci i puntatori a funzione quello di compare l'hai gia scritto qualche messaggio sopra, ti manca solo quello della qsort.
Un trucco per non sbagliare é il seguente
1)prendo il prototipo di una funzione
int unafnz(int par,char v)
2)metto il nome tra parentesi
int (unafnz)(int par,char v)
3)lo trasformo in puntatore
int (*unafnz)(int par,char v)
4)tolgo i nomi dalle variabili
int (*unafnz)(int,char)
5)gli cambio nome per sicurezza
int (*myfnz)(int,char)
6)opzionale la trasformo in un tipo
typedef int(*myfnz)(int,char);
7)la uso
int dsort(void* v,size_t n,size_t sz, myfnz f,eccc)

Scusa se non ho messo nei tag code ma dal cell fatico ad usarli piu tardi poi modifico
Easy framework per il linguaggio C.
vbextreme hack your life
gila75
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2739
Iscrizione: mercoledì 16 gennaio 2013, 17:28
Desktop: ubuntu-2d
Distribuzione: Ubuntu 12.04.2 LTS i686
Località: Airuno(Lecco)

Re: Puntatori a Funzione[C]

Messaggio da gila75 »

Ora io inizio il prototipo e tu lo continui seguendo le linee dell'esercizio,leggilo attentamente,ho sempre scritto puntatori a funzione e non puntatore a puntatore di funzione.
Puntatori a puntatori di funzioni perchè:
Assegno nel main il puntatore alla funzione cmp.
Sempre nel main, se chiamo una funzione (esempio prova),e devo passarle come parametro il puntatore alla funzione cmp, sono obbligato
a usare un puntatore a puntatore, no?
Scusami se ti sto facendo impazzire vbextreme, ma sono tante le cose da capire.
Avatar utente
vbextreme
Entusiasta Emergente
Entusiasta Emergente
Messaggi: 1214
Iscrizione: domenica 12 gennaio 2014, 14:06
Desktop: lxde
Distribuzione: xubuntu 14.10

Re: Puntatori a Funzione[C]

Messaggio da vbextreme »

gila ma con i puntatori semplici come fai?

Codice: Seleziona tutto

void funzione (int*);
...
int* a = &abc,
funzione(a);
...
come vedi non si passa un puntatore a puntatore ma semplice puntatore.
Uguale uguale per i puntatori a funzione.
Quindi avrai

Codice: Seleziona tutto

int dsort( void* v, size_t n, size_t sz, ?questa la fai te?, int (*compara) (const void * a, const void * b) );
Ora prova a procedere come ti ho consigliato sopra per la qsort.
Easy framework per il linguaggio C.
vbextreme hack your life
gila75
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2739
Iscrizione: mercoledì 16 gennaio 2013, 17:28
Desktop: ubuntu-2d
Distribuzione: Ubuntu 12.04.2 LTS i686
Località: Airuno(Lecco)

Re: Puntatori a Funzione[C]

Messaggio da gila75 »

vbextreme [url=http://forum.ubuntu-it.org/viewtopic.php?p=4556961#p4556961][img]http://forum.ubuntu-it.org/images/icons/icona-cita.gif[/img][/url] ha scritto:gila ma con i puntatori semplici come fai?

Codice: Seleziona tutto

void funzione (int*);
...
int* a = &abc,
funzione(a);
...
come vedi non si passa un puntatore a puntatore ma semplice puntatore.
Uguale uguale per i puntatori a funzione.
Quindi avrai

Codice: Seleziona tutto

int dsort( void* v, size_t n, size_t sz, ?questa la fai te?, int (*compara) (const void * a, const void * b) );
Ora prova a procedere come ti ho consigliato sopra per la qsort.
Mi sto perdendo un po' :)
Se io devo passare un puntatore ad una funzione devo usare un puntatore a puntatore direi.
Ho scritto questo:

Codice: Seleziona tutto

#include <stdlib.h>
#include <stdio.h>

void fun_punt (int **punt_punt)
{
    printf ("valore puntatore passato a funzione %d\n", **punt_punt);
    **punt_punt=((**punt_punt)*2);
    return;
}

int  main()
{
    int a=10;
    int *p=&a;
    fun_punt(&p); 
    printf ("nuovo valore di a %d\n",a);
    return 0;
}

In questo caso io passo *p, quindi nella funzione avrò un puntatore a puntatore.
Credo che valga lo stesso con le funzioni no?
Avatar utente
vbextreme
Entusiasta Emergente
Entusiasta Emergente
Messaggi: 1214
Iscrizione: domenica 12 gennaio 2014, 14:06
Desktop: lxde
Distribuzione: xubuntu 14.10

Re: Puntatori a Funzione[C]

Messaggio da vbextreme »

NO!

Codice: Seleziona tutto

int A = 10;
Ora se io voglio passare A ad una funzione e potere modificare il suo valore(10) la devo passare per indirizzo ovvero:

Codice: Seleziona tutto

fnz(&A);
ma potrei benissimo fare:

Codice: Seleziona tutto

int A = 10;
int* B = &A;
fnz(B);
Come vedi non passo l'indirizzo di B ma il valore di B che sarà l'indirizzo di A,ottenendo lo stesso risultato di sopra.
Se io avessi passato per indirizzo B (&B) avrei un puntatore a puntatore e quindi nella funzione con * otterro l'indirizzo di A e non il suo valore di 10.

Ora perchè devi passare un **? non devi mica modificare l'indirizzo della funzione puntata! devi solamente usare il puntatore!

QUESTO è QUELLO CHE DEVI USARE:

Codice: Seleziona tutto

void stampa(void)
{
    printf("stampa");
}

void usastampa( void(*st)(void) )
{
    st();//in questo caso accedo direttamenta a cosa punto con st perchè devo semplicemente chiamare la funzione
}

int main()
{
    usastampa(stampa);
}

se io invece volessi modificare la funzione allora dovrei passarla per riferimento(ti ricordi come fai per l'head di una lista? se non gli passi il riferimento alla testa non la puoi modificare)
ed ecco l'esempio di quando servo un **,ovvero passo ad una funzione un puntatore a funzione che contiene una funzione,dentro a questa faccio in modo che vada a puntare ad un'altra funzione.

Codice: Seleziona tutto

void stampaA()
{
    printf("a");
}

void stampaB()
{
    printf("b");
}

void esteso( void(**f)(void) )
{
    *f = stampaB;
}

int main()
{
    void(*festesa)(void) = stampaA;
    esteso(&festesa);
    festesa();

    return 0;
}
Spiegato?
Quindi in questo esercizio devi usare la funzione passala quindi semplicemente come puntatore a funzione.
Se dovevi cambiare la funzione puntata dal tuo puntatore e renderla disponibile al di fuori della funzione,allora si che avresti dovuto usare le due ** :lol:
Ora smetti di usare la testa se non per :muro:
Fai letteralmente quello che ti ho detto senza capire!Vedrai che dopo averlo fatto lo capisci! :maestro:
Easy framework per il linguaggio C.
vbextreme hack your life
gila75
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2739
Iscrizione: mercoledì 16 gennaio 2013, 17:28
Desktop: ubuntu-2d
Distribuzione: Ubuntu 12.04.2 LTS i686
Località: Airuno(Lecco)

Re: Puntatori a Funzione[C]

Messaggio da gila75 »

ok, ok non ti arrabbiare vbextreme :D
Ti sto facendo ammattire lo so...scusami.
Mi sa che però non ci stiamo intendendo sulla "consegna" dell'esercizio.
Riguardo al discorso del puntatore a puntatore funzione, guarda questo codice. Era solo una prova del compito proposto da te.
Per questo esempio credo sia giusto il ** (puntatore a puntatore).
Ora rileggo ciò che ho scritto.

Codice: Seleziona tutto

#include <stdlib.h>
#include <stdio.h>
#define N 5
#define CMP int (**cmp)(const void*, const void*)

void quick (int *array,int n, int size, CMP);
int compara (const void * a, const void * b);


int compara (const void * a, const void * b)
{   
      return ( *(int*)a - *(int*)b );
}


void quick (int *array,int n, int size, CMP)
{   
    qsort (array,n,size,(*cmp));
    return ;
}

int  main()
{
   
    int i;
    int array[N]={5,4,12,2,1};
    int size=sizeof(int);
    int   (*ptr_cmp)(const void*, const void*)=compara;
    quick(array,N,size,&ptr_cmp);
    
    for (i=0; i<N; i++)
    { 
        printf ("%d\n", array[i]);
    }
    return 0;
}

Avatar utente
vbextreme
Entusiasta Emergente
Entusiasta Emergente
Messaggi: 1214
Iscrizione: domenica 12 gennaio 2014, 14:06
Desktop: lxde
Distribuzione: xubuntu 14.10

Re: Puntatori a Funzione[C]

Messaggio da vbextreme »

Codice: Seleziona tutto

#include <stdio.h>
#include <stdlib.h>
//MATH
#include <time.h>
#include <math.h>

void mth_initrandom()
{
    srand((unsigned)time(NULL));
}

int mth_random(int n)
{
    return rand() % n;
}
//


typedef int(*COMPAR)( void*, void*); // base comparazione
typedef void (*SORTING) (void* , size_t , size_t , COMPAR ); // base qsort

unsigned int ncmp;

int cmp_int(int* a, int* b)
{
    ++ncmp;
    return *a - *b;
}

int dsort(void* v, size_t sz, size_t n, SORTING fsort, COMPAR fcmp)
{
    ncmp = 0;
    fsort(v,n,sz,fcmp);
    return ncmp;
}

#define V_SZ 10
#define V_RANGE 10

int main(void)
{
    mth_initrandom();

    int v[V_SZ];

    printf("Random:\n");
    int i;
    for ( i = 0; i < V_SZ; i++)
        printf("v[%d]=%d\n",i,(v[i] = mth_random(V_RANGE)));

    int nc = dsort(v,sizeof(int),V_SZ,(SORTING)qsort,(COMPAR)cmp_int);

    printf("Order:\n");
    for ( i = 0; i < V_SZ; i++)
        printf("v[%d]=%d\n",i,v[i]);


    printf("\nFor sorting with qsort compar:%d elements\n",nc);

    return 0;
}
Ora prova invece ad espormi le potenzialità della funzione dsort.
Easy framework per il linguaggio C.
vbextreme hack your life
gila75
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2739
Iscrizione: mercoledì 16 gennaio 2013, 17:28
Desktop: ubuntu-2d
Distribuzione: Ubuntu 12.04.2 LTS i686
Località: Airuno(Lecco)

Re: Puntatori a Funzione[C]

Messaggio da gila75 »

Devo vederlo con moooolta calma :)
Non è comunque un esercizio semplice come dicevi....hai barato :shy:
Quello che non riuscivo a fare era:
creare una funzione nel main che accettasse vettore, numero elementi vettore, il sizeof, puntatore a funzione qsort, puntatore a funzione compara.
L'esempio che ho postato prima, andava a fare il qsort e poi chiamava il puntatore della funzione compara.
io invece volevo fare un passaggio in più.
Vedo che però tu qsort l'hai messo nella funzione del main.
Devo anche capire perchè il puntatore a puntatore nel mio esempio è sbagliato. Compila e funziona alla perfezione...mannaggia.
Intanto grazie...ci penso su un po'...
Così nel frattempo ti lascio in pace :lol:
Avatar utente
vbextreme
Entusiasta Emergente
Entusiasta Emergente
Messaggi: 1214
Iscrizione: domenica 12 gennaio 2014, 14:06
Desktop: lxde
Distribuzione: xubuntu 14.10

Re: Puntatori a Funzione[C]

Messaggio da vbextreme »

puoi usare anche il ****** ma per questo esercizio basta il *.
Semplice perché bastava prendere il prototipo della qsort e trasformarlo in un puntatore come per la compare.Se guardi la dsort non fa praticamente nulla,tutto l'esercizio si concentra solo sul passaggio dei parametri.
L'unica cosa che ho aggiunto di 'eccezionale' é la creazione di un vettore con valori random.

La qsort la passo alla dsort, non la uso nel main,sara la dsort ad usare la funzione.
Ora il caso é banale ma situazioni come queste sono all'ordine del giorno col c.

Riusciresti a modificare il codice in modo che sia l'utente a decidere quale funzione di sorting usare?
Inizia solo con scelta singola della qsort poi ti passo le altre.
Easy framework per il linguaggio C.
vbextreme hack your life
gila75
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2739
Iscrizione: mercoledì 16 gennaio 2013, 17:28
Desktop: ubuntu-2d
Distribuzione: Ubuntu 12.04.2 LTS i686
Località: Airuno(Lecco)

Re: Puntatori a Funzione[C]

Messaggio da gila75 »

puoi usare anche il ****** ma per questo esercizio basta il *.
Azzardo questo: nel tuo codice non usi il ** perchè usi la typedef e quindi viene un po' diverso.
Mi piacerebbe provare a modificarlo senza il typedef come ho fatto nel mio esempio, credo che li dovrei usare il **.
Sto pomeriggio tornato dal lavoro provo. Così se non funziona, capisco il perchè e "tocco con mano".
Riusciresti a modificare il codice in modo che sia l'utente a decidere quale funzione di sorting usare?
Inizia solo con scelta singola della qsort poi ti passo le altre.
Ci provo.
Ora il caso é banale ma situazioni come queste sono all'ordine del giorno col c.
Magra consolazione :). Non sono molto semplici e comunque bisogna esercitarsi parecchio.
Non mi ricordo chi (in un altro forum), mi aveva detto che il C è una passeggiata...col cavolo!!!!
Ciao vbextreme, scappo al lavoro, e buona giornata a tutti :ciao:
Avatar utente
ienaplinsky
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 954
Iscrizione: giovedì 21 gennaio 2010, 9:56
Località: Napoli

Re: Puntatori a Funzione[C]

Messaggio da ienaplinsky »

gila75 ha scritto:
Fin qui, nessun problema. Ma già mi sorge un dubbio:

Codice: Seleziona tutto

void (*ptr)(int)=prova;
e perchè non

Codice: Seleziona tutto

void (*ptr)(int)=&prova;
Il nome di una funzione è l, indirizzo dove risiede il codice della funzione se provi a stampare con printf in esadecimale passando come parametro il nome di una qualsiasi funzione otterrai un indirizzo è per questo che al puntatore a funzione assegni il nome della funzione senza &
Prova

Codice: Seleziona tutto

printf("indirizzo di printf = %x",printf);
edit è %p non %x
Ultima modifica di ienaplinsky il venerdì 4 aprile 2014, 16:37, modificato 1 volta in totale.
Avatar utente
vbextreme
Entusiasta Emergente
Entusiasta Emergente
Messaggi: 1214
Iscrizione: domenica 12 gennaio 2014, 14:06
Desktop: lxde
Distribuzione: xubuntu 14.10

Re: Puntatori a Funzione[C]

Messaggio da vbextreme »

Azzardo questo: nel tuo codice non usi il ** perchè usi la typedef e quindi viene un po' diverso.
Assolutamente no.
è la stessa identica cosa se non che con la forma estesa si inizia a faticare nella comprensione del codice.

Codice: Seleziona tutto

#include <stdio.h>
#include <stdlib.h>
//MATH
#include <time.h>
#include <math.h>

void mth_initrandom()
{
    srand((unsigned)time(NULL));
}

int mth_random(int n)
{
    return rand() % n;
}
//


//typedef int(*COMPAR)( void*, void*); // base comparazione
//typedef void (*SORTING) (void* , size_t , size_t , COMPAR ); // base qsort

unsigned int ncmp;

int cmp_int(int* a, int* b)
{
    ++ncmp;
    return *a - *b;
}

int dsort(void* v, size_t sz, size_t n, void (*fsort) (void* , size_t , size_t , int(*cmp)(const void*,const void*) ), int(*fcmp)(const void*,const void*) )
{
    ncmp = 0;
    fsort(v,n,sz,fcmp);
    return ncmp;
}

#define V_SZ 10
#define V_RANGE 10

int main(void)
{
    mth_initrandom();

    int v[V_SZ];

    printf("Random:\n");
    int i;
    for ( i = 0; i < V_SZ; i++)
        printf("v[%d]=%d\n",i,(v[i] = mth_random(V_RANGE)));

    int nc = dsort(v,sizeof(int),V_SZ,qsort,(int(*)(const void*,const void*))cmp_int);

    printf("Order:\n");
    for ( i = 0; i < V_SZ; i++)
        printf("v[%d]=%d\n",i,v[i]);


    printf("\nFor sorting with qsort compar:%d elements\n",nc);

    return 0;
}
Te l'ho postato proprio con la typedef per semplificarti la vita!

Ora voglio farti vedere anche l'uso dei puntatori a funzione tramite vettore.
Usando sempre l'esempio fatto prima voglio completarlo in modo che l'utente decida quale algoritmo usare per riordinare il vettore e che venga a conoscenza di quanti confronti ha fatto l'algoritmo.
Non modificando poi il vettore originale ma una sua copia l'utente può iniziare a capire le varie velocità di riordinamento dei vari algoritmi di sorting:

Codice: Seleziona tutto

#include <stdio.h>
#include <stdlib.h>
//MATH
#include <time.h>
#include <math.h>

void mth_initrandom()
{
    srand((unsigned)time(NULL));
}

int mth_random(int n)
{
    return rand() % n;
}
//

//IO
char* con_gets(char* d,int max)
{
    char* st = d;
    int c;
    while ( (c = getchar()) != EOF && c != '\n' && --max > 0 ) *d++ = c;
    *d = '\0';
    return st;
}
//

//SORT
void bubbleSort(void *v, size_t n, size_t sz, int(cmp)(const void* a, const void* b))
{
    int i;
    int o = 0;
    char* vect;
    char* mem = malloc(sz);

    for ( ; n > 1 && !o; n--)
    {
        o = 1;

        for (vect = (char*) v, i = 0; i < n - 1; i++, vect += sz )
        {
            if ( cmp( vect, vect + sz ) > 0)
            {
                memcpy( mem, vect, sz );
                memcpy( vect, vect + sz, sz);
                memcpy( vect + sz, mem, sz);
                o = 0;
            }
        }
    }

    free(mem);
}
//


typedef int(*COMPAR)( void*, void*); // base comparazione
typedef void (*SORTING) (void* , size_t , size_t , COMPAR ); // base qsort

unsigned int ncmp;

int cmp_int(int* a, int* b)
{
    ++ncmp;
    return *a - *b;
}

int dsort(void* v, size_t sz, size_t n, SORTING fsort, COMPAR fcmp )
{
    ncmp = 0;
    fsort(v,n,sz,fcmp);
    return ncmp;
}

#define V_SZ 10
#define V_RANGE 10

int main(void)
{

    mth_initrandom();

    int v[V_SZ];
    int u[V_SZ];

    printf("Random:\n");
    int i;
    for ( i = 0; i < V_SZ; i++)
        printf("v[%d]=%d\n",i,(v[i] = mth_random(V_RANGE)));

    SORTING s[2];
            s[0] = (SORTING)qsort;
            s[1] = (SORTING)bubbleSort;

    printf("\n\n");

    char inp[80];
    int sel;

    while ( 1 )
    {
        printf("Select sorting:\n");
        printf("\t0:quick\n");
        printf("\t1:bubble\n");
        printf("\tq:quit\n");
        printf("\t->");

        con_gets(inp,80);
        if (inp[0] == 'q') break;

        sel = inp[0] - '0';
        if ( sel < 0 || sel > 1 )
        {
            printf("algoritmo inesistente\n\n");
            continue;
        }

        memcpy(u,v,sizeof(int) * V_SZ);

        int nc = dsort(u,sizeof(int),V_SZ,s[sel],(COMPAR)cmp_int);

        printf("Order:\n");
        for ( i = 0; i < V_SZ; i++)
            printf("u[%d]=%d\n",i,u[i]);

        printf("For sorting compar:%d elements\n\n",nc);

    }

    return 0;
}
Prenditi tutte le pause che ti servono e domanda pure tutto ciò che non capisci.
Easy framework per il linguaggio C.
vbextreme hack your life
gila75
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2739
Iscrizione: mercoledì 16 gennaio 2013, 17:28
Desktop: ubuntu-2d
Distribuzione: Ubuntu 12.04.2 LTS i686
Località: Airuno(Lecco)

Re: Puntatori a Funzione[C]

Messaggio da gila75 »

Grazie Iena.
Credo di aver bisogno di un chiarimento sul discorso del doppio puntatore, che io ho usato e tu no.
Dici che in questo caso è inutile. Sicuramente sarà come dici tu, io non ho molta esperienza.
La cosa però è grave...nel senso che se scopri di non aver capito un tubo su un argomento già trattato...ti mancano le certezze e tutto va a pallino.
Prima di andare avanti, devo chiarire una volta per tutte e se emerge che ho detto una panzana suprema...mollo il c e mi do al ricamo, che forse mi riesce meglio :D
Allora, vediamo questo codice...senza typedef, macro... nulla e lasciamolo così almeno l'ho scritto io e capisco bene:

Codice: Seleziona tutto

#include <stdlib.h>
#include <stdio.h>

void prova_stampa_1 ();
int foo(int a,int b,void (**f_1)(void)); 


void prova_stampa_1 ()
{
    printf ("hello\n");
    return ;
}


int foo(int a,int b, void (**f_1)(void))
{
    
    (*f_1)();
    return a+b;
}

int  main()
{
    
    int ris;
    int a=10;
    int b=15;
    void (*ptr)(void)=prova_stampa_1;
    ris=foo (a,b,&ptr );
    printf ("%d\n", ris);
    return 0;
}

io qui

Codice: Seleziona tutto

void (*ptr)(void)=prova_stampa_1;
    ris=foo (a,b,&ptr );
definisco ptr che punta a prova stampa_1 (con relativi argomenti).
sotto nella funzione foo, lo passo con & (indirizzo).
Qui

Codice: Seleziona tutto

int foo(int a,int b, void (**f_1)(void))
devo usare il doppio puntatore.

Altro esempio :

Codice: Seleziona tutto

#include <stdlib.h>
#include <stdio.h>

void prova (int **b);



void prova (int **b)
{
    printf ("%d\n",**b);
    return;
}
int  main()
{
    
    
    int a=10;
    int *b=&a;
    prova (&b);
    return 0;
}

Se invece il puntatore a funzione lo "uso" nel main, allora li si che non mi serve il ** :

Codice: Seleziona tutto

#include <stdlib.h>
#include <stdio.h>

void prova_stampa_1 ()
{
    printf ("Hello word!!\n");
    return ;
}

int  main()
{
    void (*ptr)(void)=prova_stampa_1;
    (*ptr)();
    return 0;
}

Se le cose non stanno così allora davvero non ho capito una cicca in tutto questo tempo.
PS grazie del codice Vbextreme, me lo devo vedere bene con calma...tanto prima di andare avanti su altri argomenti, mi sa che ne passa.
No, tu che dici? Funzioni, puntatori ecc..conviene abbondare nello studio...credo sia davvero la parte più critica del c, dove occorre la massima dimestichezza.
Non so voi dove avete trovato più difficoltà? quali sono in media le parti più ostiche del C ?

EDIT:
in effetti questo codice funziona anche senza il doppio **

Codice: Seleziona tutto

#include <stdlib.h>
#include <stdio.h>
#define CALL void (punt_f_2)(void)

void stampa_1 (CALL)
{
    printf ("Hello ");
    (punt_f_2)();
    return ;
}

void stampa_2 ()
{
    printf ("word\n");
    return ;
}




int  main()
{
    void (*ptr)(CALL)=stampa_1;
    void  (*ptr_2)(void)=stampa_2;
    (*ptr)(ptr_2); 
    
    return 0;
}

bhò...sono confuso...
Compila e va alla perfezione, ma non vorrei che senza puntatore, possa andare storto qualcosa al ritorno della funzione.
Come il famoso esempio dello scambio di valore di due numeri passati a funzioni per valore e non per indirizzo.
Al ritorno lo stack viene distrutto, e non si ha il risultato voluto.
Non vorrei succedesse la stessa cosa qui.
Avatar utente
matteovid
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 368
Iscrizione: mercoledì 9 dicembre 2009, 9:09
Desktop: Openbox, XFCE, XMonad
Distribuzione: GNU/Linux Arch - openSUSE Leap
Sesso: Maschile
Località: Parma

Re: Puntatori a Funzione[C]

Messaggio da matteovid »

Ciao Gila

forse dovresti capire bene le funzioni e i loro parametri, che siano valori, costanti o puntatori, poi alle funzioni che ritornano un tipo che può essere un numero, una stringa o una struttura o una funzione.
So che avrai già studiato le funzioni e bene secondo me, ma hai ancora dei dubbi, come quando parli se sei dentro alla funzione principale main e/o fuori

poi ti consiglio di studiare a fondo questo argomento che hai avviato: puntatori a funzioni

so che a volte si è avviliti, a volte euforici, ma su corraggio che sei sulla buona strada.

ti lascio con un esempio, senza typedef, senza puntatori a funzioni, solo semplice programma C con funzioni e una struttura...
Spoiler
Mostra
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct st_ex {
char prodotto[16];
float prezzo;
};

int int_cmp(const void *, const void *);

void print_int_array(const int *, size_t);

void sort_integers_esempio(void);

int cstring_cmp(const void *, const void *);

void print_cstring_array(char **, size_t);

void sort_cstrings_esempio(void);

int struct_cmp_by_prezzo(const void *, const void *);

int struct_cmp_by_prodotto(const void *, const void *);

void print_struct_array(struct st_ex *, size_t , const char *);

void sort_structs_esempio(void);

int main(void)
{
sort_integers_esempio();
sort_cstrings_esempio();
sort_structs_esempio();
return 0;
}

int int_cmp(const void *a, const void *b)
{
const int *ia = (const int *)a;
const int *ib = (const int *)b;
return *ia - *ib;
}

void print_int_array(const int *array, size_t len)
{
size_t i;

for(i=0; i<len; i++)
printf("%d | ", array);

putchar('\n');
}

void sort_integers_esempio(void)
{
int numbers[] = { 7, 3, 4, 1, -1, 23, 12, 43, 2, -4, 5 };
size_t numbers_len = sizeof(numbers)/sizeof(int);

puts("*** Int array originale ...");

print_int_array(numbers, numbers_len);

qsort(numbers, numbers_len, sizeof(int), int_cmp);

puts("*** Int array ordinato ...");

print_int_array(numbers, numbers_len);

puts("--");
}

int cstring_cmp(const void *a, const void *b)
{
const char **ia = (const char **)a;
const char **ib = (const char **)b;
return strcmp(*ia, *ib);
}

void print_cstring_array(char **array, size_t len)
{
size_t i;

for(i=0; i<len; i++)
printf("%s | ", array);

putchar('\n');
}

void sort_cstrings_esempio(void)
{
char *strings[] = { "Zorro", "Alex", "Celine", "Bill", "Forest", "Dexter" };
size_t strings_len = sizeof(strings) / sizeof(char *);

puts("*** String array originale ...");

print_cstring_array(strings, strings_len);

qsort(strings, strings_len, sizeof(char *), cstring_cmp);

puts("*** String array ordinato ...");

print_cstring_array(strings, strings_len);

puts("--");
}

int struct_cmp_by_prezzo(const void *a, const void *b)
{
struct st_ex *ia = (struct st_ex *)a;
struct st_ex *ib = (struct st_ex *)b;
return (int)(100.f*ia->prezzo - 100.f*ib->prezzo);

}

int struct_cmp_by_prodotto(const void *a, const void *b)
{
struct st_ex *ia = (struct st_ex *)a;
struct st_ex *ib = (struct st_ex *)b;
return strcmp(ia->prodotto, ib->prodotto);
}

void print_struct_array(struct st_ex *array, size_t len, const char *lf)
{
size_t i;

puts (lf);
for(i=0; i<len; i++)
printf("[ prodotto: %s \t prezzo: €%.2f ]\n", array.prodotto, array.prezzo);
/* se non stampa il simbolo dell'euro (€) con [tasto AltGr+e]
* mettere il simbolo del dollaro ($) con [tasto Maius+4, oppure shift+4]
* questo con tastiera Italiana
*/
puts("--");
}

void sort_structs_esempio(void)
{
struct st_ex structs[] = {{"mp3 player", 19.0f}, {"plasma tv", 2200.0f},
{"notebook", 1300.49f}, {"smartphone", 499.99f},
{"dvd player", 139.50f}, {"DVD -R", 0.2f }};

size_t structs_len = sizeof(structs) / sizeof(struct st_ex);

puts("*** Struct sorting...");

print_struct_array(structs, structs_len, "struct Originale");

qsort(structs, structs_len, sizeof(struct st_ex), struct_cmp_by_prezzo);

print_struct_array(structs, structs_len, "struct Ordinato per Prezzo");

qsort(structs, structs_len, sizeof(struct st_ex), struct_cmp_by_prodotto);

print_struct_array(structs, structs_len, "struct Ordinato per Prodotto");
}


chiedi dove ho trovato più difficoltà?
personalmente nelle strutture con enumerazioni, e quando incontro un compilatore non ansi, che non hanno le librerie standard, mancano le printf e le fgets e altre importanti librerie, le struct e le enumerazioni nelle parole chiave, bisogna proprio scriverle di sana pianta...
miglia da percorrere, prima di dormire
gila75
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2739
Iscrizione: mercoledì 16 gennaio 2013, 17:28
Desktop: ubuntu-2d
Distribuzione: Ubuntu 12.04.2 LTS i686
Località: Airuno(Lecco)

Re: Puntatori a Funzione[C]

Messaggio da gila75 »

Grazie Matteovid :)
forse dovresti capire bene le funzioni e i loro parametri, che siano valori, costanti o puntatori, poi alle funzioni che ritornano un tipo che può essere un numero, una stringa o una struttura o una funzione.
E si che ci ho passato parecchio tempo..ho fatto molti esercizi...prove su prove.
Passaggio di puntatori a funzione, passaggio per indirizzo, funzioni che ritornano puntatori (comodi per funzioni tipo strstr() con le stringhe, che ritornano il puntatore dell'occorrenza trovata)...
Logico, passa una settimana e già tendo a dimenticare la sintassi di come si passa l'argomento. Allora, manuale alla mano e esempi salvati.
Frustrante un po' capire che ho ancora lacune.
Ma in fondo come dici tu si va da alti e bassi...giorni che butteresti il pc e i manuali dalla finestra e giorni che sei gasato perchè ti "riesce tutto".
So che avrai già studiato le funzioni e bene secondo me, ma hai ancora dei dubbi, come quando parli se sei dentro alla funzione principale main e/o fuori
Intendevo dire se richiamo il puntatore a funzione nel main, e quindi da li, punta alla funzione, oppure passare il puntatore alla funzione.
Salvo il codice e lo studio.
gila75
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2739
Iscrizione: mercoledì 16 gennaio 2013, 17:28
Desktop: ubuntu-2d
Distribuzione: Ubuntu 12.04.2 LTS i686
Località: Airuno(Lecco)

Re: Puntatori a Funzione[C]

Messaggio da gila75 »

ienaplinsky [url=http://forum.ubuntu-it.org/viewtopic.php?p=4557365#p4557365][img]http://forum.ubuntu-it.org/images/icons/icona-cita.gif[/img][/url] ha scritto:
gila75 ha scritto:
Fin qui, nessun problema. Ma già mi sorge un dubbio:

Codice: Seleziona tutto

void (*ptr)(int)=prova;
e perchè non

Codice: Seleziona tutto

void (*ptr)(int)=&prova;
Il nome di una funzione è l, indirizzo dove risiede il codice della funzione se provi a stampare con printf in esadecimale passando come parametro il nome di una qualsiasi funzione otterrai un indirizzo è per questo che al puntatore a funzione assegni il nome della funzione senza &
Prova

Codice: Seleziona tutto

printf("indirizzo di printf = %x",printf);
edit è %p non %x
Forse il discorso del puntatore a puntatore che non serve è svelato qua sopra.
Mi sa che io erroneamente ragiono in termini di variabili, ma qui si ha a che fare con funzioni e la cosa funziona diversamente.
Avatar utente
ienaplinsky
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 954
Iscrizione: giovedì 21 gennaio 2010, 9:56
Località: Napoli

Re: Puntatori a Funzione[C]

Messaggio da ienaplinsky »

Detto grezzamente nel nome della funzione salvi l' indirizzo della prima istruzione del corpo della funzione in modo che quando la funzione viene chiamata il compilatore fa un salto incondizionato alla funzione salvandosi l' indirizzo dell' istruzione immediatamente dopo (la chiamata )per ritornare al normale flusso di codice
gila75
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2739
Iscrizione: mercoledì 16 gennaio 2013, 17:28
Desktop: ubuntu-2d
Distribuzione: Ubuntu 12.04.2 LTS i686
Località: Airuno(Lecco)

Re: Puntatori a Funzione[C]

Messaggio da gila75 »

ienaplinsky [url=http://forum.ubuntu-it.org/viewtopic.php?p=4557727#p4557727][img]http://forum.ubuntu-it.org/images/icons/icona-cita.gif[/img][/url] ha scritto:Detto grezzamente nel nome della funzione salvi l' indirizzo della prima istruzione del corpo della funzione in modo che quando la funzione viene chiamata il compilatore fa un salto incondizionato alla funzione salvandosi l' indirizzo dell' istruzione immediatamente dopo (la chiamata )per ritornare al normale flusso di codice
Forse ho capito...ma dico forse.
Ho scritto un piccolo programma per vedere come vengono gestiti gli indirizzi.
In effetti, come diceva vbextereme (non che dubitassi, ma volevo capire :) ) non servono i doppi puntatori.
Forde mi confondo col passaggio di un puntatore a funzione e li servono i doppi puntatori.
Ecco cosa ho scritto:

Codice: Seleziona tutto

#include <stdlib.h>
#include <stdio.h>
#define CALL void (punt_f_2)(void)

void stampa_1 (CALL)
{
    printf ("stampo indirizzo funzione stampa_2 passato dal main %p\n",punt_f_2);
    printf ("HELLO ");
    (punt_f_2)();
    return ;
}

void stampa_2 ()
{
    printf ("WORD\n\n");
    return ;
}




int  main()
{
    
    void (*ptr)(CALL)=stampa_1;
    void  (*ptr_2)(void)=stampa_2;
    (*ptr)(ptr_2); 
    printf ("indirizzo stampa_2 %p\n",stampa_2);
    printf ("indirizzo *ptr_2 %p\n",ptr_2);
    
    return 0;
}

output :
stampo indirizzo funzione stampa_2 passato dal main 0x8048472
HELLO WORD

indirizzo stampa_2 0x8048472
indirizzo *ptr_2 0x8048472
gila@ubuntu:~/Scrivania$
Tutti gli indirizzi combaciano.
Giusto il ragionamento?
Viene già passato l'indirizzo.
Devo approfondire, ma credo che le cose siano così, no?
Comunque mi sono accordo di aver interpretato male il concetto di puntatore a puntatore e passaggio di puntatore a funzione.
Ho fatto una prova e con mio stupore e "sgomento"...si è comportata al contrario di come credevo.
Quindi...ingrano la retro e cerco di sistemare quel concetto :(
Scrivi risposta

Ritorna a “Programmazione”

Chi c’è in linea

Visualizzano questa sezione: 0 utenti iscritti e 6 ospiti