E ora, la versione corredata da una "graziosissima" classe...
file main.cpp
#include <stdlib.h>
#include <stdio.h>
#include "classe_esame.h"
#define LMAX_RIGA 1023 // ogni riga del file non deve eccedere questa lunghezza
const char kStrNomeFile[] = "dati.txt"; // il nome del file da leggere
/** ==> PROTOTIPI <==========================================================**/
Esame *carica_dati_esami( const char *nf, int *qe );
void stampa_resoconto_esami( Esame *e, int qe );
int conta_righe_file_dati( const char *nf );
/*==============================================================================
Legge dati formattati dal file chiamato kStrNomeFile.
Se il caricamento va a buon fine, stampa un elenco dei dati letti.
==============================================================================*/
int main() {
int qe;
Esame *e = carica_dati_esami( kStrNomeFile, &qe );
if( NULL != e ) {
stampa_resoconto_esami( e, qe );
delete[] e; e = NULL;
}
return 0;
}
/*==============================================================================
Dato il nome di un file nf ne carica il contenuto in un array di oggetti di tipo
Esame allocato dinamicamente.
Se l'operazione va a buon fine, restituisce il puntatore all'array degli oggetti
allocati e debitamente "compilati", collocando all'indirizzo puntato dal
parametro qe la quantita' degli elementi dell'array allocato.
In caso d'errore, restituisce NULL e non modifica lo spazio di memoria puntato
dal parametro qe.
==============================================================================*/
Esame *carica_dati_esami( const char *nf, int *qe ) {
if( NULL==nf || NULL==qe ) return NULL;
int qr = conta_righe_file_dati( kStrNomeFile );
if( 0 == qr ) return NULL;
Esame *e = NULL;
FILE *f = fopen( nf, "r" );
if( NULL != f ) {
try {
char buff[LMAX_RIGA+1];
int i;
e = new Esame[qr];
for( i=0; i<qr; ++i ) {
if( !fgets(buff,LMAX_RIGA,f) )
break;
if( !e[i].AcquisisciDatiDaStringa(buff,'\t','/') )
break;
}
fclose( f ); // non ci serve piu'
if( i == qr ) {
*qe = i; // comunica la quantita' degli esami letti
}
else {
printf( "File \"%s\": errore alla riga %d.\n\n", nf, i+1 );
delete[] e; e = NULL;
}
} catch( ... ) {
fclose( f );
return NULL;
}
}
return e;
}
/*==============================================================================
Mostra in console il contenuto degli oggetti di tipo Esame presenti nell'array
puntato dal parametro e. Il parametro qe indica la quantita' degli elementi di
tipo Esame presenti nell'array.
Se e e' NULL e/o qe e' minore o uguale a 0, la funzione non fa nulla.
==============================================================================*/
void stampa_resoconto_esami( Esame *e, int qe ) {
if( NULL != e && qe > 0 ) {
int i;
for( i=0; i<qe; ++i ) {
printf( "esame: %s\n", e[i].Nome() );
printf( "punti: %d/%d\n", e[i].Punteggio(), Esame::kMaxPunti );
printf( "data: %s\n\n", e[i].Data('-') );
}
}
}
/*==============================================================================
Dato il nome di un file nf, conta la quantita' delle righe in esso contenute.
L'identificazione delle righe avviene contando le ricorrenze del carattere '\n'.
Un file, anche vuoto, contiene sempre almeno una riga (per quanto vuota).
La quantita' delle righe viene restituita come valore di ritorno.
==============================================================================*/
int conta_righe_file_dati( const char *nf ) {
if( NULL == nf ) return 0;
FILE *f = fopen( nf, "r" );
if( NULL == f ) return 0;
int qr = 1;
for( int c=fgetc(f); c!=EOF; c=fgetc(f) )
qr += '\n' == c;
fclose( f );
return qr;
}
file classe_esame.h
#ifndef CLASSE_ESAME_H
#define CLASSE_ESAME_H
class Esame {
public:
Esame();
Esame( const char *n, int pt, char g, char m, short a );
Esame( const char *d, char sep, char sepData );
virtual ~Esame();
bool Nome( const char *n );
const char *Nome( void ) { return nome; }
bool Punteggio( int p );
bool Punteggio( const char *d );
int Punteggio( void ) { return punti; }
bool Data( char g, char m, short a );
bool Data( const char *d, char sep );
void Data( char *g, char *m, short *a );
const char *Data( char sep, int formato = 224 );
bool AcquisisciDatiDaStringa( const char *d, char sep, char sepData );
static const int kLMaxNome;
static const int kQElDaStringa;
static const int kMaxPunti;
static int QuantitaElementiInStringa( const char *d, char sep );
static int QuantitaSpaziIniziali( const char *d );
static int LongDaStringa( const char *d, long *n );
static bool Bisestile( int a );
protected:
private:
char nome[32]; // 32: kLMaxNome+1
int punti;
char giorno;
char mese;
short anno;
};
#endif // CLASSE_ESAME_H
file classe_esame.cpp
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "classe_esame.h"
const int Esame::kLMaxNome = 31;
const int Esame::kQElDaStringa = 3;
const int Esame::kMaxPunti = 30;
Esame::Esame() {
memset( nome, 0, sizeof(nome) );
punti = 0;
giorno = 0;
mese = 0;
anno = 0;
}
Esame::Esame( const char *n, int pt, char g, char m, short a ) {
if( !Nome(n) ) throw "Nome esame non valido";
if( !Punteggio(pt) ) throw "Punteggio esame non valido";
if( !Data(g,m,a) ) throw "Data esame non valida";
}
Esame::Esame( const char *d, char sep, char sepData ) {
if( !AcquisisciDatiDaStringa(d,sep,sepData) )
throw "Dati da stringa non validi";
}
Esame::~Esame() {
//dtor
}
bool Esame::Nome( const char *n ) {
if( NULL != n ) {
size_t ln;
memset( nome, 0, LMAX_NOME+1 );
n += QuantitaSpaziIniziali( n );
ln = strlen( n );
if( ln <= kLMaxNome ) {
strncpy( nome, n, kLMaxNome );
}
else {
strncpy( nome, n, kLMaxNome-3 );
strcat( nome, "..." );
}
return true;
}
return false;
}
bool Esame::Punteggio( int p ) {
if( p>=0 && p<=kMaxPunti ) {
punti = p;
return true;
}
return false;
}
bool Esame::Punteggio( const char *d ) {
if( NULL != d ) {
long nTmp;
if( 0 != LongDaStringa(d,&nTmp) )
return Punteggio( nTmp );
}
return false;
}
bool Esame::Data( char g, char m, short a ) {
if( g>0 && m>0 && a>0 ) {
if( m>12 ) return false;
switch( m ) { /* verifica gli intervalli dei valori per il giorno */
case 2: // mese di febbraio
if( g<(29+Bisestile(a)) )
break;
else return false;
case 4: case 6: case 9: case 11: // mesi di 30 gg massimo
if( g<31 )
break;
else return false;
default: // tutti gli altri mesi
if( g>31 ) return false;
}
giorno = g;
mese = m;
anno = a;
return true;
}
return false;
}
bool Esame::Data( const char *d, char sep ) {
if( 3 == QuantitaElementiInStringa(d,sep) ) {
char gTmp, mTmp;
short aTmp;
long nTmp;
int letti;
if( (letti=LongDaStringa(d,&nTmp)) ) gTmp = nTmp; else return false;
d += letti+1; // +1 per andare oltre al separatore
if( (letti=LongDaStringa(d,&nTmp)) ) mTmp = nTmp; else return false;
d += letti+1; // +1 per andare oltre al separatore
if( (letti=LongDaStringa(d,&nTmp)) ) aTmp = nTmp; else return false;
return Data( gTmp, mTmp, aTmp );
}
return false;
}
void Esame::Data( char *g, char *m, short *a ) {
if( NULL != g ) *g = giorno;
if( NULL != m ) *m = mese;
if( NULL != a ) *a = anno;
}
const char *Esame::Data( char sep, int formato ) {
static char d[16];
int g = giorno;
int m = mese;
int a = anno;
switch( formato ) {
case 112: sprintf( d, "%d%c%d%c%02d", g, sep, m, sep, a%100 ); break;
case 222: sprintf( d, "%02d%c%02d%c%02d", g, sep, m, sep, a%100 ); break;
case 114: sprintf( d, "%d%c%d%c%04d", g, sep, m, sep, a ); break;
default: sprintf( d, "%02d%c%02d%c%04d", g, sep, m, sep, a );
}
return d;
}
bool Esame::AcquisisciDatiDaStringa( const char *d, char sep, char sepData ) {
if( NULL != d ) {
if( kQElDaStringa == QuantitaElementiInStringa(d,sep) ) {
size_t ld = strlen( d );
char *s = (char*) malloc( ld+1 );
if( NULL != s ) {
Esame eTmp; // per immagazzinare temporaneamente i dati letti
char *ptr; // un puntatore ausiliario
bool ok;
strcpy( s, d );
*(ptr=strchr(s,sep)) = '\0'; // cambia il separ. con '\0'
if( (ok=eTmp.Nome(s)) ) {
s = ptr+1; // supera il separatore
*(ptr=strchr(s,sep)) = '\0'; // cambia il separ. con '\0'
if( (ok=eTmp.Punteggio(s)) ) {
s = ptr+1; // supera il separatore
ok = eTmp.Data( s, sepData );
}
}
free( s );
if( ok ) *this = eTmp;
return ok;
}
}
}
return false;
}
int Esame::QuantitaElementiInStringa( const char *d, char sep ) {
int qEl = 0;
if( NULL != d )
for( ++qEl; *d; ++d )
qEl += sep==*d;
return qEl;
}
int Esame::QuantitaSpaziIniziali( const char *d ) {
if( NULL != d ) {
const char *ptr = d;
while( isspace(*ptr) ) ++ptr;
return ptr-d;
}
return 0;
}
int Esame::LongDaStringa( const char *d, long *n ) {
if( NULL != d && NULL != n ) {
char *fine;
long nTmp;
nTmp = strtol( d, &fine, 10 );
if( fine != d ) {
*n = nTmp;
return fine-d;
}
}
return 0;
}
bool Esame::Bisestile( int a ) {
if( a > 1582 ) /* calendario gregoriano */
return (!(a%400)) || ( (!(a%4)) && (a%100) );
else /* calendario giuliano (non fa la verifica dei 400 anni) */
return (!(a%4)) && (a%100);
}
Per quanto possa sembrare impossibile... funziona! MANICOMIO 2!