590 likes | 733 Views
CAPITOLO 16. La sintassi di un file binario è diversa da quella di un file testo. FILE. OF. =. identificatore. type. In Pascal è possibile avere oltre ai file testo, cioè file di char, anche file di interi, stringhe, records.
E N D
La sintassi di un file binario è diversa da quella di un file testo. FILE OF = identificatore type In Pascal è possibile avere oltre ai file testo, cioè file di char, anche file di interi, stringhe, records. Unica condizione è quella che se un file è ad esempio dichiarato di interi esso non può contenere che interi. Tutti i file di tipo non-testo sono detti file binari. La estensione di un file testo è NomeFile.txt La estensione di un file binario è NomeFile.dat
PROGRAM FileTesto(output, Teresa); VAR Teresa:text; Ch:char; BEGIN END. PROGRAM FileBinari(output, Ints,Reals,Records); TYPE String30=STRING[30]; NameType=RECORD First, Middle, Last:String30; END; IntsFile=FILE OF integer; RealsFile=FILE OF real; RecFile=FILE OF NameType; VAR Ints:IntsFile; Reals:RealsFile; Names:RecFile; BEGIN END. Preparazione alla scrittura del file rewrite(NomeFile) es. rewrite(Reals) Preparazione alla lettura del file reset(NomeFile) es. reset(Reals)
…………….. Giulio Luca Rossi Carlo Maria Bianchi Gian Giacomo Verdi …………….. Area Dati AName.First Carlo AName.Middle Maria AName.Last Bianchi Carlo Maria Bianchi Il controllo di fine file viene eseguito come per i text file con la funzione <eof> eof(NomeFile) Essendo i dati scritti uno di seguito all’altro non esiste più l’<eoln>. Nel caso del RecFile i record NameType=RECORD descritti da First, Middle, Last:String30; avremo La lettura avviene record per record, non stringa per stringa
E’ possibile leggere anche più di un valore alla volta da un file. Esempio read(Reals, R1, R2, R3,….) Per leggere un intero file si può far uso dell’ <eof> Esempio reset(Ints); WHILE NOT eof(Ints) DO BEGIN read(Ints, Intero); elabora(Intero) END; L’uso dell’ <eoln> produce un errore di sintassi.
Errore !!!!!! E’ possibile scrivere in un file binario se ovviamente è stato preparato per la scrittura. Esempio write(Ints, AnInt, 3*AnInt); write(Reals, Re1, 3.1416); write(Names, AName); write(Names, Name1, Name2); TYPE String30=STRING[30]; NameType=RECORD First, Middle, Last:String30; END; IntsFile=FILE OF integer; RealsFile=FILE OF real; RecFile=FILE OF NameType; VAR Ints:IntsFile; Reals:RealsFile; Names:RecFile; Come si vede anche più di un dato può contemporaneamente essere scritto in un file binario. Attenzione !!! Ogni elemento che si scrive deve essere dello stesso Type del file. Quindi sono sbagliate le scritture del tipo write(Ints, Re1, 3.2*Re1); write(Reals, AnInt, AnInt DIV 2); write(Names, Aname.First, Aname.Middle, Aname.Last); Non essendoci <eoln> non è permesso il writeln.
COPIA DI FILE BINARI Supponiamo di avere due file binary AFile e Bfile aventi lo stesso SomeType le cui componenti sono del tipo ComponentType. WHILE NOT eof(Afile) DO read(Afile, Acomponent) write(Bfile, Acomponent) PROCEDURE CopyFile(VAR InNames, OutNames:RecFile); VAR AName:NameType; BEGIN WHILE NOT eof(InNames) DO read(InNames, AName); write(OutNames, AName) END END;
Si noti che con una sola operazione di read o write si possono leggere molti valori contemporaneamente se questo è previsto dalla struttura dei file in gioco. Ad esempio un record con 20 campi può essere scritto con una sola operazione e non campo per campo. Nel caso in cui si vogliono dare i valori di un record campo per campo, ad esempio da tastiera, allora si può adoperare la seguente procedura: WITH RecordVar DO introduci il valore del campo write(OutFile, RecordVar)
PROCEDURE WriteAName(VAR OutFile:NameFile); VAR Aname: NameType; BEGIN WITH Aname DO BEGIN write(‘ First Name: ‘); readln(First); write(‘ Middle Name: ‘); readln(Middle ); write(‘ Last Name: ‘); readln(Last ); END; write(OutFile, AName) END; TYPE String30=STRING[30]; NameType=RECORD First, Middle, Last:String30; END; IntsFile=FILE OF integer; RealsFile=FILE OF real; RecFile=FILE OF NameType; VAR Ints:IntsFile; Reals:RealsFile; Names:RecFile;
Studente Anagrafe Nascita Matricola AnnoCorso Risultati Media Cognome Nome Giorno Mese Anno TYPE Stringa20 = STRING[20] RisultatiArray =ARRAY[1.. TotaleProve ] OF integer; DataRecord = RECORD AnagraficaRecord = RECORD Giorno, Cognome, Mese, Nome : Stringa20 Anno : integer END; END; StuRecord = RECORD Anagrafe : AnagraficaRecord ; CONST MaxStud=150; TYPE StuRecord = RECORD ………………. END; ClassArray=ARRAY[1..Maxstud] OF StuRecord; StuRecFile=FILE OF StuRecord; VAR InFile:StuRecFile; AClass: ClassArray; TotalStudents:integer; Nascita : DataRecord ; Matricola : StringaNome ; AnnoCorso : StringaNome ; Risultati : RisultatiArray ; Media:real; END;
Procedura per la costruzione di un Array di record a partire da un file binario. Supponiamo di introdurre meno di MaxStud record PROCEDURE FillClass(VAR AClass: ClassArray; VAR TotalStudents: integer; VAR InFile: StuRecFile); VAR AStudent: StuRecord; BEGIN TotalStudents:=0; reset(InFile); WHILE NOT eof(InFile) DO BEGIN TotalStudents:= TotalStudents+1; read(InFile, AStudent); Aclass[TotalStudents]:=AStudent END END; StuRecord = RECORD Anagrafe : AnagraficaRecord ; Nascita : DataRecord ; Matricola : StringaNome ; AnnoCorso : StringaNome ; Risultati : RisultatiArray ; Media:real; END;
Sessione StuRecord OldMaster Semester Sessione StuRecord StuRecord merge MStuRec NewMaster MStuRec AGGIORNAMENTO DI FILE DI RECORD BINARI Dati due File di record binari ordinati, fare il merge del primo nel secondo producendo un terzo file ordinato. Corso Programmazione Sessione Invernale CSPI99 Corso Programmazione Sessione Estiva CSPE99 Corso Programmazione CSP99
Pseudo Codice di UpdateMerge AssignFiles(LaSessione, Semester, OldMaster, NewMaster); Merge(LaSessione, Semester, OldMaster, NewMaster); Risultati(Semester,OldMaster,NewMaster); writeln(' Fine aggiornamento ') END.
Semester OldMaster StuRecord MStuRec NewMaster MStuRec MERGE Pseudo codice {Merge(LaSessione, Semester, OldMaster ,NewMaster} prendi un record MStu1 da OldMaster {GetMasterRec(MStu1)} prendi un record MStu2 da Semester {GetSemesterRec(LaSessione,MStu2,Semester} WHILE NOT sono finiti i due file DO write il record con “nome” più piccolo in NewMaster prendi un altro record dal file giusto {OldMaster o Semester} copia gli ultimi record MStu1 e MStu2 in NewMaster {CopyLastTwo(MStu1,MStu2,NewMaster} {CopyOldMasterRecs(OldMaster,NewMaster} copia ordinatamente i record dai file non esauriti in NewMaster {CopySemesterRecs(LaSessione,Semester,NewMaster}
MStuRecord StuRecord Sessione Cognome Nome Nascita Matricola AnnoCorso Risultati Media Semester OldMaster StuRecord Sessione StuRecord MStuRec NewMaster MStuRec Sessione StuRecord CONST TotaleProve=100; TYPE Stringa4 = STRING[4]; Stringa10 = STRING[10]; Stringa25 = STRING[25]; RisultatiArray=ARRAY[1..TotaleProve] OF integer; StuRecord = RECORD Cognome, Nome : Stringa25; Nascita:Stringa10; Matricola:Stringa10; AnnoCorso:Stringa4; Risultati:RisultatiArray; Media:real; END; MStuRecord= RECORD Sessione:Stringa25; Info:StuRecord END; StuRecFile= FILE OF StuRecord; MStuRecFile= FILE OF MStuRecord; VAR LaSessione: Stringa25; {semestre appena finito} Semester: StuRecFile; {file semestre appena finito} OldMaster:MStuRecFile; {file preesistente} NewMaster : MStuRecFile; {file aggiornato}
Semester OldMaster NewMaster LaSessione Semester OldMaster NewMaster LaSessione Semester OldMaster NewMaster Risultati AssignFiles Merge OldMaster NewMater MStu1 MStu2 MStu1 Semester MStu2 MStu1.Info MStu2.Info GetMasterRec GetSemesterRec CopyLastTwo Semester NewMaster Stu1GoesFirst Vero Falso NewMater MStu1 NewMater MStu2 OldMaster NewMaster write write OldMaster MStu1 Semester MStu2 CopySemesterRecs GetMasterRec GetSemesterRec CopyMasterRecs
Semester OldMaster StuRecord Sessione StuRecord MStuRec NewMaster MStuRec Sessione StuRecord PROCEDURE AssignFiles(VAR LaSessione:Stringa25; VAR Semester:StuRecFile;VAR OldMaster, NewMaster : MStuRecFile); {si legge la sessione da tastiera, si aprono i file Semester, OldMaster, in lettura e NewMaster in scrittura } VAR CourseName, InvernaleOEstiva,Anno: Stringa25; BEGIN write(' Nome corso= '); readln(CourseName); {es. PRO} write(' Sessione ("Invernale: i" o "Estiva: e")): '); readln(InvernaleOEstiva); {es. e} write(' Anno (due digiti): '); readln(Anno); {es. 00} LaSessione:= InvernaleOEstiva+ Anno; {es. e00} assign(Semester, CourseName+'e'+'.dat'); {es. PROe00.dat} IF InvernaleOEstiva='e' THEN assign(OldMaster, CourseName+’i'+'00.dat') ELSE assign(OldMaster, CourseName+'e'+'00.dat'); {es. PROe.dat} assign(NewMaster, CourseName+ InvernaleOEstiva +'new.dat'); {es. PROenew.dat} reset(OldMaster); reset(Semester); rewrite(NewMaster) END;
PROCEDURE Merge (LaSessione:Stringa25; VAR Semester:StuRecFile; VAR OldMaster, NewMaster : MStuRecFile); VAR Astu:StuRecord; {variabile record letta da Semester} MStu1, MStu2: MStuRecord; {variabile record letta da OldMaster e quella formata da AStu e LaSessione} BEGIN GetMasterRec(MStu1,OldMaster); GetSemesterRec(LaSessione,MStu2,Semester); WHILE NOT eof(OldMaster) AND NOT eof(Semester) DO BEGIN IF Stu1GoesFirst(MStu1.Info,Mstu2.Info) THEN BEGIN write(NewMaster,MStu1); GetMasterRec(MStu1,OldMaster) END ELSE BEGIN write(NewMaster,MStu2); GetSemesterRec(LaSessione,MStu2,Semester) END; END; CopyLastTwo(MStu1,MStu2,NewMaster); CopyOldMasterRecs(OldMaster,NewMaster); CopySemesterRecs(LaSessione,Semester,NewMaster); close(Semester); close(OldMaster); close(NewMaster) END; Semester OldMaster StuRecord Sessione StuRecord MStuRec NewMaster MStuRec Sessione StuRecord Necessario perché il Get... avviene dopo la write MStuRecord= RECORD Sessione:Stringa25; Info:StuRecord END;
MStuRecord StuRecord Sessione Cognome Nome Nascita Matricola AnnoCorso Risultati Media Semester OldMaster StuRecord Sessione StuRecord MStuRec NewMaster MStuRec Sessione StuRecord PROCEDURE GetMasterRec(VAR MStu:MStuRecord;VAR OldMaster:MStuRecFile); BEGIN IF NOT eof(OldMaster) THEN read(OldMaster,MStu) END; PROCEDURE GetSemesterRec(LaSessione:Stringa25;VAR MStu:MStuRecord; VAR Semester:StuRecFile); BEGIN IF NOT eof(Semester) THEN BEGIN read(Semester,MStu.Info); MStu.Sessione:=LaSessione END END;
Stu1, Stu2 Stu1.Cognome <> Stu2.Cognome Stu1.Nome <> Stu2.Nome Stu1.Matricola <> Stu2. Matricola = = Vero Falso <> <> Stu1.Cognome < Stu2.Cognome Stu1.Nome < Stu2.Nome Vero Vero Falso Falso FUNCTION Stu1GoesFirst(Stu1,Stu2:StuRecord):boolean; BEGIN IF Stu1.Cognome<>Stu2.Cognome THEN Stu1GoesFirst:=Stu1.Cognome<Stu2.Cognome ELSE IF Stu1.Nome<>Stu2.Nome THEN Stu1GoesFirst:=Stu1.Nome<Stu2.Nome ELSE Stu1GoesFirst:=Stu1.Matricola<Stu2.Matricola END;
PROCEDURE CopyLastTwo(MStu1,MStu2:MStuRecord;VAR NewMaster:MStuRecFile); BEGIN IF Stu1GoesFirst(MStu1.Info,Mstu2.Info) THEN BEGIN write(NewMaster,MStu1); write(NewMaster,MStu2) END ELSE BEGIN write(NewMaster,MStu2); write(NewMaster,MStu1) END; END; PROCEDURE CopyOldMasterRecs(VAR OldMaster, NewMaster:MStuRecFile); VAR AName:MStuRecord; BEGIN WHILE NOT eof(OldMaster) DO BEGIN read(OldMaster,AName); write(NewMaster,AName) END END;
PROCEDURE CopySemesterRecs(LaSessione:Stringa25; VAR Semester:StuRecFile; VAR NewMaster : MStuRecFile); VAR MStu:MSTuRecord; BEGIN WHILE NOT eof(Semester) DO BEGIN read(Semester,MStu.Info); MStu.Sessione:=LaSessione; write(NewMaster,MStu) END END;
PROCEDURE Risultati (VAR SemFile:StuRecFile; VAR OldFile,NewFile :MStuRecFile); VAR NameSem:StuRecord; NameOld:MStuRecord; NameNew:MStuRecord; BEGIN writeln(' Semestre Old New '); WHILE NOT eof(NewFile) DO BEGIN IF eof(SemFile) THEN BEGIN NameSem.Cognome:=' -- '; NameSem.Nome:=' -- ' END ELSE read(SemFile,NameSem); IF eof(OldFile) THEN BEGIN NameOld.Info.Cognome:=' -- '; NameOld.Info.Nome:=' -- ' END ELSE read(OldFile,NameOld) END; read(NewFile,NameNew); writeln(NameSem.Cognome:6,' ',NameSem.Nome:4,' ', NameOld.Info.Cognome:6,' ', NameOld.Info.Nome:4,' ', NameNew.Info.Cognome:6,' ', NameNew.Info.Nome:4); END; END;
Semestre Old New agazzi carlo brescia ugo agazzi carlo bottazzi anna distante claudio bottazzi anna napoli giulio livorno giulia brescia ugo perna claudio venezia anna distante claudio venezia elena viterbo giorgio livorno giulia -- -- -- -- napoli giulio -- -- -- -- perna claudio -- -- -- -- venezia anna -- -- -- -- venezia elena -- -- -- -- viterbo giorgio Fine aggiornamento
Pseudo codice per il Merge e Update di due file InFile1 InFile2 GetRec(Rec1,InFile1) GetRec(Rec2,InFile2) WHILE NOT eof(InFile1) AND NOT eof(InFile2) DO IF Rec1.Key < Rec2.Key THEN write(OutFile,Rec1) GetRec(Rec1,InFile1) ELSE write(OutFile,Rec2) GetRec(Rec2,InFile2) CopyLastTwo(Rec1,Rec2,OutFile) CopyRemainder(InFile1,OutFile} CopyRemainder(InFile2,OutFile} close all files
Esercizio • Scrivere due procedure: • una per creare un file di tipo Semester e un file di tipo OldMaster • una per leggere gli stessi file.
I PUNTATORI Allocazione Statica Dato un blocco ogni variabile è allocata in memoria quando inizia l’elaborazione del blocco e deallocata quando l’elaborazione di tutto il blocco termina. Allocazione Dinamica Quando ogni variabile è allocata o deallocata in memoria durante l’elaborazione del blocco. Variabile dinamica E’ una variabile alla quale si assegna spazio in memoria durante l’elaborazione di un blocco. Il puntatore Un puntatore è una variabile il cui valore rappresenta un indirizzo di memoria. Esso serve per creare o eliminare una variabile dinamica.
= ^ identificatore type Variabile Anonima: una variabile alla quale si accede solo tramite un puntatore Variabile Nominata: una variabile alla quale si accede tramite un nome ESEMPIO TYPE DataType = RECORD Giorno:1..31; Mese:1..12; Anno:integer END; DataPunt=^DateType; IntPunt=^integer; VAR Oggi:DataPunt; A,B:IntPunt; Domani:DataType; Si noti che la variabile Oggi, così come la variabile IntPunt, non assume i tre valori del record, o il valore di intero, a cui fa riferimento ma solo quello dell’indirizzo di memoria a partire del quale vi sono eventualmente i valori
? ? 21 ? ? 11 ? ? 2000 Per assegnare un indirizzo a una variabile puntatore si usa la procedura new: es. new(Oggi) Spazio di memoria assegnato Prima di fare la chiamata new(Oggi) Oggi^ ? Dopo la chiamata new(Oggi) Oggi^ TYPE DataType = RECORD Giorno:1..31; Mese:1..12; Anno:integer END; DataPunt=^DateType; IntPunt=^integer; VAR Oggi:DataPunt; A,B:IntPunt; Per assegnare dei valori alla variabile dinamica Oggi new(Oggi) Oggi^ read(Oggi^.Giorno,Oggi^.Mese, Oggi^.Anno) Enter 21 11 2000 Oggi^ .Giorno .Mese .Anno
21 11 2000 Oggi^ A^ 5 B^ 7 TYPE DateType = RECORD Giorno:1..31; Mese:1..12; Anno:integer END; DataPunt=^DateType; IntPunt=^integer; VAR Oggi:DataPunt; A,B:IntPunt; new(A); new(B); new(Oggi); A^:=5; B^:=7; write(‘Dammi la data (giorno mese anno): ‘); WITH Oggi^ DO readln(Giorno, Mese, Anno) Dammi la data (giorno mese anno) : 21 11 2000
L’operazione A^ :=B^ 7 L’operazione C :=B A^ 5 garbage C^ X 12 B^ C^ 7 12 B^ 7 Gli unici operatori che si applicano alle variabili puntatori sono: operatore di assegnazione := operatori booleani = <> TYPE DataType = RECORD Giorno:1..31; Mese:1..12; Anno:integer END; DataPunt=^DateType; IntPunt=^integer; VAR Oggi:DataPunt; A,B,C:IntPunt; Domani:DataType;
A^ 7 B^ 7 A^ : =5 B^ := 7 A^ :=B^ IF (A^ = B^) AND (A <> B) THEN writeln(‘ I puntatori sono diversi ma i valori delle variabili puntate sono eguali’) TYPE IntPunt=^integer; VAR A,B,C:IntPunt;
garbage C^ X 12 B^ 7 C^ C^ 12 12 B^ ? B^ Come eliminare la spazzatura TYPE IntPunt=^integer; VAR A,B,C:IntPunt; C :=B IF (C = B) THEN writeln(‘ I puntatori puntano alla stessa variabile’) dispose(C) C :=B IF (C = B) THEN writeln(‘ I puntatori puntano alla stessa variabile’)
In memoria esiste una speciale area detta run-time-heap dove sono allocate le variabili puntatore. Nello heap ci sono le variabili puntatori create da new ad es. A B C D
Questa istruzione è valida solo se il puntatore C esiste. L’istruzione C:=B mostra che possiamo assegnare memoria ad un puntatore senza fare uso di new questo ci permette di avere due puntatori che puntano alla stessa variabile dinamica, riducendo così lo spazio di memoria usato. Possiamo quindi scrivere new(B); B^:=18; B:=C Vi è un solo valore che una variabile puntatore può assumere e che non punta a nulla: NIL. Es: D:= NIL; Questa assegnazione serve per informare che per ora la variabile puntatore non è stata ancora associata a una variabile dinamica. Attenzione se a un puntatore è assegnato NIL, es. D:= NIL, non è possibile fare dispose(D). Si possono fare test per vedere se il puntatore è libero di essere associato ad una variabile dinamica. Attenzione NIL non è assegnato per default.
Se abbiamo allocato memoria es. new(D); D^:=5; D:= NIL resta spazzatura bisogna invece fare coem di seguito new(D); D^:=5; dispose(D); D:= NIL; NIL non elimina la spazzatura Poichè possiamo assegnare memoria ad un puntatore senza fare uso di new questo ci permette di avere due puntatori che puntano alla stessa variabile dinamica, riducendo così lo spazio di memoria usato.
ClientRecord Anagrafe ClienteN Info Cognome Nome ARRAY DI PUNTATORI CONST MaxStu=100; TotaleProve=5; TYPE String25=STRING[25]; String10=STRING[10]; String4=STRING[4]; RisultatiArray=ARRAY[1.. TotaleProve] OF integer StuRecord = RECORD Cognome, Nome: String25; Nascita: String10; Matricola:String10; Risultati:RisultatiArray; Media:real; END; ClientesFile=FILE OF ClientRecord; ClientPointer=^ClientRecord; PointerArray=ARRAY[0..MaxClients] OF ClientPointer; VAR ClientsOnFile:ClientsFile; ByName, ByNo: PointerArray; TotalStu:integer; Supponiamo che i ClienteN siano stringhe di lunghezza 5 tutte piene. Quindi avremo numeri tipo 00000 00123 23041 Useremo la stringa 00000 come sentinella.
Zucchi Carlini Abate Anna Ugo Carlo 03/01/75 30/11/76 30/11/72 050/514 050/734 050/714 2000 2000 1999 28 22 28 30 27 30 21 23 30 27 21 22 23 30 27 27 24 25 PROBLEMA Leggere il file Semester e realizzare due array di puntatori uno ordinato per nome (ByName) ed uno per matricola (ByMat). L’array ByName contiene i puntatori agli studenti ordinati per nome. Vogliamo scrivere una funzione che faccia una ricerca di uno studente per numero di matricola sull’array ByMat. ByName ByMat 1 1 mid mid TotalStu TotalStu
Pseudo Codice AssegnaFile(Semester) OrganizzaDati(ByName,ByMat,TotalStu,Semester) write('Dammi la matricola cercata: '); readln(Matr); Risultati(CercaStudente(ByMat,Matr,1,TotalStu));
PROGRAM ArrayPuntatori(input, output, Semester); CONST MaxStu=100; TotaleProve=100; TYPE Stringa4 = STRING[4]; Stringa10 = STRING[10]; Stringa25 = STRING[25]; RisultatiArray=ARRAY[1..TotaleProve] OF integer; StuRecord = RECORD Cognome, Nome : Stringa25; Nascita:Stringa10; Matricola:Stringa10; AnnoCorso:Stringa4; Risultati:RisultatiArray; Media:real; END; StuFile=FILE OF StuRecord; StuPointer=^StuRecord; PointerArray=ARRAY[0.. MaxStu] OF StuPointer; VAR Semester: StuFile; ByName, ByMat: PointerArray; TotalStu:integer; Matr:Stringa10;
PROCEDURE Insert(NewElement:StuPointer; Candidate: integer; VAR ByMatP:PointerArray); BEGIN WHILE (ByMatP[Candidate-1]^.Matricola > NewElement^.Matricola ) DO BEGIN ByMatP[Candidate]:= ByMatP[Candidate-1]; Candidate:=Candidate-1 END; ByMatP[Candidate]:=NewElement END; PROCEDURE OrganizzaDati(VAR ByName,ByMat:PointerArray;VAR TotalStu:integer; VAR StuOnFile:StuFile); VAR AStu:StuPointer; BEGIN reset(StuOnFile); TotalStu := 0; new(ByMat[0]); ByMat[0]^.Matricola:='00000'; WHILE NOT eof(StuOnFile) DO BEGIN new(AStu); read(StuOnFile, AStu^); TotalStu := TotalStu + 1; ByName[TotalStu] := AStu; Insert(AStu, TotalStu, ByMat) END; close(StuOnFile) END;
FUNCTION CercaStudente(VAR ByMatP: PointerArray; Numero:Stringa10; Lo,Hi:integer): StuPointer; VAR Probe:integer; BEGIN IF Lo > Hi THEN CercaStudente :=NIL ELSE BEGIN Probe:=(Lo+Hi) DIV 2; IF ByMatP[Probe]^.Matricola = Numero THEN CercaStudente:= ByMatP[Probe]; ELSE IF ByMatP[Probe]^.Matricola < Numero THEN CercaStudente:= CercaStudente(ByMat, Numero, Probe+1,Hi) ELSE CercaStudente:= CercaStudente(ByMat, Numero, Lo,Probe-1) END END; PROCEDURE Risultati(MatrCand:Stupointer); BEGIN writeln(Matrcand^.Cognome,' ', MatrCand^.Nome,' ', MatrCand^.Matricola); END;
{******************** MAIN ******************} BEGIN assign(semester,'a:\probe.dat'); OrganizzaDati(ByName,ByMat, TotalStu, Semester); readln; write('Dammi la matricola cercata: '); readln(Matr); Risultati(CercaStudente(ByMat,Matr,1,TotalStu)); readln END.
Esercizio Scrivere il programma completo per la gestione dei records attraverso array di puntatori ordinati per Nome, Matricola, Data di Nascita, Media.
SBAGLIATO !!!!!!!!!! SBAGLIATO !!!!!!!!!! CORRETTO !!!!!!!!!! Alcuni suggerimenti sui file Evitare di usare il REPEAT … UNTIL quando si leggono file binari o testo. reset(SomeFile) REPEAT read(SomeFile,SomeComponent) elabora(SomeComponent) UNTIL eof(SomeFile) reset(SomeFile) IF NOT eof(SomeFile) THEN REPEAT read(SomeFile,SomeComponent) elabora(SomeComponent) UNTIL eof(SomeFile) Non mettere mai un reset o un rewrite all’interno di un loop. WHILE NOT eof(SomeFile) DO BEGIN reset(SomeFile); read(SomeFile,SomeComponent) elabora(SomeComponent) END;
Ricordare che il valore di una variabile file cambia sempre quando si usano il read o il write, quindi le chiamate alle variabili file vanno sempre fatte per VAR e mai per valore. Ricordare che readln e writeln si possono usare solo con i file testo e non con i file binari. Quando si implementano procedure per la gestione di file realizzare sempre procedure per provare se i record o comunque i dati sono correttamente inseriti facendo le prove con pochi esempi.
Alcuni suggerimenti sui puntatori Per il passaggio di parametri relativi ai puntatori valgono le stesse regole che si applicano per gli altri tipi di variabili. Quando un puntatore è chiamato per valore viene fatta una copia locale del suo valore, cioè dell’indirizzo. Quando un puntatore è chiamato per variabile viene prodotto un alias locale per il suo valore attuale, ricordando sempre che si tratta di indirizzi.
PROGRAM TestChiamatePuntatori; TYPE IntP=^integer; VAR AnIntP:IntP; PROCEDURE ValCall(XP:IntP); BEGIN XP^:=7; END; PROCEDURE VarCall(VAR XP:IntP); BEGIN XP^:=7; END; BEGIN new(AnIntP); AnIntP^:=5; ValCall(AnIntP); writeln(‘Output= ‘,AnIntp^:1); END. BEGIN new(AnIntP); AnIntP^:=5; ValCallVar(AnIntP); writeln(‘Output= ‘,AnIntp^:1); END. Output= 7 Questo accade perché l’indirizzo passato dalla chiamata rimane lo stesso mentre il valore della variabile dinamica è cambiato. Questa chiamata equivale ad una chiamata per VAR su XP^. Output= 7 Il valore resta lo stesso essendo la chiamata precedente equivalente ad una chiamata per VAR su XP^.
PROGRAM TestChiamatePuntatori; TYPE IntP=^integer; VAR AnIntP:IntP; PROCEDURE ValCall(XP:IntP); BEGIN dispose(XP); END; PROCEDURE VarCall (VAR XP:IntP); BEGIN dispose(XP); END; BEGIN new(AnIntP); AnIntP^:=5; VarCall (AnIntP); writeln(‘Output= ‘,AnIntp^:1); END. BEGIN new(AnIntP); AnIntP^:=5; ValCall(AnIntP); writeln(‘Output= ‘,AnIntp^:1); END. Output= non predicibile Questo accade perché l’indirizzo passato dalla chiamata viene deallocato. Poiché questo indirizzo nel main corrisponde anche a quello di AnInt^ il valore di AnInt^ ora non è più predicibile. Output= non predicibile Come prima.
PROGRAM TestChiamatePuntatori; TYPE IntP=^integer; VAR AnIntP:IntP; PROCEDURE ValCall(XP:IntP); BEGIN dispose(XP); new(XP); END; PROCEDURE VarCall (XP:IntP); BEGIN dispose(XP); new(XP); END; BEGIN new(AnIntP); AnIntP^:=5; ValCall(AnIntP); writeln(‘Output= ‘,AnIntp^:1); END. BEGIN new(AnIntP); AnIntP^:=5; VarCall (AnIntP); writeln(‘Output= ‘,AnIntp^:1); END. Output= non predicibile Questo accade perché l’indirizzo passato dalla chiamata viene deallocato. Poiché questo indirizzo nel main corrisponde anche a quello di AnInt^ il valore di AnInt^ ora non è più predicibile. Inoltre la memoria allocata da new diventa spazzatura non appena si esce dal blocco. Output= non predicibile Come prima. Solo che ora non si crea spazzatura.