Questo sito utilizza cookies solo per scopi di autenticazione sul sito e nient'altro. Nessuna informazione personale viene tracciata. Leggi l'informativa sui cookies.
Username: Password: oppure
C/C++ - Problema con puntatori void
Forum - C/C++ - Problema con puntatori void

Avatar
AlessandroS (Normal User)
Newbie


Messaggi: 4
Iscritto: 12/11/2011

Segnala al moderatore
Postato alle 12:13
Sabato, 12/11/2011
Salve a tutti,

Avrei dei problemi a completare un programma in cui deve:
1) Creare due vettori A e B allocati dinamicamente ( new tipo[n]; ) con dimensione scelta da input , aventi un tipo che può essere unsigned short o float , tale tipo viene scelto durante l' esecuzione dall' user ( 0 se è unsigned short , 1 se è float ) . Per tale motivo ho dovuto utilizzare i puntatori a void.

2) Creare un vettore C di stessa dimension e tipo dei vettori A e B , i quali elementi i-esimi vengono calcolati nel seguente modo:

C = A / B se i è pari;
C = A^B ( elevato a B ) se i è dispari;

Dovendo creare un puntatore a funzione ( sempre perchè la traccia me lo richiede ).
3) Stamapare il Vettore C

Punti risolti: i punti 1) e 3) funzionano poichè, una volta letti i vettori A e B li ho stampati con il sottoprogramma che dovrei utilizzare per il vettore C e funziona

Problema: il punto 2) mi da problemi , per tale motivo vi incollo il sottoprogramma che applica la divisione ( identico per la potenza ) e penso che il problema consista in quello perchè durante l' esecuzione e precisamente nella stampa del vettore C , i risultati non sono esatti:

Codice sorgente - presumibilmente C++

  1. Codice:
  2.  void divisione ( void* A, void* B, void* C,const int t) {
  3.         if ( t == 0 )
  4.         {
  5.                 unsigned short *u = (unsigned short*)A;
  6.                 unsigned short *v = (unsigned short*)B;
  7.                 unsigned short *ris = new unsigned short;
  8.                 cout << "divisione "<< *u << "fratto "<< *v <<endl;
  9.                 *ris= *u/ *v;
  10.                 cout << "il risultato di e' "<< *ris<<endl;
  11.                 *(unsigned short*)C=*ris;
  12.         }
  13.         else
  14.         {
  15.                 float *u= (float*)A;
  16.                 float *v= (float*)B;
  17.                 float *ris= new float;
  18.                 *ris= *u/ *v;
  19.                 *(float*)C=*ris;
  20.         }
  21. }


quei cout mi servivano per utilizzare un debugging manuale  cmq da quei cout ho potuto vedere che cmq vengono presi giusti i valori nelle rispettive i-esime posizioni dei vettori A e B e anche il risultato *ris è giusto . Ma quando vado a stampare ( tramite un altro sottoprogramma ) il vettore C , mi da valori random. In conlusione penso che il problema sia nel comando *(unsigned short*)C= *ris; ---> non è giusto fare così? se si o se no mi potreste dire come potrei fare?

Se non vi è chiaro vi posso incollare tutto il programma che è diviso in 3 file.

Grazie in anticipo ,
Alessandro

PM Quote
Avatar
pierotofy (Admin)
Guru^2


Messaggi: 6230
Iscritto: 04/12/2003

Segnala al moderatore
Postato alle 17:42
Sabato, 12/11/2011
Come viene chiamato divisione? Posta tutto il codice.


Il mio blog: https://piero.dev
PM Quote
Avatar
AlessandroS (Normal User)
Newbie


Messaggi: 4
Iscritto: 12/11/2011

Segnala al moderatore
Postato alle 19:46
Sabato, 12/11/2011
mathop.h
Codice sorgente - presumibilmente C++

  1. #ifndef MATHOP_H_
  2. #define MATHOP_H_
  3.  
  4. #include <math.h>
  5. #include <typeinfo>
  6. typedef void (*pfunz)(void*,void*,void*,const int);
  7. void divisione ( void*, void*, void*,const int);
  8. void potenza ( void*, void*, void*,const int);
  9.  
  10.  
  11. #endif /* MATHOP_H_ */



