PDA

View Full Version : [C] Passaggio array a funzione


salvodel
30-12-2007, 11:06
Dal titolo il problema sembrerebbe semplice ma spiegando meglio credo che sia ancora piu semplice. Sto utilizzando del codice al cui interno è presente una funzione con la seguente intestazione:
void func(double *p, double *x, int m, int n, void *data)
L'autore inserito una variabile aggiuntiva non utilizzata all'interno della funzione per permettere a chiunque di aggiungere una propria variabile. Il problema nasce nel momento in cui io voglio fare una cosa del genere:
void func(double *p, double *x, int m, int n, double *data1, double *data2, double *data2)
Ovviamente questo mi da errore poiche la funzione non è definita cosi in tutte le altre parti del programma. A questo punto non so se è giusto e vantaggioso andare a modificare tutte le intestazioni della funzione presente nei vari file .c e .h oppure trovare una soluzione migliore al problema.
In un primo momento avevo pensato di inserire all'interno della funzione la lettura dei file e creare li dentro gli array di cui ho bisogno. Questa soluzione salvo mie sviste non è possibile poiche ci deve essere all'interno del programma un ciclo for che mi fa eseguire la lettura n volte.
Volevo sapere una vostra idea sulla soluzione di questo problema. Per adesso ancora non ho provato ma cercando su internet ho trovato questa soluzione, ditemi se è giusta:

typedef double **matrice;
matrice data; /* Dichiara la matrice */

... /* Trova il valore di n */

a = calloc(dim1, sizeof *a); /* Alloca vettore di puntatori */
if ( !a ) { ... }
for (i=0: i<n: i++) {
a[i] = calloc(dim2, sizeof *a) /* Alloca i-esima riga */
if ( !a[i] ) { ... }
}

... /* Usa la matrice */
for (i=0; i<n; i++) /* Libera la memoria */
free(a[i]);
free(a);

Un solo dubbio:confused: : la prima calloc mi genera il numero di colonne mentre la seconda il numero di righe? Quindi nel mio caso avendo tre array dovrei fare una cosa del genere:
dim1=3;
dim2=numero_punti;
Giusto?
Grazie a tutti.

salvodel
02-01-2008, 08:29
# How can I pass my own data?

Assume that you want to pass two arrays, one of doubles and one of integers. A quick but not very elegant solution is to use global variables. The simplest way to avoid using globals is to declare a structure as

struct mydata{
double dar[XXX];
int iar[YYY];
};

where XXX and YYY denote the appropriate array sizes. Then, define a structure variable with

struct mydata data;

and fill it:

data.dar[0]=7.0;
data.iar[0]=-17;
// etc

Following this, call the appropriate LM routine passing it the address of data as the adata argument, e.g.

ret=dlevmar_der(func, fjac, ..., (void *)&data);

Your func and fjac routines should interpret the supplied data using type casting:

struct mydata *dptr;

dptr=(struct mydata *)adata; // adata is passed as void *

// supplied data can now be accessed as dptr->dar[0], etc

Ho trovato questa soluzione ma non ho ben capito i passaggi nelle righe finali. Nella prima parte crea una struttura dati e passa l'indirizzo. Successivamente fa il type casting ma non ho capito bene. Provo ascrivere come ho capito:

struct mydata
{
double vet1[100];
double vet2[100];
}

.....

struct mydata dati;
Alla funzione incriminata passo l'indirizzo di dati. All'interno della funzione faccio il type casting?
Cioè mi ricreo una nuova variabile
struct mydata *dati_fun;
faccio il type casting
dati_fun=(struct mydata *)?????
All'interno della funzione accedo ai dati con
dati_fun.vet1[];
dati_fun.vet2[];
Dove cisono i punti interrogativi non mi è chiaro il passaggio.:confused:
Grazie a tutti e buon inizio anno.

cionci
02-01-2008, 09:42
Allora...

struct MyData {
double *data1;
double *data2;
double *data3;
double *data4;
double *data5;
} data;

data.data1 = myData1;
...
...
data.data5 = myData5;

func(a, b, c, d, e, (void *)&data);

Dentro a func ovviamente se vuoi usare i tuoi dati devi ottenere nuovamente il puntatore alla struttura:

