PDA

View Full Version : [C] Alberi binari, datemi un mano a capire una piccola porzione di codice.


MaX-xXx
19-11-2014, 10:45
Albero LeggiAlberoFD(FILE *fd) {
Albero a;
int res, x;
char c;

/* legge la parentesi ( */
res=fscanf(fd, "%c", &c);
if(res!=1 || c!='(') {
ungetc(c, fd);
return NULL;
}

/* legge l'intero oppure ) */
res=fscanf(fd, "%c", &c);
if(res!=1 || c==')')
return NULL;

ungetc(c, fd);
fscanf(fd, "%d", &x);

/* crea il nodo */
a=malloc(sizeof(struct NodoAlbero));
a->radice=x;
a->sinistro=LeggiAlberoFD(fd);
a->destro=LeggiAlberoFD(fd);


/* legge ) */
fscanf(fd, "%c", &c);

return a;
}

Salve, i miei dubbi sono riguardo la funzione ungetc(c, fd).
Come funziona in questo caso?
Poi non capisco il secondo fscanf: come fa a memorizzare il secondo carattere senza chiamare prima la funzione ungetc(c, fd), che avanza al carattere successivo?
Per il resto è tutto chiaro.
Grazie per l'aiuto

monte.cristo
19-11-2014, 14:01
L'algoritmo è più o meno questo:
1) Leggi con fscanf un carattere dal file fd
2) Se la fscanf non riesce a leggere un carattere oppure il carattere letto non è '(' allora la funzione "rimette a posto" il carattere c nel file fd con la ungetc e termina restituendo NULL (in questo caso quindi la lista non è nel formato corretto)
3) Con la seconda fscanf leggi un altro carattere
4) Se la seconda fscanf non riesce a leggere un carattere o il carattere letto è ')' allora la funzione termina restituendo NULL (in questo caso se sei al primo livello di ricorsione la lista è vuota cioè hai solo la parentesi aperta e chiusa perciò la radice dell'albero deve essere NULL mentre se sei nei livelli successivi di ricorsione hai finito la lista e quindi restituisci NULL perchè non ci sono più valori da allocare nei nodi)
5) Se arrivi qui, un carattere è stato letto e non è ')' perciò deve essere un intero. Di conseguenza va rimesso a posto il carattere già letto dalla seconda fscanf e riletto con una terza fascanf come numero e messo in x
6) Crei un nodo in cui salvare il valore x
7) Chiami ricorsivamente la funzione (prima per costruire il sottoalbero a sinistra e poi a destra)
8) Alla fine leggi l'ultimo carattere che sarà ')' e poi la funzione restituisce a

Un consiglio personale: per capire come funziona una funzione ricorsiva basta prendere un esempio di stringa valida e analizzare uno alla volta i vari livelli della ricorsione. Io di solito lo facevo a mano perchè mi aiutava a ragionare. ;)

sottovento
19-11-2014, 14:15
/* legge la parentesi ( */
res=fscanf(fd, "%c", &c);
if(res!=1 || c!='(') {
ungetc(c, fd);
return NULL;
}



E' da notare che se la fscanf fallisce, il contenuto di c e' indeterminato; pertanto andrai ad inserire un valore indeterminato nel buffer dello stream di ingresso, che presumibilmente utilizzerai con scarso profitto da qualche altra parte del codice (altrimenti non ti saresti premurato in reinserirlo, giusto?)

MaX-xXx
20-11-2014, 09:56
ti ringrazio molto per l'aiuto, sei stato illuminante! :D :D

MaX-xXx
20-11-2014, 10:01
Grazie a tutti voi per l'aiuto! con l'algoritmo espresso in linguaggio formale ora mi è molto più chiaro!