mathop.cpp
Codice sorgente - presumibilmente C++

  1. #include "mathop.h"
  2. #include <iostream>
  3. using namespace std;
  4.  
  5. void divisione ( void* A, void* B, void* C,const int t) {
  6.         if ( t == 0 )
  7.         {
  8.                 unsigned short *u = (unsigned short*)A;
  9.                 unsigned short *v = (unsigned short*)B;
  10.                 unsigned short *ris = new unsigned short;
  11.                 cout << "divisione "<< *u << "fratto "<< *v <<endl;
  12.                 *ris= *u/ *v;
  13.                 cout << "il risultato di e' "<< *ris<<endl;
  14.                 *(unsigned short*)C=*ris;
  15.         }
  16.         else
  17.         {
  18.                 float *u= (float*)A;
  19.                 float *v= (float*)B;
  20.                 float *ris= new float;
  21.                 *ris= *u/ *v;
  22.                 *(float*)C=*ris;
  23.         }
  24. }
  25.  
  26. void potenza ( void* A, void* B, void* C,const int t) {
  27.         if ( t == 0 )
  28.         {
  29.                 unsigned short *u = (unsigned short*)A;
  30.                 unsigned short *v = (unsigned short*)B;
  31.                 unsigned short *ris = new unsigned short;
  32.                 cout << "potenza "<< *u << "alla "<< *v <<endl;
  33.                 *ris = pow(*u,*v);
  34.                 cout << "il risultato di e' "<< *ris<<endl;
  35.                 *(unsigned short*)C=*ris;
  36.  
  37.         }
  38.         else
  39.         {
  40.                 float *u= (float*)A;
  41.                 float *v= (float*)B;
  42.                 float *ris= new float;
  43.                 *ris= pow(*u,*v);
  44.                 *(float*)C=*ris;
  45.         }
  46. }



main.cpp
Codice sorgente - presumibilmente C++

  1. #include <iostream>
  2. #include "mathop.h"
  3. using namespace std;
  4.  
  5.  
  6. void leggi_vettore ( void *&, int , const int , const char nome);
  7. pfunz* produci_pfunz( const int );
  8. template <typename T>
  9. void inserimento( T *&, const int, const char);
  10. void produci_vettore ( void *,void * , void * , const int , const int , pfunz* );
  11. void stampa_Vettore ( void * C, const int n, const int t);
  12.  
  13. int main() {
  14.         int t , n;
  15.         void *A,*B,*C;
  16.         cout << "--> Inserisci il riemp:"<<endl;
  17.         cin >> n;
  18.         do
  19.         {
  20.         cout<< "--> 0 unsigned short"<<endl
  21.                 << "--> 1 per float "<<endl
  22.                 << "--> Inserisci il numero a seconda di che tipo vuoi creare il vettore: "<<endl;
  23.         cin >> t;
  24.         } while (( t !=1 ) && ( t != 0 ));
  25.         leggi_vettore(A,n,t,'A');
  26.         leggi_vettore(B,n,t,'B');
  27.         stampa_Vettore(A,n,t);
  28.         stampa_Vettore(B,n,t);
  29.         pfunz* f= produci_pfunz(n);
  30.         produci_vettore(C,A,B,n,t,f);
  31.  
  32.         cout << "--------------------> Stampa Vettore C <--------------------"<<endl;
  33.     stampa_Vettore(C,n,t);
  34.         return 0;
  35. }
  36.  
  37. void leggi_vettore ( void *& p_void, int n , const int t, const char nome) {
  38.         cout <<endl<< "---------> Lettura del Vettore "<< nome <<" <---------"<<endl;
  39.         if ( t == 0 )
  40.         {
  41.           unsigned short *u = new unsigned short[n];
  42.           inserimento ( u,n ,nome);
  43.           p_void = u ;
  44.         }
  45.         else
  46.         {
  47.            float *u= new float[n];
  48.            inserimento (u,n,nome);
  49.            p_void = u ;
  50.         }
  51.         cout << "---> Vettore "<< nome << " creato di tipo "<<
  52.                 ( ( t == 1 ) ? "float" : "unsigned short") ;
  53.         cout <<endl<<endl;
  54. }
  55.  
  56. template <typename T>
  57. void inserimento ( T *& u , const int n , const char nome)
  58. {
  59.          for ( int i =0 ; i < n ; i++ )
  60.          {
  61.                  cout << nome <<"["<< i <<"]: "<<endl;
  62.                  cin >> u[i];
  63.          }
  64. }
  65.  
  66. pfunz* produci_pfunz (  const int n ) {
  67.         pfunz* pf= new pfunz[n];
  68.     for ( int i =0 ; i< n ; i++)
  69.     {
  70.         if ( i%2== 0)
  71.                   pf[i]=&potenza;
  72.         else
  73.                 pf[i]=&divisione;
  74.      }
  75.     return pf;
  76. }
  77.  
  78. void produci_vettore ( void *C,void * A, void * B , const int n , const int t, pfunz* f ) {
  79.   if ( t == 0 )
  80.         {
  81.                 C = new unsigned short[n];
  82.                 unsigned short*u= (unsigned short*)A;
  83.                 unsigned short*v= (unsigned short*)B;
  84.                 for ( int i = 0; i< n ; i++)
  85.                 {
  86.                          cout << "vale: "<< i <<endl;
  87.                      f[i](u+i,v+i,C+i,t );
  88.             }
  89.         }
  90.   else
  91.     {
  92.            C = new float[n];
  93.            float*u= (float*)A;
  94.            float*v= (float*)B;
  95.            for ( int i = 0; i< n ; i++)
  96.                              f[i](u+i,B+i,v+i,t );
  97.     }
  98. }
  99.  
  100. void stampa_Vettore ( void * C, const int n, const int t)
  101. {
  102.         if ( t== 0)
  103.         {
  104.             unsigned short *u= (unsigned short*)C;
  105.             for ( int i =0; i< n ; i++)
  106.                     cout << "C["<<i<<"]: "<< u[i]<<endl;
  107.     }
  108.         else
  109.         {
  110.                 float *u= (float*)C;
  111.                 for ( int i =0; i< n ; i++)
  112.                         cout << "C["<<i<<"]: "<< u[i]<<endl;
  113.         }
  114. }