struct MyData *myData = (struct MyData *)data; //data è il puntatore a void passato

A questo punto puoi utilizzare come vuoi la struttura con myData->data1...etc etc

salvodel
02-01-2008, 15:21
A questo punto puoi utilizzare come vuoi la struttura con myData->data1...etc etcPrima di tutto grazie mille come al solito.
Ho provato a farlo girare ma non va ma credo di aver fatto alcuni errori
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <float.h>
#include "lm.h"

#define batch 10
#define stringa "OUTPUT.DAT"

void errore(double *p, double *x, int m, int n, (void *)&data)
{
int ii,jj,kk,t;
int S=10;
struct mydata *matricedati= (struct mydata *)data;

double u[2][batch];
double d[2][batch];
double err;
/*..................*/
}

int main()
{
struct mydata
{
double vet1[100];
double vet2[100];
}
struct mydata data;
register int i, j;
int problem, ret;
/*..................*/
ret=dlevmar_dif(errore, p, x, m, n, 1000, opts, info, NULL, NULL, NULL);
/*..................*/
return 0;
}
In rosso ci sono i punti incriminati. Dove c'è NULL devo mettere (void *)&data?

extern int dlevmar_dif(
void (*func)(double *p, double *hx, int m, int n, void *adata),
double *p, double *x, int m, int n, int itmax, double *opts,
double *info, double *work, double *covar, void *adata);
La cosa che non mi è chiara è perche devo passare i dati in dlevmar_dif quando a me servono nella funzione errore?

cionci
02-01-2008, 15:28
La funzione la devi definire così:

void errore(double *p, double *x, int m, int n, void *data)
{
}

Il passaggio del parametro lo devi fare con (void *)&data.
Inoltre la struct la devi dichiarare all'esterno del main e prima della definizione di errore.

Mi dici chi ti ha nominato dlevmar_dif ? Non mi sembra di averne mai parlato nel post precedente :mbe:

salvodel
03-01-2008, 10:37
La funzione la devi definire così:

void errore(double *p, double *x, int m, int n, void *data)
{
}Questa è gia definita cosi dall'autore ma mi sa che i dati non li devo passare da qui...Il passaggio del parametro lo devi fare con (void *)&data.
Inoltre la struct la devi dichiarare all'esterno del main e prima della definizione di errore.

Mi dici chi ti ha nominato dlevmar_dif ? Non mi sembra di averne mai parlato nel post precedente :mbe:

La funzione dlevmar_dif non l'hai citata tu ma era presente nelle FAQ del sito dove l'ho scaricato. Mi sa che devo fare un passaggio per me un po strano.
Correggimi se sbaglio:
Nella dlevmar_dif passo i dati come mi hai detto tu (void *)&data nel terzo NULL in rosso poi credo che lo faccia in automatico la dlevmar_dif il passaggio dei dati alla funzione errore.
Nella funzione errore invece devo mettere struct mydata *matricedati= (struct mydata *)data;
Un ultimo chiarimento
A questo punto puoi utilizzare come vuoi la struttura con myData->data1...etc etc
In C la utilizzo con myData.data1 giusto? quella è la notazione da C++?
Di nuovo grazie

cionci
03-01-2008, 11:52
Questa è gia definita cosi dall'autore ma mi sa che i dati non li devo passare da qui...
Appunto...sei te che ne codice che hai postato hai modificato l'ultimo parametro in:

void errore(double *p, double *x, int m, int n, (void *)&data)
{
}

Quella modifica non va fatta...

La funzione dlevmar_dif non l'hai citata tu ma era presente nelle FAQ del sito dove l'ho scaricato. Mi sa che devo fare un passaggio per me un po strano.
Correggimi se sbaglio:
Nella dlevmar_dif passo i dati come mi hai detto tu (void *)&data nel terzo NULL in rosso poi credo che lo faccia in automatico la dlevmar_dif il passaggio dei dati alla funzione errore.

Evidentemente dlevmar_dif era un nome di funzione d'esempio :D
(void *)&data lo devi fare nella chiamata della funzione errore, non nella definizione della funziona come avevi messo...

Un ultimo chiarimento

In C la utilizzo con myData.data1 giusto? quella è la notazione da C++?

