Oppure

Loading
12/11/11 11:13
AlessandroS
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[i] = A[i] / B[i] se i è pari;
C[i] = A[i]^B[i] ( elevato a B[i] ) 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:
 void divisione ( void* A, void* B, void* C,const int t) {
	if ( t == 0 )
	{
		unsigned short *u = (unsigned short*)A;
		unsigned short *v = (unsigned short*)B;
		unsigned short *ris = new unsigned short;
		cout << "divisione "<< *u << "fratto "<< *v <<endl;
		*ris= *u/ *v;
		cout << "il risultato di e' "<< *ris<<endl;
		*(unsigned short*)C=*ris;
	}
	else
	{
		float *u= (float*)A;
		float *v= (float*)B;
		float *ris= new float;
		*ris= *u/ *v;
		*(float*)C=*ris;
	}
}

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
aaa
12/11/11 16:42
pierotofy
Come viene chiamato divisione? Posta tutto il codice.
Il mio blog: piero.dev
12/11/11 18:46
AlessandroS
mathop.h
#ifndef MATHOP_H_
#define MATHOP_H_

#include <math.h>
#include <typeinfo>
typedef void (*pfunz)(void*,void*,void*,const int);
void divisione ( void*, void*, void*,const int);
void potenza ( void*, void*, void*,const int);


#endif /* MATHOP_H_ */


mathop.cpp
#include "mathop.h"
#include <iostream>
using namespace std;

void divisione ( void* A, void* B, void* C,const int t) {
	if ( t == 0 )
	{
		unsigned short *u = (unsigned short*)A;
		unsigned short *v = (unsigned short*)B;
		unsigned short *ris = new unsigned short;
		cout << "divisione "<< *u << "fratto "<< *v <<endl;
		*ris= *u/ *v;
		cout << "il risultato di e' "<< *ris<<endl;
		*(unsigned short*)C=*ris;
	}
	else
	{
		float *u= (float*)A;
		float *v= (float*)B;
		float *ris= new float;
		*ris= *u/ *v;
		*(float*)C=*ris;
	}
}

void potenza ( void* A, void* B, void* C,const int t) {
	if ( t == 0 )
	{
		unsigned short *u = (unsigned short*)A;
		unsigned short *v = (unsigned short*)B;
		unsigned short *ris = new unsigned short;
		cout << "potenza "<< *u << "alla "<< *v <<endl;
		*ris = pow(*u,*v);
		cout << "il risultato di e' "<< *ris<<endl;
		*(unsigned short*)C=*ris;

	}
	else
	{
		float *u= (float*)A;
		float *v= (float*)B;
		float *ris= new float;
		*ris= pow(*u,*v);
		*(float*)C=*ris;
	}
}


main.cpp
#include <iostream>
#include "mathop.h"
using namespace std;


void leggi_vettore ( void *&, int , const int , const char nome);
pfunz* produci_pfunz( const int );
template <typename T>
void inserimento( T *&, const int, const char);
void produci_vettore ( void *,void * , void * , const int , const int , pfunz* );
void stampa_Vettore ( void * C, const int n, const int t);

int main() {
	int t , n;
	void *A,*B,*C;
	cout << "--> Inserisci il riemp:"<<endl;
	cin >> n;
	do
	{
	cout<< "--> 0 unsigned short"<<endl
		<< "--> 1 per float "<<endl
		<< "--> Inserisci il numero a seconda di che tipo vuoi creare il vettore: "<<endl;
	cin >> t;
	} while (( t !=1 ) && ( t != 0 ));
	leggi_vettore(A,n,t,'A');
	leggi_vettore(B,n,t,'B');
	stampa_Vettore(A,n,t);
	stampa_Vettore(B,n,t);
	pfunz* f= produci_pfunz(n);
	produci_vettore(C,A,B,n,t,f);

	cout << "--------------------> Stampa Vettore C <--------------------"<<endl;
    stampa_Vettore(C,n,t);
	return 0;
}

void leggi_vettore ( void *& p_void, int n , const int t, const char nome) {
	cout <<endl<< "---------> Lettura del Vettore "<< nome <<" <---------"<<endl;
	if ( t == 0 )
	{
	  unsigned short *u = new unsigned short[n];
	  inserimento ( u,n ,nome);
	  p_void = u ;
	}
	else
	{
	   float *u= new float[n];
	   inserimento (u,n,nome);
	   p_void = u ;
	}
	cout << "---> Vettore "<< nome << " creato di tipo "<<
		( ( t == 1 ) ? "float" : "unsigned short") ;
	cout <<endl<<endl;
}

template <typename T>
void inserimento ( T *& u , const int n , const char nome)
{
	 for ( int i =0 ; i < n ; i++ )
	 {
		 cout << nome <<"["<< i <<"]: "<<endl;
		 cin >> u[i];
	 }
}

