PDA

View Full Version : [C] Problema azzeramento valori struct a seguito di inserimento campo


NathanNever77
14-08-2011, 20:29
Ciao ragazzi,
premetto che è la prima volta che scrivo sul forum …ho letto il regolamento ma abbiate pietà per eventuali sviste.
E’ da tempo che mi sto scervellando su un problema con del codice in linguaggio C e dopo notti passate in bianco mi rivolgo a voi nella speranza di una soluzione. Utilizzo NetBeans con MinGW su Sistema operativo Windows 7.
Credo di trovarmi nella classica situazione in cui mi sfugge proprio un particolare che non riesco a mettere a fuoco e probabilmente si tratta di una cosa di facile soluzione per chi ha un minimo di esperienza di programmazione (ad averne più di me non ci vuole moto).
Introduco la questione: ho scritto del codice per gestire l’inserimento, la visualizzazione e la cancellazione di una struct su file. Questa struct contiene alcune informazioni relative ad una giocata con sistema al superenalotto come anno e numero del concorso, nome del sistema ed il sistema stesso.
(NOTA: per quanto riguarda il discorso cancellazione ora mi accontento di “azzerare” i valori dei campi ponendoli tutti uguali a -1)
Ora viene il bello: le righe di codice che allego sono FUNZIONANTI !


/* CODICE FUNZIONANTE */
/* Per passare al codice non funzionante riportare a codice i */
/* commenti sopra la righe indicate con HHH */

#include <stdio.h>
#include <string.h>

#define MAXRIGMAT 5
#define MAXCOLMAT 5

#define MENU 0
#define INS_SIS 1
#define CAN_SIS 2
#define RIC_SIS 3
#define VIS_TOT_SIS 4

#define OUT 100

/* DEFINIZIONE STRUCT */
struct s_sistema {
int s_n_anno; /* ANNO DEL CONCORSO */
int s_n_conc; /* NUMERO DEL CONCORSO */
char s_nome_sist[30]; /* NOME DEL SISTEMA */
int s_n_rig_mat; /* NUMERO DI RIGHE DEL SISTEMA */
int s_n_col_mat; /* NUMERO DI COLONNE DEL SISTEMA */
int s_n_quot; /* NUMERO DI QUOTE */
/* int s_n_parx; */ /* NUMERO DI PARTECIPANTI */
/* HHH */
int matrice[MAXRIGMAT][MAXCOLMAT]; /* MATRICE */
};

struct s_sistema sg; /* SISTEMA GIOCATO */

int rig, col; /* CONTATORI MATRICE */

FILE *fp_s; /* PUNTATORE A FILE PER IL SISTEMA */

int i;
int xx, yy;

/* DICHIARAZIONE DELLE FUNZIONI */
int men_gio(void);

void ins_sis(void);
void can_sis(void);
void eli_sis(long);
void vis_sis(void);
void ric_sis(void);
long cer_sis(int *, int *, char *);
void vis_tot_sis(void);

/************ M A I N ************/
void main()
{ int scelta=MENU;
while (scelta!=OUT) {
switch(scelta) {

/***** INIZIO MENU *****/
case MENU: {
scelta=men_gio();
if(scelta==MENU)
scelta=OUT;
break;
} /****** FINE MENU ******/


/***** INIZIO INS_SIS *****/
case INS_SIS: {
ins_sis();
scelta=MENU;
break;
} /****** FINE INS_SIS ******/


/***** INIZIO CAN_SIS *****/
case CAN_SIS: {
can_sis();
scelta=MENU;
break;
} /****** FINE CAN_SIS ******/


/***** INIZIO RIC_SIS *****/
case RIC_SIS: {
ric_sis();
scelta=MENU;
break;
} /****** FINE RIC_SIS ******/


/***** INIZIO VIS_TOT_SIS ****/
case VIS_TOT_SIS: {
vis_tot_sis();
scelta=MENU;
break;
} /****** FINE VIS_TOT_SIS ******/

} /****** FINE SWITCH ******/
} /***** FINE WHILE ******/
} /***** FINE MAIN ******/