Mi sa che devi ripassarti un po' di C ;)
myData è un puntatore e come tale per accedere agli elementi della struttura dati bisogna usare l'operatore ->.
myData->data1 equivale a (*myData).data1

salvodel
04-01-2008, 09:21
Mi sa che devi ripassarti un po' di C ;)
Grazie a qualche tua strigliata:cry: ed ai molti consigli :ave: sono riuscito a risolvere alcuni problemi.
Appunto...sei te che ne codice che hai postato hai modificato l'ultimo parametro in:

void errore(double *p, double *x, int m, int n, (void *)&data)
{
}

Quella modifica non va fatta...

Evidentemente dlevmar_dif era un nome di funzione d'esempio :D
(void *)&data lo devi fare nella chiamata della funzione errore, non nella definizione della funziona come avevi messo...
Ti scrivo la procedura corretta giusto se ti puo interessare visto che forse non mi sono spiegato bene.
Io scrivo la funzione errore e le operazioni base le fa la funzione dlevmar_dif. Per passare i dati alla funzione errore non devo far altro che passarli alla funzione dlevmar_dif che li passa alla funzione errore.
Il mio problema ora è che quello che faccio dentro la funzione errore mi viene ripetuto troppe volte...ma di questo te ne parlero nelle prossime ore dopo averci sbattutto un bel po la testa.
Grazie

cionci
04-01-2008, 09:24
Io non ho capito ancora cos'è questa dlevmar_dif e se fa parte della tua libreria o no :D
Non è che mi dici come è definita ?

salvodel
04-01-2008, 09:42
Io non ho capito ancora cos'è questa dlevmar_dif e se fa parte della tua libreria o no :D
Non è che mi dici come è definita ?

E' il cuore del programma ed è cosi definita:
extern int dlevmar_dif(
void (*func)(double *p, double *hx, int m, int n, void *adata),
double *p, double *x, int m, int n, int itmax, double *opts,
double *info, double *work, double *covar, void *adata);
Come vedi io gli passo la funzione di cui voglio trovare i minimi, nel mio caso la funzione errore. Io sbagliavo il passaggio dei dati proprio qui: li davo nella funzione errore invece li dovevo dare in dlevmar_dif.
Ora ho un dubbio: l'ultimo parametro della func si chiama data ma se faccio come mi dice le

edit

cionci
04-01-2008, 09:45
Mi fai vedere come richiami il tutto ?

salvodel
04-01-2008, 09:53
Mi fai vedere come richiami il tutto ?

Per problemi di stabilità:D avevo inviato e poi stavo facendo un edit.

Ora ho un dubbio: l'ultimo parametro della func si chiama data ma se faccio come mi dice leFAQ (http://www.ics.forth.gr/~lourakis/levmar/faq.html#Q9) mi da errore? Se invece metto data il programma gira e si pianta per altri motivi che adesso andrò ad indagare
Come al solito grazie per l'interessamento. Ti invio il programma spolpato di tutte le cose che non servono...se cosi è poco chiaro ti metto anche il resto.

/********************************************************************************
* Levenberg-Marquardt minimization.
********************************************************************************/

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

#include "lm.h"

#define stringa "OUTPUT.DAT"
#define esp 2.718281828459

struct mydata{
double t[100];
double X[100];
double XP[100];
double XPP[100];
double TETAG[100];
double WIND[100];
double d[100];
} data;


/********************************************************************************
* Lettura dati da file "OUTPUT.DAT".
********************************************************************************/

int legge(int punti)
{
FILE *fp;
int i=0;

if((fp=fopen(stringa,"r"))==NULL)
printf("Impossibile aprire il file");
else
{
printf("Dati letti:\n");
while(fscanf(fp,"%LE %LE %LE %LE %LE %LE %LE",&data.t,&data.X[i],&data.XP[i],&data.XPP[i],&data.TETAG[i],&data.WIND[i],&data.d[i])>0)
{
printf(".");
i++;
if(i>100)
{
printf("\n");
break;
}
}
for(i=0;i<100;i++)
printf("%.4g\t",data.t[i]);
printf("\n");
}

fclose(fp);

return i;
}

/********************************************************************************
* Funzione dell'errore quadratico.
********************************************************************************/