pfunz* produci_pfunz (  const int n ) {
	pfunz* pf= new pfunz[n];
    for ( int i =0 ; i< n ; i++)
    {
    	if ( i%2== 0)
    		  pf[i]=&potenza;
    	else
    		pf[i]=&divisione;
     }
    return pf;
}

void produci_vettore ( void *C,void * A, void * B , const int n , const int t, pfunz* f ) {
  if ( t == 0 )
	{
		C = new unsigned short[n];
		unsigned short*u= (unsigned short*)A;
		unsigned short*v= (unsigned short*)B;
		for ( int i = 0; i< n ; i++)
		{
			 cout << "vale: "<< i <<endl;
		     f[i](u+i,v+i,C+i,t );
	    }
	}
  else
    {
	   C = new float[n];
	   float*u= (float*)A;
	   float*v= (float*)B;
	   for ( int i = 0; i< n ; i++)
	   		     f[i](u+i,B+i,v+i,t );
    }
}

void stampa_Vettore ( void * C, const int n, const int t)
{
	if ( t== 0)
	{
	    unsigned short *u= (unsigned short*)C;
	    for ( int i =0; i< n ; i++)
		    cout << "C["<<i<<"]: "<< u[i]<<endl;
    }
	else
	{
		float *u= (float*)C;
		for ( int i =0; i< n ; i++)
			cout << "C["<<i<<"]: "<< u[i]<<endl;
	}
}


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
aaa
12/11/11 21:50
pierotofy
Penso di aver trovato il problema:

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


Quando fai:

u + i


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

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:

#include <iostream>

void func(void *a, int t){
     if (t == 0){
        std::cout << (unsigned short *)a << std::endl;
     }else{
        std::cout << (float *)a << std::endl;    
     }     
}

int main(void){
 unsigned short *a = new unsigned short[4];
 for (int i = 0; i<4; i++){
     a[i] = i;    
 }
 
 for (int j = 0; j<4; j++){
     func(a + j, 0);   
 }
 
 std::cout << std::endl;
 
 for (int j = 0; j<4; j++){
     func(a + j, 1);   
 }
 system("pause");
 return 0;   
}


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

Cambiando le chiamate con:

func((unsigned short *)a + j, 0);
// ...
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:
                for ( int i = 0; i< n ; i++)
                {
                         cout << "vale: "<< i <<endl;
                     f[i]((unsigned short *)u+i,(unsigned short *)v+i,(unsigned short *)C+i,t );
            }

// ...

                for ( int i = 0; i< n ; i++)
                {
                         cout << "vale: "<< i <<endl;
                     f[i]((float *)u+i,(float *)v+i,(float *)C+i,t );
            }


Ah, e per il futuro suggerisco di scegliere dei nomi migliori per le tue variabili e funzioni...
Il mio blog: piero.dev
13/11/11 11:17
AlessandroS
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 :

[Code]
void produci_vettore ( void* C, void * A, void * B , const int n , const int t,pfunz* f ) {
if ( t == 0 )
    {
        unsigned short*res = new unsigned short[n];
        unsigned short*u= (unsigned short*)A;
        unsigned short*v= (unsigned short*)B;
        cout << "Indirizzo di res: "<<res<<endl;
        for ( int i = 0; i< n ; i++)
        {
             cout << "vale: "<< i <<endl;
         f[i]((unsigned short*)u+i,(unsigned short*)v+i,(unsigned short*)res+i,t );
     }
        cout << "Indirizzo dopo operazione: res: "<<res<<endl;
        C=res;
        cout << "indirizzo di C: "<< C<<endl;
        return C;
    }
else
{
     float *res = new float[n];
     float*u= (float*)A;
     float*v= (float*)B;
     for ( int i = 0; i< n ; i++)
              f[i]((float*)u+i,(float*)v+i,(float*)res+i,t );
     C=res;
     return C;
}
}
[/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:


[Code] void* produci_vettore ( void * A, void * B , const int n , const int t, pfunz* f ) {
void* C;
if ( t == 0 )
    {
        unsigned short*res = new unsigned short[n];
        unsigned short*u= (unsigned short*)A;
        unsigned short*v= (unsigned short*)B;
        cout << "Indirizzo di res: "<<res<<endl;
        for ( int i = 0; i< n ; i++)
        {
             cout << "vale: "<< i <<endl;
         f[i]((unsigned short*)u+i,(unsigned short*)v+i,(unsigned short*)res+i,t );
     }
        cout << "Indirizzo dopo operazione: res: "<<res<<endl;
        C=res;
        cout << "indirizzo di C: "<< C<<endl;
        return C;
    }
else
{
     float *res = new float[n];
     float*u= (float*)A;
     float*v= (float*)B;
     for ( int i = 0; i< n ; i++)
              f[i]((float*)u+i,(float*)v+i,(float*)res+i,t );
     C=res;
     return C;
}
}
[/Code]

e ovviamente nel main:
[Code] void *C= produci_vettore(....);[/Code]

Grazie infinite per la disponibilità ^^
Alessandro

Ultima modifica effettuata da AlessandroS 13/11/11 11:24
aaa