/*********** DEFINIZIONE men_sis() *************/
int men_gio(void) {

int scelta;
char invio;
int vero=1;
while(vero) {
printf("\n\n OPZIONI: \n");
printf("\n 1. Inserisci sistema");
printf("\n 2. Cancella sistema");
printf("\n 3. Ricerca sistema");
printf("\n 4. Visualizza tutti i sistemi");
printf("\n\n Effettua la scelta: ");
scanf("%d", &scelta);
scanf("%c", &invio);

switch(scelta) {
case 0:
case 1:
case 2:
case 3:
case 4:
return(scelta);
default:
break;
} /* FINE SWITCH SCELTA */
} /* FINE WHILE */
return(0);
} /* FINE FUNZIONE */


/*********** DEFINIZIONE ins_sis() *************/
void ins_sis(void) {

char invio;
fp_s=fopen("sistemigiocati.dat", "a+");

/* INDICA L'ANNO DEL CONCORSO */
printf("\nInserisci l'anno del concorso (2 cifre): ");
scanf("%d", &sg.s_n_anno);
scanf("%c", &invio);

/* INDICA IL NUMERO DEL CONCORSO */
printf("\nInserisci il numero del concorso: ");
scanf("%d", &sg.s_n_conc);
scanf("%c", &invio);

/* INDICA IL NUMERO DI PARTECIPANTI */
/* sg.s_n_parx=10; */
/* HHH */

/* INDICA IL NUMERO DI QUOTE */
sg.s_n_quot=84;

/* INDICA IL NOME DEL SISTEMA */
printf("\nInserisci il nome del sistema giocato: ");
gets(sg.s_nome_sist);

/* INDICA IL NUMERO DI RIGHE DELLA MATRICE */
sg.s_n_rig_mat=3;

/* INDICA IL NUMERO DI COLONNE DELLA MATRICE */
sg.s_n_col_mat=sg.s_n_rig_mat;

/* CARICA LA MATRICE GIOCATA */
sg.matrice[0][0]=84;
sg.matrice[0][1]=9;
sg.matrice[0][2]=29;

sg.matrice[1][0]=7;
sg.matrice[1][1]=88;
sg.matrice[1][2]=69;

sg.matrice[2][0]=67;
sg.matrice[2][1]=27;
sg.matrice[2][2]=42;

/********* TRASFERIMENTO VALORI NELLA STRUCT ***********/
/* SCRITTURA SU FILE */
fwrite(&sg, sizeof(struct s_sistema), 1, fp_s);
fclose(fp_s);
}

/*********** DEFINIZIONE can_sis() ****************/
void can_sis() {
char pausa;
char invio;
int anno;
int conc;
char nome_sist[30];
long pos;
printf("\n\nInserisci l'anno del concorso (2 cifre): ");
scanf("%d", &anno);
scanf("%c", &invio);
printf("\n\nInserisci il numero del concorso: ");
scanf("%d", &conc);
scanf("%c", &invio);
printf("\n\nInserisci il nome del sistema: ");
gets(nome_sist);

/* INVOCA RICERCA SISTEMA */
pos=cer_sis(&anno, &conc, nome_sist);
printf("\n\n Il sistema si trova nella posizione: %ld", pos);

if(pos == -1) {
printf("\n\nSistema non presente nel database");
scanf("%c", &pausa);
return;
}

/* INVOCA VISUALIZZA SISTEMA */
vis_sis();
printf("\n\nConfermi la cancellazione ? (S/N) ");
scanf("%c", &pausa);
if (pausa=='S' || pausa=='s') {
eli_sis(pos);
return;
}
}


/*************** DEFINIZIONE eli_sis() *************/
void eli_sis(long pos) {
printf("\n\n Elimino il sistema nella posizione: %ld", pos);
/* Azzero i campi della struct */
sg.s_n_anno=-1;
sg.s_n_conc=-1;
strcpy(sg.s_nome_sist, "NONE");
sg.s_n_rig_mat=-1;
sg.s_n_col_mat=-1;
sg.s_n_quot=-1;
/* sg.s_n_parx=-1; */
for(xx=0;xx<MAXRIGMAT;xx++)
for(yy=0;yy<MAXCOLMAT;yy++)
sg.matrice[xx][yy]=-1;

/* Apro il file */
fp_s=fopen("sistemigiocati.dat", "r+");
/* Posiziono il fp */
fseek(fp_s,pos,0);
/* Scrivo */
fwrite(&sg, sizeof(struct s_sistema), 1, fp_s);
/* Chiudo */
fclose(fp_s);
}