Ho messo tanti sottoprogrammi nel main solo perchè sono richiesti nella traccia. Cmq per quanto riguarda la chiamata è riferita al sottoprogramma produci_Vettore nel quale c'è un puntatore a funzione void che per ogni i-esimo ciclo chiama la funzione divisione o potenza. Se lo esegui potrai vedere che la lettura e la stampa dei vettori A e B funziona e anche il risultato della divisione/potenza per ogni i-esimo ciclo . L' unica cosa che non mi funzione è la stampa del vettore C quando chiamo la funzione stampa_Vettore. Il problema penso è che il risultato di ogni divisione/potenza non viene inserito nell' indirizzo giusto, cioè quello a cui punta C.

Grazie per l' interesse ^^
Alessandro

PM Quote
Avatar
pierotofy (Admin)
Guru^2


Messaggi: 6230
Iscritto: 04/12/2003

Segnala al moderatore
Postato alle 22:50
Sabato, 12/11/2011
Penso di aver trovato il problema:

Codice sorgente - presumibilmente C/C++

  1. for ( int i = 0; i< n ; i++)
  2.                 {
  3.                          cout << "vale: "<< i <<endl;
  4.                      f[i](u+i,v+i,C+i,t );
  5.             }



Quando fai:

Codice sorgente - presumibilmente Plain Text

  1. u + i



In realta' il compilatore, quando conosce le dimensioni di u (unsigned short = 2 bytes, float = 4 bytes) cambiera' il codice in:

Codice sorgente - presumibilmente Plain Text

  1. u + i * sizeof(tipo);



Ovviamente questo avviene implicitamente ed e' calcolato durante la compilazione. Ma e' impossibile sapere se utilizzerai un float oppure un unsigned short, quindi il compilatore probabilmente fara' un assunzione e utilizzera' uno o l'altro.

Il problema e' dimostrabile con questo programma:

Codice sorgente - presumibilmente C++

  1. #include <iostream>
  2.  
  3. void func(void *a, int t){
  4.      if (t == 0){
  5.         std::cout << (unsigned short *)a << std::endl;
  6.      }else{
  7.         std::cout << (float *)a << std::endl;    
  8.      }    
  9. }
  10.  
  11. int main(void){
  12.  unsigned short *a = new unsigned short[4];
  13.  for (int i = 0; i<4; i++){
  14.      a[i] = i;    
  15.  }
  16.  
  17.  for (int j = 0; j<4; j++){
  18.      func(a + j, 0);  
  19.  }
  20.  
  21.  std::cout << std::endl;
  22.  
  23.  for (int j = 0; j<4; j++){
  24.      func(a + j, 1);  
  25.  }
  26.  system("pause");
  27.  return 0;  
  28. }



Noterai che gli indirizzi hanno un offset di 2 bytes in entrambi i casi.

Cambiando le chiamate con:

Codice sorgente - presumibilmente C/C++

  1. func((unsigned short *)a + j, 0);
  2. // ...
  3. func((float *)a + j, 1);



Definendo esplicitamente il tipo di dato che stiamo passando, l'output e' invece corretto. Per gli unsigned short l'offset e' di 2 bytes, per il float e' di 4.

Prova a cambiare:
Codice sorgente - presumibilmente C++

  1. for ( int i = 0; i< n ; i++)
  2.                 {
  3.                          cout << "vale: "<< i <<endl;
  4.                      f[i]((unsigned short *)u+i,(unsigned short *)v+i,(unsigned short *)C+i,t );
  5.             }
  6.  
  7. // ...
  8.  
  9.                 for ( int i = 0; i< n ; i++)
  10.                 {
  11.                          cout << "vale: "<< i <<endl;
  12.                      f[i]((float *)u+i,(float *)v+i,(float *)C+i,t );
  13.             }



