Domanda su inizializzazione puntatori a funzioni

di il
12 risposte

Domanda su inizializzazione puntatori a funzioni

Salve a tutti.
ho un problema con l'inizializzazione di una variabile puntatore a funzione.

in un codice a cui sto lavorando ho due funzioni a cui voglio far puntare un vettore di puntatori; la prima funzione ha void come argomento e mi restituisce un unsigned int, la seconda ha sia in ingresso che in uscita un unsigned int.
se inizializzo una sola delle due funzioni, la prima, tutto procede per il verso giusto, come nel codice sotto riportato.
PS il codice eratostene e' di Nippolo

#include <stdio.h>
#include <math.h>
#define N 5000

unsigned int insert(void) {    
 	int a,n;
  	
  	printf("inserisci n deve essere >=2\n");
        scanf("%u",& n);   
  	printf("controlliamo se n e' pari o dispari\n");
  	printf("troviamo i numeri primi <= di n con il Crivello di Eratostene\n");	
  	
  	        a = sqrt (n);
  	        if(n==a*a)
  	        printf("il numero %u e' un quadrato perfetto\n",n);
  	
  		if (n%2 == 0)
  		printf("il numero %u e' positivo e pari\n",n);
  		else
  		printf("il numero %u e' positivo e dispari\n",n);
                                   
                                   return n;
                                   }
                        
unsigned int eratostene(unsigned int n)    {
                     
    int v[n - 1];
    unsigned int i;
    unsigned int j;
    for(i = 0; i < n - 1; ++i)
    {
        v[i] = i + 2;
    }
    i = 0;
    while(1)            //il C valuta 0 come falso e tutti gli altri numeri interi come vero
    {
        j = v[i] * v[i];
        if(j > n)
        {
            break;
        }
        do
        {
            v[j - 2] = 0;  //marco a 0 tutti i multipli
            j += v[i];
        }
        while(j <= n);
        while(v[++i] == 0);
    }
    
    printf("NUMERI PRIMI MINORI O UGUALI DI %u\n", n);
             for(j = 0; j < n -1; ++j) {
        if(v[j])
        {
           printf("%u ", v[j]);
        }
                                   }           
          printf("\n");
                                            
    return 0;
                                              }//end function






int main() {

unsigned int (*p[2]) (void, unsigned int) = {insert,eratostene};    //problema inizializzazione vettore puntatore
unsigned int n;

//n = p();


return 0;   }



 /*     con questa main qui sotto funziona

int main() {

unsigned int (*p)(void)={insert};
unsigned int n;

n = p();

return 0;   }
   */
