Newsgroup: it.comp.lang.c
Titolo: File ad accesso casuale

Devo gestire un file ad accesso casuale di strutture formate da: matricola,
nome, cognome,numero di esami, nome degli esami, voto degli esami per ogni
studente.
Dovrei essere in grado anche di aggiornare il file risalendo allo studente
giusto tramite la matricola.
Il problema č che le poche idee che ho al riguardo non mi hanno aiutato a
venirne a capo.
Se qualcuno fosse cosě gentile da darmi qualche delucidazione giene sarei
molto grata.
Grazie.
Chiara.

 giusto tramite la matricola.
Qui  supponiamo  che tutti  i  record  abbiano  un numero  di  matricola
continuo e crescente.
#define LINE_SIZE 150
#define BASE 654485
long matricola = 654512;
fseek(file, 0, SEEK_SET);
fseek(file, (matricola - BASE) * LINE_SIZE, SEEK_SET);
LINE_SIZE e`  la dimensione (in byte)  di un singolo record. BASE  e` il
primo numero di matricola presente nel file. (matricola - BASE) ti da un
offset in termini di record  (ovvero quanti record a partire dall'inizio
del file), moltiplicando per LINE_SIZE  ottieni l'offset in byte (che e`
quello che ti serve per accedere al record.
ciao
Kronos
-- 
Home: 
http://kronoz.cjb.net
"La Via prosegue senza fine."
	Bilbo Baggins - Il Signore degli Anelli - J.R.R. Tolkien

grazie, ma ho anche un altro problema.
Il file lo devo creare io e poi lo devo poter aggiornare a mio piacimento
(per esempio, potrei voler cambiare il numero di esami dati e rispettivi
nome e voto); il punto è che non sono sicura di come si può fare, cioè, per
scrivere il file lo apro in w ma poi come faccio a scorrerlo in una chiamata
successiva?
E soprattutto, i valori io li salvo dentro un vettore, però quando vado a
modificare i dati devo modificare anche il testo.
L'uso di fseek() e ftell() mi è abbastanza chiaro (per quanto possibile)
però mi perdo nella gestione dei dati in questo file sequenziale che tra
l'atro devo creare io.
Aiuto.
Grazie
Chiara

 vado a modificare i dati devo modificare anche il testo.
Continuo  a  non seguirti. Mantieni  i  record  in un  array? Allora  la
soluzione piu` semplice e` di  operare su quello e scriverlo interamente
alla fine del programma.
struct lista_voti {
        char esame[30];
        unsigned char voto;
        struct lista_voti *next;
};
struct studente {
        long matricola;
        char nome[30];
        ....
        struct lista_voti *voti;
};
struct studente studenti[MAX];
Per memorizzare  i dati devi  stabilire un formato per  rappresentare la
lista. Ad es:
Begin
esame1: 30
esame2: 18
End
In questo modo in lettura riuscirai a ricostruirla.
ciao
Kronos
-- 
Home: 
http://kronoz.cjb.net
Runtime error 6D at f000:a12f : user incompetente

 ed aggiungere una lista dinamica con la coppia <esame, voto>.
Il concetto č chiaro, sulla realizzazione ci devo lavorare.
Grazie.
ciao.
Chiara

 gli heap mi faresti veramente un gran favore, grazie.
Ok, eccolo qui`:
typedef struct node_ {
        int key;
        struct node_ *sx, *dx;
} node_t;
static node_t *root = NULL;
node_t *new_node(int key) {
        node_t *tmp;
        tmp = malloc(sizeof(node_t));
        assert(tmp);
        tmp->key = key;
        tmp->sx = tmp->dx = NULL;
        return tmp;
}
/* Questa e` la funzione ricorsiva che effettua la lettura del file e
 * ricostruisce l'albero. Viene chiamata dalla funzione load.
 */
