Problemi sui Puntatori

di il
11 risposte

Problemi sui Puntatori

Salve,
ho qualche difficoltà a capire cosa sbaglio nella scrittura delle istruzioni di questo programma:

Occorre immagazzinare le seguenti informazioni su una persona: nome, età, altezza
e peso. Scrivere una funzione che legga i dati di una persona, ricevendo come parametro
un puntatore e un'altra funzione che li visualizzi.
#include <iostream>
using namespace std;
void visualizza (persona *, int);
void inserisci (persona *, int, void *(persona *, int));

struct persona
{
   char nome[30];
   int eta;
   double altezza;
   double peso;       
       }

main ()
{

     int n=0;
     cout << "Quante persone vuoi salvare? ";
     cin >> n;
     persona arr[n];
     persona *p;  // punto struttura
     p=arr;
     inserisci(p,n, visualizza(p,n); // invio come parametri l'array puntato, la dimensione e una funzione
     
     system("pause");
     return 0;
     }
     
void visualizza(persona ar[], int nn)
{
     cout << " Nella lista sono presenti le seguenti persone: ";
     for (int i=0; i<nn; i++)
     {
         cout << *ar[i]->nome << endl;
         cout << ar->nome << endl;
         }
         }
         
void inserisci(persona *ar, int nn, void *vis (persona *, int))
{
     cout << "Inserisci i campi utente: " << endl;
     for (int i=0; i<nn; i++)
     {
         cout << "Nome: "; cin >> arr[i].nome;
         cout << "Eta': "; cin >> arr[i].eta;
         cout << "Altezza: "; cin >> arr[i].altezza;
         cout << "Peso: "; cin >> arr[i].peso;
         }
         vis(ar, nn);
     }
Dovrei anche deallocare la memoria ma lo farò dopo... penso che ci sia qualche problema nei prototipi e i parametri che passo. La funzione inserisci ha come terzo parametro la funzione visualizza.....
Alcuni pezzi come visualizza li ho lasciati a metà e fatto delle prove li continuerò dopo...
Cosa sbaglio secondo voi?
grazie

11 Risposte

  • Re: Problemi sui Puntatori

    La sintassi del puntatore a funzione e il suo uso è sbagliata.
    Devi fare:
    
    void inserisci (persona *, int, void (*ptr_function)( int) );
    
    oppure
    
    typedef void (*PTR_FUNCTION)(int);
    void inserisci(persona* p, int nn, PTR_FUNCTION ptr_function);
    
    Il primo modo è locale alla funzione per usarlo una volta sola. Il secondo definisce un puntatore a funzione a cui può essere agganciato ogni funzione che rispetti il typedef.
    Poi è sufficiente solo il nome della funzione concreta come parametro reale alla funzione invocante.
    
    inserisci(p,n, visualizza);
    ...
    // in inserisci
    ...
    ptr_function(p, nn);
    ...
    
  • Re: Problemi sui Puntatori

    Poi è sufficiente solo il nome della funzione concreta come parametro reale alla funzione invocante.
    correttamente, da manuale, il puntatore andrebbe deferenziato;
    ma si può anche evitare oppure esagerare
    
    ...
    // in inserisci
    ...
    (******ptr_function)(p, nn);
    ...
    
  • Re: Problemi sui Puntatori

    ixamit ha scritto:


    correttamente, da manuale, il puntatore andrebbe deferenziato;
    Se non ricordo male in C è obbligatorio dereferenziarlo. In C++ tale vincolo è stato tolto per permettere l'uso di function objects senza cambiare l'algoritmo di fondo.
    (A dirla tutta in C++ i puntatori a funzione C style sono usati solo per interfacciarsi con codice legacy. Di solito si usano i function objects nel caso in esame.)
  • Re: Problemi sui Puntatori

    Ciao, grazie per la risposta....
    Inserisci prende come parametro visualizza che è una funzione che prende 2 parametri un array di tipo persona e un int. Perchè mettere
    void (*persona) (int)
    com eparametro di inserisci?
    Comunque non mi compila, mi dice:

    variable or field `visualizza' declared void
    `persona' was not declared in this scope
    expected primary-expression before "int"

    errori sin dalla prima riga....

    il prototipo delle funzioni lo scrivo così:
    void visualizza (persona are, int);
    void inserisci (persona *, int, void ( (*persona) (int) ) );
  • Re: Problemi sui Puntatori

    Godric ha scritto:


    ciao, grazie per la risposta....
    Inserisci prende come parametro visualizza che è una funzione che prende 2 parametri un array di tipo persona e un int. Perchè mettere
    void (*persona) (int)
    com eparametro di inserisci?
    Occhio che io ho scritto:
    
    void inserisci (persona *, int, void (*ptr_function)( int) );
    
    per non incasinare il compilatore dato che persona nel momento in cui la definisci diventa "riservata". E ho definito il prototipo così perché:
    1) è il modo in cui definiscono i puntatori a funzione senza il typedef;
    2) per rendere locale la definizione (con il typedef diventa globale, come detto prima).
    Comunque non mi compila, mi dice:
    Sposta i prototipi delle funzioni sotto la definizione di persona. In alternativa puoi scrivere:
    
    struct persona;
    
    sopra i prototipi di dette funzioni (utilizzando così la forward reference alla struttura).
  • Re: Problemi sui Puntatori

    Perdonami, ma ho difficoltà a capire. Cercherò di impostare il mio dubbio nel modo più semplice pox.
    
    struct persona
    {
       char nome[30];
       int eta;
       double altezza;
       double peso;       
           }
    
    void visualizza (persona *, int);
    void inserisci (persona *, int, void (*persona) (int));
    main ()
    {
    ...
    persona *arr=new persona[n];     
    inserisci(arr,n, visualizza(arr,n);
    ..}
    
    void visualizza(persona *ar, int nn)
    {...}
    
    void inserisci(persona *ar, int nn, visualizza(persona *, int))
    {...}
    
    Il propotipo inserisci come 3° parametro ha una funzione che prende un puntatore di tipo persona e un intero. Sul main passo correttamente il parametro?
    Nella funzione inserisci è corretto il 3° parametro così inserito?

    Per farlo funzionare correttamente come dovrei scriverlo? Potresti, se non chiedo troppo, farlo tu per me? Così io vedo un esempio pratico e capisco.
  • Re: Problemi sui Puntatori

    Pardon, avevo letto male il codice.
    La sostanza però non cambia molto, concettualmente almeno.
    Il prototipo corretto è:
    
    void inserisci (persona *, int, void (*ptr_function) (persona*, int) );
    
    il 3° parametro è un puntatore a funzione che restituisce void e accetta un puntatore a persona e un int. Quello che però deve esserti chiaro è che il nome del parametro che devi usare all'interno di inserisci() è ptr_function.
    Sul main passo correttamente il parametro?
    No. Devi passare solo il nome della funzione: visualizza in questo caso. In tutti gli altri casi passeresti il valore di ritorno della funzione, il che da errore di compilazione.

    Va usato così:
    
    ...
    void visualizza (persona *, int);
    void inserisci (persona *, int, void (*ptr_function)( persona*,  int ));
    main ()
    {
    ...
    persona *arr=new persona[n];     
    inserisci(arr,n, visualizza);
    ..}
    
    void visualizza(persona *ar, int nn)
    {...}
    
    void inserisci(persona *ar, int nn, void (*ptr_function)( persona*,  int ) )
    {
    ...
    ptr_function(ar,nn);
    ...
    }
    
  • Re: Problemi sui Puntatori

    Ok, molto prima avevo fatto così, ma mi dice questo:

    18 new types may not be defined in a return type
    18 two or more data types in declaration of `visualizza'
    18 In function `int main()':

    30 invalid conversion from `persona (*)(persona*, int)' to `void (*)(persona*, int)'
    ... altri errori

    Codice:
    #include <iostream>
    using namespace std;
    
    
    struct persona
    {
       char nome[30];
       int eta;
       double altezza;
       double peso;       
           }
    
    void visualizza (persona *, int);
    void inserisci (persona *, int, void (*ptr_function)(persona*,int));
    
    
    int main ()
    {
    
         int n=0;
         cout << "Quante persone vuoi salvare? ";
         cin >> n;
         persona *arr=new persona[n];
         
         inserisci(arr,n, visualizza); // invio come parametri l'array puntato, la dimensione e una funzione
         
         system("pause");
         return 0;
         }
         
    void visualizza(persona *ar, int nn)
    {
         cout << " Nella lista sono presenti le seguenti persone: ";
         for (int i=0; i<nn; i++)
         {
             cout << *ar[i]->nome << endl;
             cout << ar[i]->nome << endl;
             }
             }
             
    void inserisci(persona *ar, int nn, void (*ptr_function)(persona *, int))
    {
         cout << "Inserisci i campi utente: " << endl;
         for (int i=0; i<nn; i++)
         {
             cout << "Nome: "; cin >> arr[i].nome;
             cout << "Eta': "; cin >> arr[i].eta;
             cout << "Altezza: "; cin >> arr[i].altezza;
             cout << "Peso: "; cin >> arr[i].peso;
             }
             ptr_function(ar,nn);
         }
    
  • Re: Problemi sui Puntatori

    Stavo pensando.... xkè
    inserisci(arr,n, visualizza);
    non passiamo parametri a visualizza? come fa a sapere quale variabili prendere?
  • Re: Problemi sui Puntatori

    non passiamo parametri a visualizza? come fa a sapere quale variabili prendere?
    L'unica cosa che devi passare è l'indirizzo della funzione visualizza, e al momento della chiamata devi aggiungerci i parametri. visualizza è un indirizzo simbolo rilasciato dal compilatore per identificare la funzione, nonché il punto d'ingresso alla funzione stessa. I parametri vengono passati dal chiamante, come è consuetudine fare. Compreso questo concetto, devi semplicemente definirlo come hai visto sopra:
    mettendo delle parentesi nella funzione puntatore e definire i parametri.


    Un esempio in C di puntatore a funzione che passa un puntatore a struct. un int e ritorna un int.
    
    #include <stdio.h>
    typedef struct foo { const char *s; }foo;
    
    int trot(foo *foobar, int n)
    {
        while (n--)
            printf ("%s\n",foobar[n].s);
        return n; // return -1
    }
    
    int fox(foo *foobar, int n, int (*pf)(foo*, int n))
    {
        return (*pf)(foobar, n); // così
        return pf(foobar, n);	 // o così
    }
    
    int main ()
    {
        foo foobar[]={ {"aaa"},{"bbb"},{"ccc"},{"ddd"},{"..."} };
        int n=sizeof(foobar)/sizeof(foobar[0]);
    
        printf ("trot addr=%p\n"
                 "trot return %d\n", trot,fox(foobar, n, trot));
    	return 0;
    }
    
    
    Di seguito andiamo a ritrovare l'indirizzo della funzione nella symbol table dell'eseguibile
    
    % gcc prova.c -Wall
    % ./a.out
    ...
    ddd
    ccc
    bbb
    aaa
    trot addr=0x400584
    trot return -1
    %
    % objdump -t a.out | grep trot
    0000000000400584 g     F .text  000000000000003d              trot
    %
    
  • Re: Problemi sui Puntatori

    Adesso mi compila.... peò non funziona mi fa inseire solo 1 persona e mi d aquindi un risultato sbagliato.... come mai?
    #include <iostream>
    using namespace std;
    
    
    struct persona
    {
       char nome[30];
       int eta;
       double altezza;
       double peso;       
           };
           
    typedef void (*Pvisualizza)(persona f[], int r);
    void visualizza (persona f[], int);
    void inserisci (persona f[] , int, Pvisualizza fvisualizza);
    
    
    int main (void)
    {
    
         int n=0;
         cout << "Quante persone vuoi salvare? ";
         cin >> n;
         persona persona[n];
         
         inserisci(persona,n,visualizza); // invio come parametri l'array puntato, la dimensione e una funzione
         
         system("pause");
         return 0;
         }
         
    void visualizza(persona ar[], int nn)
    {
         cout << " Nella lista sono presenti le seguenti persone: ";
         for (int i=0; i<nn; i++)
            cout << ar[i].nome << endl;
                }
             
    void inserisci(persona ar[], int nn, Pvisualizza fvisualizza)
    {
         cout << "Inserisci i campi utente: " << endl;
         for (int i=0; i<nn; i++)
         {
             cout << "Nome: "; cin >> ar[i].nome;
             cout << "Eta': "; cin >> ar[i].eta;
             cout << "Altezza: "; cin >> ar[i].altezza;
             cout << "Peso: "; cin >> ar[i].peso;
             }
             fvisualizza(ar,nn);
         }
    
Devi accedere o registrarti per scrivere nel forum
11 risposte