quando invece cerco di inizializzare due funzioni (cercando di seguire la sintassi) mi da degli errori.
ho riportato nel codice di cui sopra la parte di codice non funzionante e disattivata da /*
ringrazio in anticipo per ogni aiuto.

12 Risposte

  • Re: Domanda su inizializzazione puntatori a funzioni

    Se ricordo bene due puntatori a due funzioni che hanno firma differente non sono dello stesso tipo
    Puoi mettere in array puntatori a funzioni che hanno stessi parametri e stesso tipo di ritorno
  • Re: Domanda su inizializzazione puntatori a funzioni

    Grazie della risposta, non ho capito cos'e' la firma.
  • Re: Domanda su inizializzazione puntatori a funzioni

    Comunque ho risolto con questo
    
    int main() {
    
    unsigned int (*apfunz[2]) (unsigned int) = {insert,eratostene};    //problema inizializzazione vettore puntatore
    int i;
    unsigned int n;
    
    
    for(i=0;i<2;i++)
    
    printf("%u\n",apfunz[i]);  //indirizzi del puntatore a funzioni
    printf("\n");
    
    
    (*apfunz[0])(12);         //richiamo funzione insert
    (*apfunz[1])(12);         //richiamo funzione eratostene --calcola su n=12
    
    return 0;   }
    
  • Re: Domanda su inizializzazione puntatori a funzioni

    Quindi hai usato una sola firma, appunto come ti dicevano di fare.
  • Re: Domanda su inizializzazione puntatori a funzioni

    Si adesso ho capito cos'e' la firma.
    ma ancora non mi e' proprio chiaro, insomma quello che cerco di capire e' questo.
    faccio tre domande.
    1) e' vero che (come nel mio caso) l'elenco delle funzioni a cui i puntatori puntano devono avere lo stesso tipo in ingresso o altrimenti non funziona?
    2) e' vero che nel caso in cui ho un solo puntatore a piu' funzioni il puntatore puo' puntare individualmente a funzioni con tipi diversi?
    3) nel caso la domanda 1) sia vera (e pare esserlo), esiste un modo per aggirare il problema?
    il problema e' "definire" un vettore di puntatori a funzioni con diverse firme o una procedura alternativa per aggirare il problema.

    ps questo dei puntatori a funzioni mi sembra un ottimo attrezzo qualcuno sa suggerirmi qualche altro potente attrezzo ?
    grazie
  • Re: Domanda su inizializzazione puntatori a funzioni

    1) stessa firma
    2) ni
    3) no

    Per gli attrezzi te ne suggerisco uno ... un buon librone sul linguaggio
  • Re: Domanda su inizializzazione puntatori a funzioni

    marittimo ha scritto:


    esiste un modo per aggirare il problema?
    il problema e' "definire" un vettore di puntatori a funzioni con diverse firme o una procedura alternativa per aggirare il problema.
    "problema" e' una parola grossa: è così difficile chiamare le funzioni direttamente? I puntatori a funzione servono per callback, bootloader... quelle cose lì

    Comunque per quello che vale (è fortemente sconsigliato fare così e non è garantito che funzioni con tutti i compilatori)
    #include "stdio.h"
       
    void fun1(void){
        printf("42\n");      
    }
    void fun2(int n){
        printf("%d\n", n);      
    }
    int  fun3(void){
        int n;
        printf("Inserisci un numero\n");      
        scanf(" %d", &n);   
        printf("Hai digitato %d\n", n);      
        return n;
    }
    
    int main(void) {
        int (*p[3]) (...) = {fun1, fun2, fun3};
        int r;
        
        p[0]();
        p[1](100);   
        r =  p[2]();
        printf("Il return value e' %d\n", r);  
        
        return 0;
    }
    e in compilazione
    g++ -fpermissive
  • Re: Domanda su inizializzazione puntatori a funzioni

    Grazie Weierstrass per il codice mi sembra chiaro ora.
    forse pero' e' meglio fare chiarezza su quello che sto cercando di fare.
    ho costruito un codice che mi permette di fare la fattorizzazione di un intero (la mia implementazione di eratostene e' piuttosto laboriosa e Nippolo mi ha passato un codice molto piu' intelligente del mio); il mio codice originario mi restituisce i primi minori o uguali ad n; il vettore delle differenze tra due primi successivi, dopodiche' impostando la distanza tra due primi mi da il vettore dei primi la cui distanza e' quella impostata e infine mi restituisce i fattori e gli esponenti della fattorizzazione.
    tutto questo funziona.
    il passo successivo e' quello di creare un codice che fa le seguenti cose:
    1)il nuovo codice fa tutto quello che fa il codice originario per diversi valori di un m intero impostato (esempio m=3 a cui corrispondono m1=12;m2=16;m3=144) e per questi tre valori il codice calcola i primi, le differenze, fattori, esponenti etc etc.
    2)il nuovo codice fatto tutto quello di cui al punto 1) trova ad esempio il minimo comune multiplo e il massimo comune divisore (in questo caso tra 12,16 e 144).
    e per adesso mi accontento.
    ora io pensavo di poter implementare questo nuovo codice con i puntatori a funzione, non ci ho ancora pensato a fondo visto che ho capito il loro funzionamento solo ora.

    in un futuro, tempo permettendo vorrei poter interfacciare queste successioni (ed altre) con gnuplot per cercare di avere una visione grafica.
    a tal proposito sarebbe interessante sapere se esiste qualche widget o software che ti permette non solo di visualizzare l'oggetto ma anche di interagire cambiando parametri o condizioni e piu' importante ancora visualizzare l'evoluzione dell'oggetto tra due cambi di parametri.

    ad esempio (e chiudo) avendo una successione {an} di numeri complessi dove il singolo aj = re + i*im e' un punto del piano, poter vedere la disposizione sul piano di tutti gli aj per un n fissato e successivamente cambiando n vorrei vedere la nuova disposizione e una sorta di cammino dei punti tra il primo n e il secondo.
    grazie a tutti per l'aiuto.
    questo sotto e' il codice 2 leggermente migliorato e in evoluzione
    
    #include <stdio.h>
    #include <math.h>
    
    
    unsigned int insert(unsigned int n) {    
     	unsigned int a;
      	
      	//printf("inserisci n deve essere >=2\n");
            //scanf("%u",& n);   
      	printf("controlliamo se n e' pari o dispari\n");
      	printf("troviamo i numeri primi <= di %u con il Crivello di Eratostene\n",n);	
      	
      	        a = sqrt (n);
      	        if(n==a*a)
      	        printf("il numero %u e' un quadrato perfetto\n",n);
      	
      		if (n%2 == 0)
      		printf("il numero %u e' positivo e pari\n",n);
      		else
      		printf("il numero %u e' positivo e dispari\n",n);
                                       
                                       return n;
                                       }
    
    
                            
    unsigned int eratostene(unsigned int n)    {
                         
        int v[n - 1];
        unsigned int i;
        unsigned int j;
        for(i = 0; i < n - 1; ++i)
        {
            v[i] = i + 2;
        }
        i = 0;
        while(1)            //il C valuta 0 come falso e tutti gli altri numeri interi come vero
        {
            j = v[i] * v[i];
            if(j > n)
            {
                break;
            }
            do
            {
                v[j - 2] = 0;  //marco a 0 tutti i multipli
                j += v[i];
            }
            while(j <= n);
            while(v[++i] == 0);
        }
        
        printf("NUMERI PRIMI MINORI O UGUALI DI %u\n", n);
                 for(j = 0; j < n -1; ++j) {
            if(v[j])
            {
               printf("%u ", v[j]);
            }
                                       }           
              printf("\n");
                                                
        return 0;
                                                  }//end function
    
    
    
                               
    unsigned int main() {
    unsigned int (*apfunz[]) (unsigned int) = {insert,eratostene};    
    int i,n;
    
            printf("inserisci n deve essere >=2\n");
            scanf("%u",& n);   
    
    for(i=0;i<2;i++) {     //2 e' il numero delle funzioni nell'elenco
    
    (*apfunz[i])(n);  }   
    
                                 /*
    for(i=0;i<2;i++)          {
    printf("%u\n",apfunz[i]); } //indirizzi del puntatore a funzioni
    
    printf("\n");
                                */
    
    return 0;   }
    
  • Re: Domanda su inizializzazione puntatori a funzioni

    marittimo ha scritto:


    ..
    3) nel caso la domanda 1) sia vera (e pare esserlo), esiste un modo per aggirare il problema?
    ...
    NON HA SENSO passare ad una funzione puntatori a funzioni con signature (firme) diverse: il pezzo di codice che chiama la funzione identificata dal puntatore DEVE PASSARE IL NUMERO ED IL TIPO CORRETTO di valori, e DEVE RICEVERE come risultato IL VALORE DEL TIPO PREVISTO.
    A sua vola, la funzione chiamata DEVE RICEVERE il numero parametri corretto ed i valori dei parametri del tipo corretto.

    SE hai una funzione che non e' conforme con la signature richiesta, quello che si fa e' DEFINIRE una nuova funzione che HA la signatura giusta e CHIAMA la funzione con la signatura sbagliata, e fa le opportune conversioni.

    E' ASSOLUTAMENTE ERRATO sfruttare "debolezze" di questa logica, perche' si sta' SOTTOSTIMANDO i disastri che si potrebbero capitare.

    Un esempio di "debolezza" che 'funziona' e' usare una funzione che ritorna un valore E NON USARLO
    Un esempio di "debolezza" che NON FUNZIONA e' chiamare una funzione di tipo void e usare il valore ritornato: NON C'E' SCRITTO da nessuna parte che il valore ritornato ha un qualche senso ANCHE se MIRACOLOSAMENTE e' uno 0.
  • Re: Domanda su inizializzazione puntatori a funzioni

    Buon pomeriggio a tutti e grazie delle risposte.
    allora vediamo se ho capito o meno.
    
    int(*una)(int)
    
    una e' una variabile di tipo puntatore che punta a una funzione che ha in ingresso un intero e restituisce un intero
    
    int(*tre[3])(int)
    
    tre e' un vettore i cui elementi sono puntatori ciascuno dei quali punta a una funzione che ha in ingresso un intero e restituisce un intero
    
    int(*tre_bis[3])(int,float)
    
    tre_bis e' un vettore i cui elementi sono puntatori ciascuno dei quali punta a una funzione e questa funzione ha in ingresso un intero e un float
    quindi e' come se scrivessi
    
    int(*tre_bis[0])(int,float)
    int(*tre_bis[1])(int,float)
    int(*tre_ter[2])(int,float)
    
    ora se tutto quello di cui sopra e' corretto, nella fase di inizializzazione del puntatore a funzione posso scrivere
    
    int(*tre_bis[3])(int,float)={f0,f1,f2};
    
    il che equivale a scrivere
    
    int(*tre_bis[0])(int,float)=f0;
    int(*tre_bis[1])(int,float)=f1;
    int(*tre_bis[2])(int,float)=f2;
    
    a patto che f0,f1,f2 siano funzioni che ricevono in ingresso un int e un float e restituiscono un int.
    mi concedo licenza di proseguire con l'immunita' del dubbio.
    la mia domanda inziale era di questo tipo.
    e' possibile scrivere questo che sto scrivendo qui sotto?
    
    int(*tre_ter[0])(int,float,chart)=f0;
    int(*tre_ter[1])(int,float,*chart)=f1;
    int(*tre_ter[2])(int,float)=f2;
    
    e se si come dovrebbe essere scritto
    
    int(*tre_bis[3])(int,float,????????)
    
    ora nel mio primo listato in cima alla pagina avevo una situazione del genere; due funzioni ed il main che le richiamava con il puntatore a funzione.
    
    int f1 (void) 
    int f2 (int)
    
    sopra f 1 e' senza argomenti e ritorna un intero ed f 2 che aveva in ingresso l'intero ritornato da f 1 e ritornava a sua volta un intero.
    ora nella main quando ho scritto la sintassi del puntatore a queste due funzioni ho scritto qualcosa del genere
    
    int (*puntatore[2]) (void,int) ={f1,f2};
    
    e il risultato della compilazione mi restituiva un errore; in pratica cercavo di scrivere una qualche sintassi che rispondesse a quella scritta con i punti interrogativi di cui sopra e mi sembra di aver capito che in C non e' consentito fare cio', il caso che funziona e' quello del tre_bis.
    ora leggendo la risposta di migliorabile, credo di aver capito quello che lui cerca di dirmi; concordo anche sul primo esempio di debolezza da lui citato.
    sul secondo esempio di debolezza da lui citato credo di non seguirlo piu'; il motivo e' il seguente: nel mio primo listato ho creato una funzione void che restituisce un intero e poi ho usato questo valore nella funzione successiva, in questa funzione lo stesso valore compariva nei parametri; in definitiva quest'ultima parte a cui migliorabile fa riferimento mi e' piuttosto oscura.
    se qualcuno volesse provare ad aggiungere qualcosa riguardo questo punto sarebbe un grosso aiuto.
    per il momento grazie.
  • Re: Domanda su inizializzazione puntatori a funzioni

    Marittimo devi anche leggere quello che ti viene scritto. Cosa non ti è chiaro dell'operatore di ellissi?

    Sempre con la flag -fpermissive
    
    #include "stdio.h"
    
    struct chart{
        int n;
        float f;
    };
        
    void fun1(int n , float f){
        printf("%d\n", n);    
        printf("%f\n", f);    
    }
    
    void fun2(int n, float f, chart c){
        printf("%d\n", n);   
        printf("%f\n", f);
        printf("%d\n", c.n);   
        printf("%f\n", c.f);         
    }
    
    void fun3(int n, float f, chart * c){
        printf("%d\n", n);   
        printf("%f\n", f);
        printf("%d\n", c->n);   
        printf("%f\n", c->f);         
    }
    
    int main(void) {
        void (*p[3]) (int, float, ...) = {fun1, fun2, fun3};
        chart c = {10, 20.1};
        
        p[0](10, 10.5);
        p[1](5, 7.7, c);  
        p[2](5, 7.7, &c);
    
        return 0;
    }
    
    E comunque, ripeto, il guadagno pratico è nullo e i rischi sono alti. Prova lo stesso esempio con void (*p[3]) (...) oppure void (*p[3]) (int, ...) e auguri.

    Io non ci perderei altro tempo. Visto che ti interessano i numeri primi, ci sono degli algoritmi che riducono drasticamente il tempo di computazione rispetto a Eratostene. Prova a studiare quelli che sicuramente sono un argomento più utile
  • Re: Domanda su inizializzazione puntatori a funzioni

    Grazie della risposta Weierstrass.
    per quanto riguarda gli altri algoritmi ti riferisci al crivello quadratico di pomerance?
    credo di aver gia' implementato il crivello quadratico e il metodo di fermat e credo anche il metodo della successione rho, da qualche parte nel computer ho i codici.
    comunque sia quando ho tempo mi piace giocare un po con questi codici, tanto tempo fa avevo studiato il fortran 77, adesso sto cercando di imparare un po il C facendo qualche codice nel tempo libero.
    ho imparato anche a scrivere dati su un file da codice da dare in pasto a gnuplot, quello che sto cercando di capire ora e' se gnuplot o qualche altro widget mi permette di interagire cambiando qualche parametro e di restituirmi graficamente una sorta di "movimento grafico" che mi fa vedere come i punti si muovono.
    per essere meno vaghi per intenderci vorrei vedere come la funzione zeta di riemann mi fa muovere il punto del piano mentre do in pasto alla funzione i punti del piano che si trovano sulla retta di parte reale 0.5.
    io lo so gia' come si muovono, ma per giocare vorrei vederlo.
    giusto per finire il discorso sono nel bel mezzo della costruzione di una fresa a controllo numerico con un piano di lavoro di due metri per un metro e venti con la quale vorrei lavorare la parte in legno del coperchio della mia cassa da morto.
    ora qui si apre un vero dilemma, secondo mia figlia di 4 anni dovrei fresare sul coperchio l'immagine del suo gatto, secondo mia moglie la cifra approssimata per difetto di tutti i soldi che ho speso inutilmente e secondo un altro perditempo di un mio amico la parte reale della zeta di riemann.
    io vorrei andare per la terza scelta ma posizionare lo zero a meta' della mia altezza risulterebbe problematico per il fatto che non so come estendere analiticamente in prossimita' delle mie gambe questa funzione o meglio potrei specchiarla ma non conoscere la faccia di questa estensione mi disturba parecchio.
    forse potrei mettere lo zero vicino ai piedi e risolvere il problema.
    ci pensero'.
    nel frattempo vi ringrazio di cuore del tempo che mi avete dedicato, lo apprezzo veramente.
    PS a proposito andando fuori tema ancora se qualcuno ha qualche idea del perche' deve proprio essere 1 diviso 137 e rotti vi prego ditemelo.
Devi accedere o registrarti per scrivere nel forum
12 risposte