Scaricare la presentazione
La presentazione è in caricamento. Aspetta per favore
PubblicatoFiorenza Giovannini Modificato 10 anni fa
2
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 La sintassi di un file binario è diversa da quella di un file testo. identificatore = FILEOF type
3
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 lettura del file reset(NomeFile) es. reset(Reals) Preparazione alla scrittura del file rewrite(NomeFile) es. rewrite(Reals)
4
Il controllo di fine file viene eseguito come per i text file con la funzione eof(NomeFile) Essendo i dati scritti uno di seguito allaltro non esiste più l. 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 Giulio Luca RossiCarlo Maria BianchiGian Giacomo Verdi…………….. Carlo Maria Bianchi Area Dati AName.First Carlo AName.Middle Maria AName.Last Bianchi
5
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 Esempio reset(Ints); WHILE NOT eof(Ints) DO BEGIN read(Ints, Intero); elabora(Intero) END; Luso dell produce un errore di sintassi.
6
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); 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); Errore !!!!!! Non essendoci non è permesso il writeln. 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;
7
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;
8
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)
9
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;
10
TYPE Stringa20 = STRING[20] RisultatiArray=ARRAY[1..TotaleProve] OF integer; AnagraficaRecord = RECORD Cognome, Nome : Stringa20 END; DataRecord = RECORD Giorno, Mese, Anno :integer END; StuRecord = RECORD Anagrafe:AnagraficaRecord; Nascita:DataRecord; Matricola:StringaNome; AnnoCorso:StringaNome; Risultati:RisultatiArray; Media:real; END; Studente AnagrafeNascitaMatricola CognomeNomeAnnoMeseGiorno AnnoCorsoRisultatiMedia CONST MaxStud=150; TYPE StuRecord = RECORD ………………. END; ClassArray=ARRAY[1..Maxstud] OF StuRecord; StuRecFile=FILE OF StuRecord; VAR InFile:StuRecFile; AClass: ClassArray; TotalStudents:integer;
11
Procedura per la costruzione di un Array di record a partire da un file binario. 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; Supponiamo di introdurre meno di MaxStud record StuRecord = RECORD Anagrafe:AnagraficaRecord; Nascita:DataRecord; Matricola:StringaNome; AnnoCorso:StringaNome; Risultati:RisultatiArray; Media:real; END;
12
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 Estiva CSPE99 Corso Programmazione Sessione Invernale CSPI99 Corso Programmazione CSP99 Semester OldMaster NewMaster merge SessioneStuRecord SessioneStuRecord MStuRec
13
Pseudo Codice di UpdateMerge AssignFiles(LaSessione, Semester, OldMaster, NewMaster); Merge(LaSessione, Semester, OldMaster, NewMaster); Risultati(Semester,OldMaster,NewMaster); writeln(' Fine aggiornamento ') END.
14
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} Semester OldMaster NewMaster StuRecord MStuRec
15
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} StuRecord NascitaMatricola CognomeNome AnnoCorsoRisultatiMedia Sessione MStuRecord SemesterOldMaster NewMaster SessioneStuRecord SessioneStuRecord MStuRec
16
AssignFiles LaSessione Semester OldMaster NewMaster Merge LaSessione Semester OldMaster NewMaster OldMaster GetMasterRec MStu1 GetSemesterRec SemesterMStu2 Stu1GoesFirst write GetMasterRecGetSemesterRec Vero Falso MStu1.Info MStu2.Info OldMasterMStu1SemesterMStu2 NewMater MStu1 NewMater MStu2 CopyLastTwo NewMater MStu1 MStu2 CopySemesterRecs OldMaster NewMaster CopyMasterRecs Semester NewMaster Risultati Semester OldMaster NewMaster
17
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; SemesterOldMaster NewMaster SessioneStuRecord SessioneStuRecord MStuRec
18
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; CopyLastTwo(MStu1,MStu2,NewMaster); CopyOldMasterRecs(OldMaster,NewMaster); CopySemesterRecs(LaSessione,Semester,NewMaster); close(Semester); close(OldMaster); close(NewMaster) END; SemesterOldMaster NewMaster SessioneStuRecord SessioneStuRecord MStuRec MStuRecord= RECORD Sessione:Stringa25; Info:StuRecord END; Necessario perché il Get... avviene dopo la write
19
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; StuRecord NascitaMatricola CognomeNome AnnoCorsoRisultatiMedia Sessione MStuRecord SemesterOldMaster NewMaster SessioneStuRecord SessioneStuRecord MStuRec
20
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; Stu1.Cognome <> Stu2.Cognome Stu1, Stu2 Stu1.Nome <> Stu2.Nome Stu1.Cognome < Stu2.Cognome Stu1.Nome < Stu2.Nome <> = = Vero Falso Vero Stu1.Matricola <> Stu2. Matricola Falso
21
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; PROCEDURE CopyOldMasterRecs(VAR OldMaster, NewMaster:MStuRecFile); VAR AName:MStuRecord; BEGIN WHILE NOT eof(OldMaster) DO BEGIN read(OldMaster,AName); write(NewMaster,AName) END END;
22
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;
23
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;
24
SemestreOld New agazzi carlobrescia ugoagazzi carlo bottazzi annadistante claudiobottazzi anna napoli giuliolivorno giuliabrescia ugo perna claudiovenezia annadistante claudio venezia elenaviterbo giorgiolivorno giulia ---- ----napoli giulio ---- ----perna claudio ---- ----venezia anna ---- ----venezia elena ---- ----viterbo giorgio Fine aggiornamento
25
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
26
Esercizio Scrivere due procedure: una per creare un file di tipo Semester e un file di tipo OldMaster una per leggere gli stessi file.
27
I PUNTATORI Allocazione Statica Dato un blocco ogni variabile è allocata in memoria quando inizia lelaborazione del blocco e deallocata quando lelaborazione di tutto il blocco termina. Allocazione Dinamica Quando ogni variabile è allocata o deallocata in memoria durante lelaborazione del blocco. Il puntatore Un puntatore è una variabile il cui valore rappresenta un indirizzo di memoria. Esso serve per creare o eliminare una variabile dinamica. Variabile dinamica E una variabile alla quale si assegna spazio in memoria durante lelaborazione di un blocco.
28
identificatoretype =^ 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 dellindirizzo di memoria a partire del quale vi sono eventualmente i valori Variabile Anonima: una variabile alla quale si accede solo tramite un puntatore Variabile Nominata: una variabile alla quale si accede tramite un nome
29
Per assegnare un indirizzo a una variabile puntatore si usa la procedura new: es. new(Oggi) TYPE DataType = RECORD Giorno:1..31; Mese:1..12; Anno:integer END; DataPunt=^DateType; IntPunt=^integer; VAR Oggi:DataPunt; A,B:IntPunt; Spazio di memoria assegnato Prima di fare la chiamata new(Oggi) Oggi^ ? Dopo la chiamata new(Oggi) Oggi^ ??? 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 ??? 21112000
30
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 21112000 Oggi^ 5 A^ 7 B^
31
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; Loperazione C :=B 12 C^ 7 B^ X garbage 7 Loperazione A^ :=B^ 5 A^ 7 B^ 12 C^
32
TYPE IntPunt=^integer; VAR A,B,C:IntPunt; 7 A^ 7 B^ 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)
33
TYPE IntPunt=^integer; VAR A,B,C:IntPunt; C :=B IF (C = B) THEN writeln( I puntatori puntano alla stessa variabile) 12 C^ 7 B^ X garbage dispose(C) C :=B IF (C = B) THEN writeln( I puntatori puntano alla stessa variabile) 12 C^ B^ ? 12 C^ B^ Come eliminare la spazzatura
34
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
35
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. Si possono fare test per vedere se il puntatore è libero di essere associato ad una variabile dinamica. Attenzione NIL non è assegnato per default. Listruzione 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 Questa istruzione è valida solo se il puntatore C esiste. Attenzione se a un puntatore è assegnato NIL, es. D:= NIL, non è possibile fare dispose(D).
36
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.
37
ARRAY DI PUNTATORI Anagrafe ClienteN Info ClientRecord CognomeNome 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 tipo000000012323041 Useremo la stringa 00000 come sentinella.
38
PROBLEMA Leggere il file Semester e realizzare due array di puntatori uno ordinato per nome (ByName) ed uno per matricola (ByMat). Larray ByName contiene i puntatori agli studenti ordinati per nome. Vogliamo scrivere una funzione che faccia una ricerca di uno studente per numero di matricola sullarray ByMat. 1 mid TotalStu 1 mid TotalStu ByName ByMat 050/71421 22 23 30 27 AbateCarlo 30/11/76200025050/73428 22 28 30 27 CarliniAnna 30/11/72199927050/51430 21 23 30 27 ZucchiUgo 03/01/75200024
39
Pseudo Codice AssegnaFile(Semester) OrganizzaDati(ByName,ByMat,TotalStu,Semester) write('Dammi la matricola cercata: '); readln(Matr); Risultati(CercaStudente(ByMat,Matr,1,TotalStu));
40
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;
41
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;
42
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;
43
{******************** 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.
44
Esercizio Scrivere il programma completo per la gestione dei records attraverso array di puntatori ordinati per Nome, Matricola, Data di Nascita, Media.
45
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) SBAGLIATO !!!!!!!!!! CORRETTO !!!!!!!!!! Non mettere mai un reset o un rewrite allinterno di un loop. WHILE NOT eof(SomeFile) DO BEGIN reset(SomeFile); read(SomeFile,SomeComponent) elabora(SomeComponent) END; SBAGLIATO !!!!!!!!!!
46
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.
47
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è dellindirizzo. Quando un puntatore è chiamato per variabile viene prodotto un alias locale per il suo valore attuale, ricordando sempre che si tratta di indirizzi.
48
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. Output= 7 Questo accade perché lindirizzo passato dalla chiamata rimane lo stesso mentre il valore della variabile dinamica è cambiato. Questa chiamata equivale ad una chiamata per VAR su XP^. BEGIN new(AnIntP); AnIntP^:=5; ValCallVar(AnIntP); writeln(Output=,AnIntp^:1); END. Output= 7 Il valore resta lo stesso essendo la chiamata precedente equivalente ad una chiamata per VAR su XP^.
49
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; ValCall(AnIntP); writeln(Output=,AnIntp^:1); END. Output= non predicibile Questo accade perché lindirizzo passato dalla chiamata viene deallocato. Poiché questo indirizzo nel main corrisponde anche a quello di AnInt^ il valore di AnInt^ ora non è più predicibile. BEGIN new(AnIntP); AnIntP^:=5; VarCall (AnIntP); writeln(Output=,AnIntp^:1); END. Output= non predicibile Come prima.
50
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. Output= non predicibile Questo accade perché lindirizzo 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. BEGIN new(AnIntP); AnIntP^:=5; VarCall (AnIntP); writeln(Output=,AnIntp^:1); END. Output= non predicibile Come prima. Solo che ora non si crea spazzatura.
51
PROGRAM TestChiamatePuntatori; TYPE IntP=^integer; VAR AnIntP:IntP; PROCEDURE ValCall(XP:IntP); BEGIN XP:=NIL; END; PROCEDURE VarCall (XP:IntP); BEGIN XP:=NIL; END; BEGIN new(AnIntP); AnIntP^:=5; ValCall(AnIntP); writeln(Output=,AnIntp^:1); END. Output= 5 Questa istruzione riassegna un valore a XP. Ora XP e AnInt hanno valori differenti. Quando si esce da ValCall XP è perso e quindi AnInt resta =5. Non cè spazzatura perché abbiamo usato il NIL. BEGIN new(AnIntP); AnIntP^:=5; VarCall (AnIntP); writeln(Output=,AnIntp^:1); END. Output= 5 Questa istruzione riassegna a AnIntP il valore NIL. Quindi quando si esce da ValCall AnIntP^ non è predicibile inoltre a AnIntP è stato assegnato un nuovo valore per cui il precedente contenente 5 è diventato spazzatura.
52
PROGRAM TestChiamatePuntatori; TYPE IntP=^integer; VAR AnIntP:IntP; PROCEDURE ValCall(XP:IntP); BEGIN new(XP); XP^:=7 writeln(XP:1) END; PROCEDURE VarCall (XP:IntP); BEGIN new(XP); XP^:=7 writeln(XP:1) END; BEGIN new(AnIntP); AnIntP^:=5; ValCall(AnIntP); writeln(Output=,AnIntp^:1); END. OutputCall=7 Output= 5 Qui si alloca un nuovo indirizzo per la variabile che prima aveva indirizzo AnInt. Leffetto della assegnazione XP:=7 è ristretto solo agli scopi della procedura ValCall. Ora XP e AnIntP rappresentano due diverse variabili puntatore, quando usciamo dalla procedura AnIntP^ vale sempre 5, mentre il valore di XP^ è perduto come spazzatura. BEGIN new(AnIntP); AnIntP^:=5; VarCall (AnIntP); writeln(Output=,AnIntp^:1); END. OutputCall=7 Output= 7 Listruzione new(XP) fa sì che AnIntP diventa spazzatura. Quindi il valore 7 è mostrato due volte poiché tramite la Call VAR restituisce detto valore a AnIntp^.
53
ESERCIZIO E-MAIL PROGRAM MESSAGGI; USES Stringa; VARstrDate, strEmail: stringADT; InFile:text; MsgNum:integer; PROCEDURE InitString (VAR strDate,strEMail:stringADT);{Inizializza le stringhe di inzio Data ed inizio Indirizzo} BEGINEND; {Visualizza l'indirizzo elettronico e le date usando la ricorsione} PROCEDURE ExtractEMail_Date_Ric (VAR MsgNum: integer; VAR InFile:text); VAR outstr,strApp,Date,EMail:stringADT; BEGIN IF not eof(InFile) THEN BEGIN ReadlnString(OutStr,InFile); StrExtract(OutStr,1,strDate.len,strApp); IF strEqual(strApp,strDate) THEN BEGIN MsgNum:=MsgNum+1; StrExtract(outstr,strDate.len+1,outstr.len,Date); ReadlnString(outstr,InFile); StrExtract(outstr,strEMail.len+1,outstr.len,EMail); END; ExtractEMail_Date_Ric(MsgNum,InFile); IF strEqual(strApp,strDate) THEN BEGIN PrintString(Date); write(' '); PrintString(EMail); writeln; END; PROCEDURE Introduction; BEGINEND;
54
{BODY} BEGIN InitString(strDate,strEMail); MsgNum:=0; Introduction; assign(InFile,'c:\tp\esempi\posta2.txt'); reset(InFile); writeln('Visualizzazione con la Ricorsione'); writeln(' Data Indirizzo'); MsgNum:=0; reset(InFile); ExtractEmail_Date_Ric(MsgNum,InFile); close(InFile); writeln('Sono stati trovati ',MsgNum,' messaggi.'); readln END.
55
PROGRAM leggi_file_di_posta; uses strinsur; { estrae da un file di posta elettronica gli indirizzi e le date e li stampa in ordine crescente per data } VAR testo:text; { file} righe:integer; { contatore di righe stampate } PROCEDURE elaboratesto(var testo:text;var righe:integer); { procedura ricorsiva che elabora il testo } VAR from,ext,str1,date,ind:tipostringa; { stringhe } BEGIN converti('From -',from); { crea una stringa di controllo } inizializza(ext); inizializza(str1); inizializza(date); inizializza(ind); WHILE NOT(eof(testo)) AND (not(strequal(ext,from))) DO {estrae da ogni rigo una stringa e la confronta con quella di controllo } BEGIN readlnstring(str1,testo); strextract(str1,1,6,ext); END; IF strequal(ext,from) THEN BEGIN strextract(str1,8,50,date); { estrae la data } readlnstring(str1,testo); strextract(str1,14,50,ind); { estrae l'indirizzo } elaboratesto(testo,righe); write(' C''Š un messaggio da parte di ');{ stampa l'indirizzo e la data letti } writelnstringa(ind,output); write(' ricevuto in data = '); writelnstringa(date,output); writeln; righe:=righe+1;{ incrementa il contatore che permette di stampare 7 messaggi alla volta } IF (righe mod 7)=0 THEN BEGIN writeln('Premi un tasto per continuare '); readln; END;
56
{BODY} BEGIN assign(testo,'c:\tp\esempi\posta.txt'); reset(testo); righe:=0; elaboratesto(testo,righe); write('Non ci sono pi messaggi '); readln; END.
57
Procedura B ExtractEMail_Date_Ric(InFile IF not eof(InFile) THEN BEGIN leggi(testo) estrai(strApp) IF strDate = FROM THEN BEGIN estrai(data) leggi(testo) estrai(indirizzo) END ExtractEMail_Date_Ric(InFile); fai_le_stampe END NOT(eof) strData = FROM Leggi estrai Fine Ricorsione pop Ricorsione push Leggi estrai Stampa SI NOSI NO Procedura A elaboratesto (testo) inizializzaStringhe(ext, str1, data, ind) WHILE NOT eof(testo) AND NOT ext=FROM DO{estrae da ogni rigo una stringa e la confronta con quella di controllo } leggi(testo) estrai(ext) IF ext=FROM THEN BEGIN estrai(data) leggi(testo) estrai(ind) elaboratesto(testo) fai_le_stampe END NOT(eof) & ext= FORM strData = FROM Leggi estrai Fine Ricorsione pop Ricorsione push Leggi estrai Stampa WHILE NO SI NO SI
Presentazioni simili
© 2024 SlidePlayer.it Inc.
All rights reserved.