Ah, e per il futuro suggerisco di scegliere dei nomi migliori per le tue variabili e funzioni...


Il mio blog: https://piero.dev
PM Quote
Avatar
AlessandroS (Normal User)
Newbie


Messaggi: 4
Iscritto: 12/11/2011

Segnala al moderatore
Postato alle 12:17
Domenica, 13/11/2011
Salve ancora ^^,

Grazie per la disponibilità . Si ha ragione, i nomi non sono molto significativi , il problema è che mi devo attenere alla traccia che mi è stata data dal prof tra cui diceva anche i nomi delle funzioni, il tipo che dobbiamo utilizzare ecc.... però alcune variabili le ho assegnate io il nome per velocizzare, pensando che non avessi avuto problemi:D.
Comunque sia , ho capito quello che mi ha detto ma il punto è che facendo quel cambiamento la stampa è la stessa, cioè errata.

Ho risolto il problema utilizzando un debugging manuale ( utilizzando i cout :D ) semplicemente perchè il debugger di eclipse non mi piace molto ( e putroppo devo utilizzare eclipse :( ). mettendo dei cout in produci vettore :

Codice sorgente - presumibilmente C++

  1. [Code]
  2. void produci_vettore (   void* C, void * A, void * B , const int n , const int t,pfunz* f ) {
  3.   if ( t == 0 )
  4.         {
  5.                 unsigned short*res = new unsigned short[n];
  6.                 unsigned short*u= (unsigned short*)A;
  7.                 unsigned short*v= (unsigned short*)B;
  8.                 cout << "Indirizzo di res: "<<res<<endl;
  9.                 for ( int i = 0; i< n ; i++)
  10.                 {
  11.                          cout << "vale: "<< i <<endl;
  12.                      f[i]((unsigned short*)u+i,(unsigned short*)v+i,(unsigned short*)res+i,t );
  13.             }
  14.                 cout << "Indirizzo dopo operazione: res: "<<res<<endl;
  15.                 C=res;
  16.                 cout << "indirizzo di C: "<< C<<endl;
  17.                 return C;
  18.         }
  19.   else
  20.     {
  21.            float *res = new float[n];
  22.            float*u= (float*)A;
  23.            float*v= (float*)B;
  24.            for ( int i = 0; i< n ; i++)
  25.                              f[i]((float*)u+i,(float*)v+i,(float*)res+i,t );
  26.            C=res;
  27.            return C;
  28.     }
  29. }
  30. [/Code]



Ho notato che a fine creazione del vettore C, quest' ultimo punta all' inidirizzo giusto. L' errore , molto banale che non so come ho fatto a non pensarci è che poichè il puntatore C non viene passato per riferimento, l' indirizzo a cui punterà C alla fine del sottoprogramma verrà perso. Per ciò ho dovuto modificare il programma in questo modo:


Codice sorgente - presumibilmente C++

  1. [Code] void* produci_vettore ( void * A, void * B , const int n , const int t, pfunz* f ) {
  2.   void* C;
  3.   if ( t == 0 )
  4.         {
  5.                 unsigned short*res = new unsigned short[n];
  6.                 unsigned short*u= (unsigned short*)A;
  7.                 unsigned short*v= (unsigned short*)B;
  8.                 cout << "Indirizzo di res: "<<res<<endl;
  9.                 for ( int i = 0; i< n ; i++)
  10.                 {
  11.                          cout << "vale: "<< i <<endl;
  12.                      f[i]((unsigned short*)u+i,(unsigned short*)v+i,(unsigned short*)res+i,t );
  13.             }
  14.                 cout << "Indirizzo dopo operazione: res: "<<res<<endl;
  15.                 C=res;
  16.                 cout << "indirizzo di C: "<< C<<endl;
  17.                 return C;
  18.         }
  19.   else
  20.     {
  21.            float *res = new float[n];
  22.            float*u= (float*)A;
  23.            float*v= (float*)B;
  24.            for ( int i = 0; i< n ; i++)
  25.                              f[i]((float*)u+i,(float*)v+i,(float*)res+i,t );
  26.            C=res;
  27.            return C;
  28.     }
  29. }
  30. [/Code]



e ovviamente nel main:
Codice sorgente - presumibilmente C/C++

  1. Codice sorgente - presumibilmente C/C++

    void *C= produci_vettore(....);




Grazie infinite per la disponibilità ^^
Alessandro


Ultima modifica effettuata da AlessandroS il 13/11/2011 alle 12:24
PM Quote