void parse(FILE *f, node_t **node) {
        /* Non va chiamata direttamente */
        char buff[128];
        int key;
        if (fgets(buff, sizeof(buff), f) == NULL) {
                *node = NULL;
                return;
        }
        if (strncmp("NULL", buff, 4) == 0) {
                *node = NULL;
                return;
        }
        if (sscanf(buff, "%d", &key) < 1) {
                fprintf(stderr, "Errore nella lettura del file\n");
                return;
        }
        *node = new_node(key);
        parse(f, &(*node)->sx);
        parse(f, &(*node)->dx);
}
void load(char const *fname) {
        FILE *f;
        if ((f = fopen(fname, "r")) == NULL) {
                fprintf(stderr, "Impossibile aprire %s\n", fname);
                perror("load:fopen()");
                return;
        }
        if (root)
                cleanup(root);
        parse(f, &root);
        fclose(f);
}
void dump(FILE *f, node_t *node) {
        if (node == NULL) {
                fprintf(f, "NULL\n");
                return;
        }
        fprintf(f, "%d\n", node->key);
        dump(f, node->sx);
        dump(f, node->dx);
}
/* Questa e` la funzione ricorsiva che scrive l'albero su file */
void store(char const *fname) {
        FILE *f;
        if ((f = fopen(fname, "w")) == NULL) {
                fprintf(stderr, "Impossibile aprire %s\n", fname);
                perror("store:fopen()");
                return;
        }
        dump(f, root);
        fclose(f);
}
In questo caso  ogni nodo contiene solo un'intero, ma  basta una piccola
modifica alle  funzioni dump  e parse  per salvare  tutto quello  che ti
serve. La  funzione di  salvataggio  scrive tutto  l'albero (compresi  i
NULL pointer)  attraversandolo in  preorder. La funzione  di caricamento
ricostruisce l'albero facendo un inserimento in preorder (ok, non esiste
"l'inserimento in preorder", pero` rende l'idea).
ciao
Kronos
-- 
Home: 
http://kronoz.cjb.net
Carpe diem, quam minimum credula postero. (Q. Horatius Flaccus)

un'altro piccolo aiutino.
Questo è il testo del mio esercizio (o meglio una parte del testo):
Il Problema.
Si tratterà di gestire  un file ad accesso casuale di strutture con le
seguenti  informazioni relative agli studenti:
matricola
nome
cognome
numero esami sostenuti
elenco esami sostenuti e relativi e voti
media
La matricola, il numero dei voti e i voti stessi sono espressi da  interi,
la media da un float e nome, cognome e nomi degli esami  da stringhe.
Il file di dati é ad accesso casuale.
Si supponga  che i voti siano in trentesimi, che il numero massimo di esami
da superare per quel corso sia 25 e che il nome degli esami sia un
codice del formato Esi, per 1?i?25.
Vogliamo
1.aggiornare  periodicamente   il file con  i dati degli studenti,
aggiungendone uno nuovo,
2. aggiornare i dati di uno studente inserito, in particolare modificando
l'elenco degli esami sostenuti da uno studente già immatricolato,
aggiungendo nuovi esami.
3. cancellare  il record di uno studente, e infine
4. stampare  l'elenco dei primi cinque studenti in ordine  di media
visualizzando  a terminale  la  matricola,  il nome, il cognome e la media.
Mi sfugge decisamente cosa intende quando parla del nome degli esami in
codice formato Esi(??).
Grazie.
Ciao.
Chiara

 in codice formato Esi(??).
Ti semplifica la vita. Non so cosa  sia il codice esi, ma supponendo che
sia un codice  di sei caratteri, puoi usare un'array  di 7 caratteri per
memorizzare codice e voto:
char codice[7] = "123abc";
int voto = 28;
struct studente s;
...
memcpy(s.voti[numero_esame], codice, 6);
s.voti[numero_esame][6] = voto;
....
memcpy(codice, s.voti[numero_esame], 6);
codice[6] = '\0';
printf("Codice esame: %s\tVoto: %d\n", codice, s.voti[numero_esame][6]);
A  questo punto  puoi salvare  (o  caricare) tutta  la struttura  usando
fwrite (o fread). L'inconveniente  e` che per modificare  un record devi
scorrere  tutto il  file fino  a  trovare quello  giusto. Poi, per  fare
l'aggiornamento:
while(...) {
        fread(&s, sizeof(struct studente), 1, file);
        if (studente_giusto);
                break;
}
modifica(&s);
fseek(file, SEEK_CUR, - sizeof(struct studente));
fwrite(&s, sizeof(struct studente), 1, file);
ciao
Kronos
-- 
Home: 
http://kronoz.cjb.net
Un apostolo vedendo Gesu` camminare sulle acque:
- Cazzo se e` buono 'sto fumo!!!