/*********** DEFINIZIONE vis_sis() *************/
void vis_sis(void) {
printf("\n\nCONCORSO n. %d-%d", sg.s_n_anno, sg.s_n_conc);
printf("\n\nNome del sistema: %s", sg.s_nome_sist);
printf("\n\nIl sistema ha %d rig e %d col", sg.s_n_rig_mat, sg.s_n_col_mat);
printf("\n\nIl sistema ha %d quote ", sg.s_n_quot);
/* printf("\n\nIl sistema ha %d partecipanti", sg.s_n_parx); */
/* HHH */
printf("\n\n");
for(xx=0; xx<sg.s_n_rig_mat; xx++) {
printf("\n");
for(yy=0; yy<sg.s_n_col_mat; yy++)
printf(" %3d", sg.matrice[xx][yy]);
}
}


/*********** DEFINIZIONE vis_tot_sis() *************/
void vis_tot_sis(void) {
int n;
char pausa;
fp_s=fopen("sistemigiocati.dat", "r");

if(fp_s!=NULL) {

do {
n=fread(&sg, sizeof(struct s_sistema), 1, fp_s);

if(n==0)
fclose(fp_s);
else {
vis_sis();
scanf("%c", &pausa);
}

} while(n!=0);
}
else printf("\nIl file non esiste: non vi sono sistemi da visualizzare");
}


/*********** DEFINIZIONE ric_sis() *************/
void ric_sis(void) {
char invio;
char pausa;
int anno;
int conc;
char nome_sist[30];
long pos;
printf("\n\nInserisci l'anno del concorso (2 cifre): ");
scanf("%d", &anno);
scanf("%c", &invio);
printf("\n\nInserisci il numero del concorso: ");
scanf("%d", &conc);
scanf("%c", &invio);
printf("\n\nInserisci il nome del sistema: ");
gets(nome_sist);

/* INVOCA LA FUNZIONE DI SCANSIONE SEQUENZIALE cer_sis() */
pos=cer_sis(&anno, &conc, nome_sist);
if(pos==-1) {
printf("\n\nSistema non presente nel database");
scanf("%c", &pausa);
return;
}
vis_sis();
scanf("%c", &pausa);
}


/*********** DEFINIZIONE cer_sis() *************/
long cer_sis(int *ca, int *cc, char *cn) {
int n;
long pos=0L;
long h=0L;

fp_s=fopen("sistemigiocati.dat", "r");

for(;;) {

n=fread(&sg, sizeof(struct s_sistema), 1, fp_s);
if(n==0) {
fclose(fp_s);
pos=-1;
return(pos);
}
else
if(*ca==sg.s_n_anno)
if(*cc==sg.s_n_conc)
if(strcmp(cn, sg.s_nome_sist)==0)
{ pos=ftell(fp_s);
printf("\n A fine ricerca posizione fp: %ld ", pos);
fclose(fp_s);
h=(pos-sizeof(struct s_sistema));
printf("\n Dimensione struct: %ld", sizeof(struct s_sistema));
printf("\n Ritorno da ricerca posizione fp: %ld ", h);
return(pos-sizeof(struct s_sistema));
}
}
}


Il problema sorge quando provo ad aggiungere alla struct un ulteriore campo contenente le informazioni sul numero di partecipanti al sistema. [Queste 3 righe di codice sono messe come commento e le potete trovare al di sopra delle 3 righe di commento indicate con HHH ].
Nel momento in cui modifico la struct come descritto va in pratica a pallino il sistema di “cancellazione/azzeramento” dei valori della struct. Anziché valorizzare i campi con -1 compaiono dei valori casuali.
Quello che ho notato e vi dico come possibile indizio è che nel momento in cui aggiungo questo campo il file pointer torna dei valori strani (il 1° sistema della serie ad esempio non si trova più nella posizione 0 ma nella posizione 1) e credo che questo porti poi all’errato azzeramento dei valori.
Sono riuscito a spiegarmi?
Help!
Ciao e grazie
NN

