Newsgroup: it.comp.lang.c
Titolo: Quando i puntatori ti levano la vita!

Ciao a tutti!
Allora, Vi riporto un listato FUNZIONANTE, guardate:
**********************************************
#include<cstdio>
#include<cstdlib>
struct record{
char nome[20];
char cognome[20];
};
main(){
struct record vettore[3];
struct record vettore2[3];
int i, quanti;
FILE *file1;
/* lettura degli elementi da tastiera */
for(i=0;i<3;i++){
printf("\nInserisci il nome %d : ",i);
gets(vettore[i].nome);
printf("\nInserisci il cognome %d : ",i);
gets(vettore[i].cognome);
}
/* apertura file */
file1 = fopen("fileesempio.txt","wb");
if(file1==NULL){
fprintf(stderr,"\n\nErrore nell\'apertura del file1 1.\n\n");
exit(1);
}
/* caricamento file */
quanti = fwrite(vettore,sizeof(struct record),3,file1);
if(quanti != 3){
fprintf(stderr,"\n\nErrore nella scrittura del file1 1.\n\n");
exit(1);
}
/* chiusura e riapertura file */
fclose(file1);
file1 = fopen("fileesempio.txt","rb");
if(file1==NULL){
fprintf(stderr,"\n\nErrore nell\'apertura del file1 2.\n\n");
exit(1);
}
quanti = fread(vettore2,sizeof(struct record),3,file1);
if(quanti != 3){
fprintf(stderr,"\n\nErrore nella lettura del file1 2.\n\n");
exit(1);
}
fclose(file1);
for(i=0;i<3;i++){
printf("\n nome %d : %s",i,vettore[i].nome);
printf("\n cognome %d : %s",i,vettore[i].cognome);
printf("\n nome %d : %s",i,vettore2[i].nome);
printf("\n cognome %d : %s",i,vettore2[i].cognome);
}
return 0;
}
*****************************************
Questo stesso listato, se si utilizza un array di puntatori alla struttura,
non funziona.
Per essere precisi, se si utilizza un array di puntatori alla struttura,
durante l'ESECUZIONE
e il caricamento del file binario, c'è un messaggio che avverte che vettore1
è CORROTTO!
Secondo voi perché?
Io ho pensato che fosse dovuto al fatto che, nel momento in cui la funzione
fread() carica
dal disco il file, lo va a riscrivere dove vettore1 aveva allocato il suo
spazio, oppure gli si
sovrappone, cosa che non accade con il listato che ho riportato sopra.
Saprete spiegarmi, per cortesia, cosa accade se si utilizza
struct record *vettore[3];
struct record *vettore2[3];
(con ovviamente gli accessi giusti! tipo vettore[i]->nome eccetera!)
E per quale motivo dopo la lettura con fread() lo stesso listato dice
"vettore1 CORROTTO"?
Grazie!
                                 CcCc

 struct record *vettore2[3];
Probabilmente hai dimenticato di allocare dinamicamente
i tuoi record.
Cioe', se usi i puntatori, non basta dichiarare
il puntatore ma devi ovviamente allocare
(con le funzioni calloc o malloc) anche
lo spazio per le strutture che i puntatori punteranno.
(potresti anche aver fatto qualche altro tipo di errore,
ma questo e' il piu' comune. Comunque NON ho letto il
listatone.)
ciao,
g.

 i tuoi record.
Oltre a questa giusta considerazione, aggiungerei anche: non e' che, 
quando usi i puntatori alle strutture, sui file tu scrivi *i puntatori* 
e non i campi della struttura a cui essi puntano?? 
Cioe', attento a non fare fread() ed fwrite() di variabili puntatori, 
cioe', in altri termini: non devi scrivere su file binario degli 
"indirizzi".
Ciao
Dan

 struct record *vettore2[3];
Ciao, 
ti ho riportato nel seguito un esempio, basato sul tuo codice, pero' con 
un "look" un po' piu' "razionale" (nel senso di object-oriented, meglio 
organizzato, etc.), e che fa uso di strutture allocate dinamicamente.
Anche se siamo in C, un approccio ordinato "alla C++" fa sempre comodo 
(IMHO).
L'ho testato, e pare funzionare.
Dacci un'occhiata, se vuoi.
Spero ti sia utile.
Dan
[Segue codice:]
<CODE language="C">
// Header file della libreria standard del C
// NOTA: Sei in C non in C++, quindi #include <stdlib.h>
// e non #include <cstdilb> [C++]
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <string.h>
///////////////////////////////////////////////////////////
//      "OGGETTO" RECORD : STRUTTURA E OPERAZIONI
///////////////////////////////////////////////////////////
// Record
typedef struct tagRecord {
    char nome[20];
    char cognome[20];
} Record;
// Prototipi
Record * Record_New( void );
void Record_Set( Record * r, const char * nome, 
                 const char * cognome );