void errore(double *p, double *x, int m, int n, void *data)
{
struct mydata *dptr;
dptr=(struct mydata *)[I]adata;

/*Definizione delle coppie ingresso-uscita*/
for(t=0; t<40; t++)
{
u[0][t] = dptr->X[t];
u[1][t] = dptr->XP[t];
u[2][t] = dptr->XPP[t];
u[3][t] = dptr->TETAG[t];
u[4][t] = dptr->WIND[t];
}
printf("\nAssegnazione vaolri u \n");

for(t=0; t<40; t++)
{
d[0][t] = dptr->X[t];
d[1][t] = dptr->XP[t];
d[2][t] = dptr->XPP[t];
}

}

/********************************************************************************
* M A I N.
********************************************************************************/

int main()
{

legge(punti);

ret=dlevmar_dif(errore, p, x, m, n, 1000, opts, info, NULL, NULL, (void *)&data);

}

cionci
04-01-2008, 10:06
Ovviamente lì ci deve essere data e non adata ;)
La chiamata dovrebbe essere corretta.

salvodel
04-01-2008, 10:07
Ovviamente lì ci deve essere data e non adata ;)
La chiamata dovrebbe essere corretta.

quindi è un errore delle FAQ?:confused:

cionci
04-01-2008, 10:19
quindi è un errore delle FAQ?:confused:
Probabilmente nell'implementazione avevano dato il nome adata e non data all'ultimo parametro...dopo tutto il nome lo puoi cambiare a piacimento ;)

salvodel
04-01-2008, 11:52
Probabilmente nell'implementazione avevano dato il nome adata e non data all'ultimo parametro...dopo tutto il nome lo puoi cambiare a piacimento ;)
Ciao cionci stavo rileggendo le FAQ (http://www.ics.forth.gr/~lourakis/levmar/faq.html#Q9) e mi è venuto un dubbio: li dice che se utilizzo la struttura non devo definirla globale. Giusto?
Visto che ci siamo ti chiedo un'altra cosa: ho 7 vettori ma non voglio passarli comestruct mydata {
double vet1;
double vet2;
......
double vet7;
} data;
poiche non posso o meglio non so come utilizzarli in un ciclo for. Non so se sono stato chiaro. Ti faccio vedere che cosa ha partorito la mia mente
struct mydata {
double mat[7][100];
} data;

for(i=0;i<7;i++)
for(j=0;j<100;j++)
data.mat[i][j]

Ci sono soluzioni piu ovvie oppure semplicemente nelle FAQ (http://www.ics.forth.gr/~lourakis/levmar/faq.html#Q9) utilizza le strutture ma potrei utilizzare nel mio caso direttamente l'array?
Grazie

cionci
04-01-2008, 13:51
Puoi mettere anche una matrice così come l'hai definita te...in pratica in quella struttura ci puoi mettere quello che ti pare ;)
La struttura la devi definire globale...l'istanza della struttura (cioè "data") la devi dichiarare locale. Infatti dice che definire quella struttura è un modo per evitare variabili globali.

salvodel
04-01-2008, 15:02
Puoi mettere anche una matrice così come l'hai definita te...in pratica in quella struttura ci puoi mettere quello che ti pare ;)
La struttura la devi definire globale...l'istanza della struttura (cioè "data") la devi dichiarare locale. Infatti dice che definire quella struttura è un modo per evitare variabili globali.
Ho detto un'altra c.....:ops2:
Cmq oggi, finalmente, sono riuscito ad utilizzare questo programmino ed il merito è tuo. Ti ringrazio per la pazienza ed i tanti consigli che mi hai dato.
Visto che siamo in fase di ringraziamento anche se quasi certamente non apriranno mai questo post voglio ringraziare

variabilepippo
wingman87
amedeoviscido
Ziosilvio
gepeppe
71104
andbin
yorkeiser

Un ultimo speciale ringraziamento lo devo fare a mad_hhatter che mi ha spesso aiutato su alcuni dubbi "matematici".
Di nuovo grazie a tutti anche a chi non compare nella lista per una mia mancanza.:vicini: :ubriachi: :mano: :ave: :cincin:

cionci
04-01-2008, 15:04
Bene ;) Di niente :)