LMCH
15-08-2011, 00:33
Il problema sorge quando provo ad aggiungere alla struct un ulteriore campo contenente le informazioni sul numero di partecipanti al sistema. [Queste 3 righe di codice sono messe come commento e le potete trovare al di sopra delle 3 righe di commento indicate con HHH ].
Nel momento in cui modifico la struct come descritto va in pratica a pallino il sistema di “cancellazione/azzeramento” dei valori della struct. Anziché valorizzare i campi con -1 compaiono dei valori casuali.
Quello che ho notato e vi dico come possibile indizio è che nel momento in cui aggiungo questo campo il file pointer torna dei valori strani (il 1° sistema della serie ad esempio non si trova più nella posizione 0 ma nella posizione 1) e credo che questo porti poi all’errato azzeramento dei valori.

Stai leggendo e scrivendo le struct in formato binario.
Significa che quando salvi su file i dati delle struct vengono presi "un byte alla volta" e ricopiati su file (e l'inverso quando li leggi).
Nel momento in cui aggiungi quel nuovo campo int, la dimensione in byte della struct aumenta (di 4 byte sotto windows) e sposta l'offset in memoria della matrice rispetto all'inizio della struct (di un int).
Significa che se avevi salvato dei dati su file "prima della modifica al programma", quando poi rileggi quei dati risultano sballati (l' n-esima struct sul file viene calcolata con un offset "sbagliato" di 4*n byte perchè ogni struct è spostata di 4 byte rispetto a quella immediatamente precedente).

E' per questo che quando si deve fare I/O su file di solito è meglio usare un qualche convenzione che permetta di riconoscere le versioni precedenti
(es: usare estensioni di file differenti, scrivere come primo dato nel file un int che indica il numero di versione, usare una libreria di I/O XML, i protocol buffers di Google, ecc. ecc.).

NathanNever77
15-08-2011, 08:12
Grazie mille LMCH,
ma dalla risposta che hai dato mi rendo conto che forse non mi sono spiegato bene …
Leggendo la tua risposta sembra che io:

- Mando in esecuzione il programma;
- Memorizzo 2 o 3 sistemi del superenalotto sul file “sistemigiocati.dat” [sulla base di una determinata struct];
- Modifico il programma aggiungendo un campo alla struct [in questo caso il numero di partecipanti];
- Mando nuovamente in esecuzione il programma;
- Memorizzo altri 2 o 3 sistemi sullo stesso file di prima [aventi ora però come base una struct diversa da quella dei sistemi già memorizzati e creando così il problema].

In realtà non è cosi.
Il problema che ho esposto si pone anche se io:

- Creo un nuovo progetto in Netbeans;
- Copio nel nuovo progetto il codice che so già in partenza non essere funzionante;
- Mando in esecuzione il programma;
- Etc, etc, …

Credo che nel momento io creo un nuovo progetto, il discorso da te fatto delle versioni precedenti del file dovrebbe venir meno, visto che sto lavorando in una nuova cartella.
Vuoi forse dire che nonostante questa ultima operazione rimane in qualche modo in memoria traccia della “vecchia struct” e risultano quindi vani i miei tentativi di partire da un nuovo progetto ???

LMCH
15-08-2011, 17:37
Il problema che ho esposto si pone anche se io:

- Creo un nuovo progetto in Netbeans;
- Copio nel nuovo progetto il codice che so già in partenza non essere funzionante;
- Mando in esecuzione il programma;
- Etc, etc, …

Credo che nel momento io creo un nuovo progetto, il discorso da te fatto delle versioni precedenti del file dovrebbe venir meno, visto che sto lavorando in una nuova cartella.
Vuoi forse dire che nonostante questa ultima operazione rimane in qualche modo in memoria traccia della “vecchia struct” e risultano quindi vani i miei tentativi di partire da un nuovo progetto ???

Non mi è chiaro come fai la copia.

Se fai la copia di tutta la cartella vecchia su quella nuova, se non sbaglio fai anche la copia di eventuali file di dati che ci possono essere.

Oppure potresti avere lo stesso problema se usi la stessa cartella per i dati in entrambi le versioni anche se il codice sorgente sta in una nuova cartella.

ESSE-EFFE
15-08-2011, 19:00
Ciao ragazzi,
Non ho controllato tutto il codice, comunque prova forzare l'apertura del file in modalità binaria.

NathanNever77
15-08-2011, 21:00
@ LMCH
Si, mi rendo conto di non riuscire a dire tutte le informazioni che gli altri utenti del forum necessitano per poter poi darmi una mano, ma è dura mettere per iscritto tutto.

Provo a riscrivere i passaggi esplicitando le azioni:

A) Creo un nuovo progetto in Netbeans;
-> Intendo dire che seleziono proprio un "New Project" dal menù principale di Netbeans e scelgo il nome. In questo modo NB crea una nuova cartella, diciamo "vergine", con il nome del nuovo progetto che ho deciso. E' quindi impossibile che in questo modo io mi "trascini dietro" file su disco creati con esecuzioni precedenti del mio programma perchè stanno nelle relative cartelle dei progetti vecchi.

B) Copio nel nuovo progetto il codice che so già in partenza non essere funzionante;
-> Una volta creato il nuovo progetto faccio il copia incolla del SOLO codice dal progetto precedente a quello nuovo. Non faccio quindi alcun copia incolla di cartelle.