void Record_Print( const Record * r );
void Record_Input( Record * r );
void Record_WriteToFile( const Record * r, FILE * f );
void Record_LoadFromFile( Record * r, FILE * f );
Record * Record_CreateFromInput( void );
///////////////////////////////////////////////////////////
// NAME: Record_New
// DESC: Crea una nuova istanza della struttura Record
///////////////////////////////////////////////////////////
Record * Record_New( void )
{
    // Alloca struttura
    Record * r = (Record *) malloc( sizeof( Record ) );
    if ( r == NULL )
        return NULL;
    // Azzera i suoi membri
    memset( r, 0, sizeof( Record ) );
    // Ritorna puntatore all'istanza
    return r;
}
///////////////////////////////////////////////////////////
// NAME: Record_Set
// DESC: Imposta i campi della struttura
///////////////////////////////////////////////////////////
void Record_Set( Record * r, const char * nome, 
                 const char * cognome )
{
    assert( r != NULL );
    // Copia i campi
    strcpy( r->nome, nome );
    strcpy( r->cognome, cognome );
}
///////////////////////////////////////////////////////////
// NAME: Record_Print
// DESC: Stampa il contenuto della struttura
///////////////////////////////////////////////////////////
void Record_Print( const Record * r )
{
    assert( r != NULL );
    printf( "[ Nome = %s ; Cognome = %s ]", r->nome, r->cognome );
}
///////////////////////////////////////////////////////////
// NAME: Record_Input
// DESC: Chiede in input all'utente il contenuto del record
///////////////////////////////////////////////////////////
void Record_Input( Record * r )
{
    assert( r != NULL );
    printf( "\nInserisci il nome: " );
    gets( r->nome );
    printf("\nInserisci il cognome: " );
    gets( r->cognome );
}
///////////////////////////////////////////////////////////
// NAME: Record_WriteToFile
// DESC: Scrivi su file il contenuto della struttura
///////////////////////////////////////////////////////////
void Record_WriteToFile( const Record * r, FILE * f )
{
    assert( r != NULL );
    assert( f != NULL );
    fwrite( r, sizeof( Record ), 1, f );
}
///////////////////////////////////////////////////////////
// NAME: Record_LoadFromFile
// DESC: Carica da file il contenuto della struttura
///////////////////////////////////////////////////////////
void Record_LoadFromFile( Record * r, FILE * f )
{
    assert( r != NULL );
    assert( f != NULL );
    fread( r, sizeof( Record ), 1, f );
}
///////////////////////////////////////////////////////////
// NAME: Record_CreateFromInput
// DESC: Crea un record da input utente
///////////////////////////////////////////////////////////
Record * Record_CreateFromInput( void )
{
    Record * r = NULL;
    // Crea il record
    r = Record_New();
    if ( r == NULL )
        return NULL;    // errore :(
    // Leggi da tastiera
    Record_Input( r );
    // Ritorna record letto
    return r;
}
///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
// NAME: ExitError
// DESC: Esce con un messaggio di errore
///////////////////////////////////////////////////////////
void ExitError( const char * msg )
{
    fprintf( stderr, "**ERRORE**: %s\n", msg );
    exit( 1 );
}
///////////////////////////////////////////////////////////
// NAME: main
// DESC: Test
///////////////////////////////////////////////////////////
int main()
{
    // Dove registrare i record
#define RECORD_FILE_NAME    "database.dat"
    // Quanti ce ne sono
#define QUANTI      3
 
    // Uso puntatori a struttura
    Record * vettore [QUANTI];
    Record * vettore2[QUANTI];
    int i, quanti;
 
    FILE *db = NULL;
    //
    // FASE 1 - POPOLARE DATABASE CON I RECORD
    //
    // Ripuliamo tutti i puntatori, come prima cosa, 
    // cosi' non abbiamo valori spuri 
    for ( i = 0; i < QUANTI; i++ )
        vettore[i] = vettore2[i] = NULL;
    // Lettura degli elementi da tastiera
    for ( i = 0; i < QUANTI; i++ )
        vettore[i] = Record_CreateFromInput();
 
    //
    // FASE 2 - SALVATAGGIO SU FILE
    //
    // Salva su file
    db = fopen( RECORD_FILE_NAME, "wb" );
    if ( db == NULL )
        ExitError( "Non posso creare il file per scrivere i record." );
    // Scrivi i record su file
    for ( i = 0; i < QUANTI; i++ )
        Record_WriteToFile( vettore[i], db );
    // Chiudi il file col DB
    fclose( db );
    db = NULL;
    //
    // FASE 3 - RICARICARE IL DB DA FILE
    //
    // Apri il file
    db = fopen( RECORD_FILE_NAME, "rb" );
    if ( db == NULL )
        ExitError( "Non posso aprire il file per leggere i record." );
    // Leggi i record nel vettore 2
    for ( i = 0; i < QUANTI; i++ )
    {
        vettore2[i] = Record_New();
        if ( vettore2[i] == NULL )
            ExitError( "Non posso allocare un nuovo record." );
        Record_LoadFromFile( vettore2[i], db );
    }
    // Chiudi il file
    fclose(db);
    db = NULL;
    // Stampa cioe' che e' stato letto, per verifica
    for ( i = 0; i < QUANTI; i++ )
    {
        printf( "\nNUMERO : %d\n\n", (i+1) );
        printf( "Record iniziale: " );
        Record_Print( vettore[i] );
        printf( "\nRecord riletto da file: " );
        Record_Print( vettore2[i] );
 
        printf( "\n-----------------------------\n" );
    }
    system( "PAUSE" );
    return 0;
}
///////////////////////////////////////////////////////////
</CODE>