C) Mando in esecuzione il programma;
-> Una volta che mando in esecuzione il programma, esso creerà il file "sistemigiocati.dat" su disco come nuovo di pacca, senza alcuna traccia delle versioni precedenti.

Rimane però il problema: se nel codice che copio lascio anche la possibilità di inserire il numero di partecipanti, al momento della cancellazione di un sistema il tutto va a ramengo.

Se copio il codice senza la possibilità di inserire il numero di partecipanti va tutto bene.

Dove cavolo sbaglio ???
- Devo piazzare qualche fflush() da qualche parte?
- Devo provare a salvare i dati in formato non binario? (ma si può fare?)
- Ho dimenticato un fclose() che manda il tutto pallino? Boh !

Sto veramente brancolando nel buio.
La cosa che mi scoccia è che è veramente l'ultimo passaggio che mi manca per avere un minimo di programma funzionante.....

-------------------------------------

@ESSE-EFFE

Perdonami ma guarda che io sono a livello base base. :banned:
Se mi dici di forzare l'aperura in binario mi mandi in crisi !!!

ESSE-EFFE
16-08-2011, 08:17
Perdonami ma guarda che io sono a livello base base. :banned:
Se mi dici di forzare l'aperura in binario mi mandi in crisi !!!
Ah, scusa, pensavo lo sapessi. Comunque basta aggiungere una 'b' nella modalità di apertura del file, per esempio invece di:

fp_s=fopen("sistemigiocati.dat", "a+");

dovresti usare:

fp_s=fopen("sistemigiocati.dat", "a+b");

Così facendo, tra l'altro, eviti che il valore EOF venga interpretato come tale.

NathanNever77
16-08-2011, 10:45
F U N Z I O N A ! ! ! :sbonk: :sbonk: :sbonk:
E U R E K A ! ! !
Grazie mille !!!

Prossima volta che passo Bergamo birra offerta ! :cincin:

Il codice che ho scritto si basa sulle nozioni apprese sul testo universitario che usai per dare l'esame di informatica; andrò a rivedere ma non mi sembra proprio che tirasse in ballo il discorso della forzatura in binario.

Mi sembra chiaro che devo approfondire le mie competenze con qualche altro testo sul linguaggio C; evito di chiedere consiglio qui per non andare Off-topic e consulterò la sezione del forum dedicata.

Nel frattempo smanetterò un po' sul web per approfondire, anche il discorso EOF

Grazie ancora !

NN