Written by xinyiman Ottobre 23, 2011, 10:28:00 pm23010 ViewsRating: 0 (0 Rates)Print
Fino ad ora abbiamo visto solo programmi che
permettevano il mantenimento di dati in memoria solo fino al termine
dell'esecuzione dello stesso. Mantenere i dati memorizzato oltre
l'esecuzione del programma è possibile tramite l'uso dei file. Per
capire come funzionano analizziamo il seguente esempio.
procedure
LavoriamoConIFile();
var
F: system.Text;
Riga: string;
begin
AssignFile (F,'Test.txt');
rewrite (f);
writeln (f,'Uso dei file1!');
CloseFile (f);
AssignFile (F,'Test.txt');
append (f);
writeln (f,'Uso dei file2!');
CloseFile (f);
AssignFile (F,'Test.txt');
reset
(f);
while
not eof(F) do
begin
readln(f,Riga);
writeln(Riga);
end;
CloseFile (f);
writeln('FINITO!');
end;
Abbiamo dichiarato due variabili, la variabile F che
contiene lo stream al file e la variabile Riga che conterrà i dati
letti dal file. In questo modo:
var
F: system.Text;
Riga: string;
Dopodiché abbiamo detto al programma che vogliamo
aprire un canale di comunicazione con un file che in questo caso si
chiama Test.txt e che il canale in questione si chiama F, e lo
abbiamo fatto in questo modo:
AssignFile (F,'Test.txt');
Però al momento non abbiamo ancora aperto fisicamente
un canale di comunicazione con il file, cosa che facciamo in questa
maniera:
rewrite (f);
Il rewrite non è il solo modo di aprire il canale verso
il file. Ci sono tre modi di farlo e sono:
rewrite: che apre il file in scrittura, se non c'è lo
crea e se esiste con del contenuto ne cancella il contenuto.
reset: che apre il file in sola lettura, e se il file
non esiste restituisce un errore
append: apre il file in scrittura ma senza cancellarne
il contenuto, aggiungendo al fondo del contenuto già esistente.
In seguito abbiamo scritto all'interno del file la
stringa 'Uso dei file1!', in questo modo:
writeln (f,'Uso dei file1!');
al passo successivo abbiamo chiuso in canale il sola
scrittura sul file in questo modo:
CloseFile (f);
Bene così facendo abbiamo creato un file di nome
Test.txt se ancora non esisteva, se invece già esisteva allora lo
abbiamo svuotato. Dopodiché abbiamo inserito la stringa 'Uso dei
file1 !'. Ma il programma non è ancora terminato, e vediamo come
prosegue:
AssignFile (F,'Test.txt');
append (f);
writeln (f,'Uso dei file2!');
CloseFile (f);
Grazie a quello appena imparato possiamo analizzare il
blocco per intero, che apre il canale al file senza svuotarlo (grazie
al comando append) e inserisce in coda la stringa 'Uso dei file2!',
in seguito chiude il canale al file.
Ma il programma ancora non è terminato, analizziamo il
pezzo successivo:
AssignFile (F,'Test.txt');
reset
(f);
while
not eof(F) do
begin
readln(f,Riga);
writeln(Riga);
end;
CloseFile (f);
writeln('FINITO!');
In questo ultimo blocco che andiamo ad analizzare
possiamo subito notare che grazie al comando reset apriamo il canale
al file in sola lettura. Dopodiché entriamo in un ciclo da cui si
esce solo quando si è a fine file. Ogni volta che eseguo una
interazione (ovvero un giro del codice contenuto nel ciclo) leggo una
riga dal file con il comando readln passandogli come parametri il
canale f e una stringa che conterrà la riga stessa e poi la stampo
grazie al comando writeln. Una volta che sono arrivato a fine file
stampo a video la stringa 'FINITO!'.
Da tenere ben presente è la dicitura EOF che significa End Of File e che serve ad identificare la fine del file.
Written by xinyiman Ottobre 22, 2011, 11:12:00 am23411 ViewsRating: 0 (0 Rates)Print
Fino ad ora tutto il codice che abbiamo scritto era in
un blocco solo, ovvero abbiamo scritto tutte le righe una dietro
l'altra, ma solo perché gli esempi visti erano semplici, ma capita e
anche sovente di dover scrivere pezzi di codice che serve
riutilizzare. Le motivazioni possono essere molteplici, ma sovente
conviene utilizzare le procedure e le funzioni piuttosto che scrivere
un monoblocco di codice. Ipotizziamo di dover invertire il valore di
due variabili di nome Valore1 e Valore2 e di dover effettuare questa
operazione sovente all'interno del nostro programma, per poter fare
questa operazione abbiamo bisogno anche della variabile di nome
Valore3. Vediamo ora come andrebbe scritto il codice che effettua
l'inversione dei valori:
Valore3:=Valore1;
Valore1:=Valore2;
Valore2:=Valore3;
Bene ora immaginiamo di doverlo scrivere 10, 100, 1000
volte all'interno del codice, possiamo facilmente capire che il
codice in questione diverrà molto lungo, quindi difficile da gestire
in un secondo momento, e in più il programma diverrebbe molto grosso
senza tenere conto che la variabile di nome Valore3 rimarrebbe
allocata in memoria per tutta l'esecuzione del programma. Mentre ora
immaginiamo di immettere questo codice scritto in una procedura, le
migliorie sono diverse, ad esempio quando la procedura ha finito la
sua vita la variabile Valore3 viene deallocata, il programma occupa
meno spazio e se bisogna fare manutenzione il codice diventa più
leggibile.
Bene fino ad ora abbiamo parlato di procedure e funzioni
come se fossero la stessa cosa, ma fondamentalmente c'è una
differenza tra le due cose, ovvero che le funzioni restituiscono un
valore, mentre le procedure no. Vediamo ora come si dichiara una
procedura e come si dichiara una funzione. Procedura:
procedure
NomeProcedura();
begin
.
.
.
end;
Funzione:
function
NomeFunzione(): tiporestituito;
begin
.
.
NomeFunzione:=valorerestituito;
end;
La prima cosa che bisogna notare è che sia le funzioni
che le procedure hanno un nome che le contraddistingue, per seconda
cosa bisogna notare che entrambe terminano con le parentesi e con il
punto e virgola. Ma le due cose più importanti da notare sono che la
funzione per restituire un valore deve specificare di che tipo è, e
per effettuare la restituzione bisogna attribuire il valore da
restituire al nome della funzione stessa.
Un altra cosa da apprendere quando si tratta l'argomento
procedure e funzioni è il passaggio di parametri. Per passaggio di
parametri si intende il passare delle informazioni alla procedura o
alla funzione. Vediamo un esempio concreto:
Bene come si può notare, all'interno delle parentesi
tonde subito dopo il nome della procedura, è presente la
dichiarazione di tre variabili intervallate da dei punti e virgola.
In questo modo definisco quanti parametri passare alla
funzione/procedura specificando il tipo del dato che gli passo.
I parametri possono essere passati in due modi, per
valore o per referenza. La differenza tra le due è che se sono
passati per valore, il valore stesso non può essere modificato
all'esterno della procedura, se invece il parametro è passato per
referenza allora il valore se viene modificato verrà modificato
sempre nel programma. In pratica i due tipi si differenziano grazie
alla parola riservata var all'interno delle parentesi tonde. Vediamo
un esempio di passaggio di parametri per valore:
procedure
Inverti(var Valore1: integer; var Valore2: integer);
e ricompilare. Una volta eseguite entrambe le versioni è
evidente la differenza tra le due.
N.B.: se per caso si immettesse la riga procedure
Inverti(Valore1: integer; var Valore2: integer); allora
Valore1 sarebbe passato per valore e Valore2 per referenza.
Written by xinyiman Ottobre 22, 2011, 11:06:00 am22995 ViewsRating: 0 (0 Rates)Print
Le strutture sono dei tipi di variabile composte da
variabile semplici, ipotizziamo di voler descrivere un animale con
una variabile, dovremmo stabilire che tipo di animale è, quanti anni
di vita ha, e tutta una serie di altri fattori. Bene con i mezzi fino
ad ora acquisiti, dovremmo fare tutto ciò con due o più variabili,
dipende dal numero di caratteristiche che si vogliono far avere
all'animale; con una struttura è possibile fare ciò con una
variabile. Vediamo ora come si dichiara una struttura:
type
nomedadareallastruttura=record
caratteristica1:
tipovariabile;
caratteristica2:
tipovariabile;
.
.
.
caratteristicaN:
tipovariabile;
end;
Ora che sappiamo come si dichiara una struttura dobbiamo
anche sapere che si posiziona subito dopo altre eventuali strutture
già dichiarate o dopo l'inclusione delle librerie, ovvero dopo la
sezione USES. Vediamo ora l'esempio di cui parlavamo poco sopra,
ovvero della variabile che identifica l'animale, io ho usato solo 2
caratteristiche, razza e anni. Le parti importanti sono sottolineate.
La prima cosa che dovrebbe saltare all'occhio come già
detto prima è il posizionamento della dichiarazione della struttura,
ovvero la prima parte sottolineata. La seconda cosa da notare è che
una volta definita la struttura dobbiamo dichiarare delle variabili
con tipo di variabile la struttura stessa, ovvero la seconda parte
sottolineata. La terza cosa da capire è che per accedere alle
singole caratteristiche della struttura si usa il punto, sia per
valorizzarlo che per leggerlo, esattamente come nel terzo blocco
sottolineato nell'ultimo esempio.
Vediamo ora un altro tipo di dato non molto utilizzato,
ma che può risultare comodo in alcune occasioni: gli insiemi, che in
Pascal sono molto simili al concetto di insieme in matematica; dato
un insieme A di oggetti di un insieme di dati B, ogni oggetto di B
appartiene o non appartiene ad A.
Vediamo come dichiarare gli insiemi con un esempio:
var giorni: SET OF integer;
Possiamo altrimenti scrivere:
type giorniLavorativi: SET OF integer;
var giorniRip : giorniLavorativi;
Ma il risultato è lo stesso. Per inizializzare un
insieme usiamo la sintassi:
giorniLavorativi := [1,3..7, 10..25, 29];
giorniRip := []; {insieme vuoto}
Si noti l'uso di un range nell'assegnazione. La sintassi
generale è quindi per un insieme [el1, el2, el3..el7, …] dove per
elN si intende elemento numero.
Le operazioni fattibili con gli insiemi sono le stesse
in matematica: ad esempio, "+" corrisponde all'unione, "-"
alla differenza e "*" all'intersezione.
[1, 3, 4] + [3, 9..11] = [1, 3, 4, 9..11]
[5, 7, 19, 22] - [22] = [5, 7, 19]
[5, 7, 19, 22] - [23] = [5, 7, 19, 22]
[11..22] * [15..56] = [15..22]
[11..22] + [15..56] = [11..56]
[5, 7, 19, 22] * [22] = [22]
[5, 7, 19, 22] * [23] = []
Per verificare se un elemento è in un insieme, usiamo
l'operatore IN:
if
1 in giorniLavorativi then
È possibile anche confrontare gli insiemi:
1. =: restituisce true se i due insiemi sono uguali;
2. <>: restituisce true se i due insiemi sono
diversi;
3. <=: restituisce true se il primo insieme è
sottoinsieme del secondo (il secondo contiene il primo);
Written by xinyiman Ottobre 20, 2011, 10:15:00 am22556 ViewsRating: (1 Rates)Print
Precedentemente si è parlato dei vettori come una serie
di celle una dietro l'altra in linea orizzontale, si possono
immaginare le matrici come un rettangolo o un quadrato di celle. Per
esempio si può immaginare questo come un vettore di 8 celle:
CELLA0
CELLA1
CELLA2
CELLA3
CELLA4
CELLA5
CELLA6
CELLA7
Mentre si può immaginare quanto segue come una matrice
di 5x4 celle:
CELLA0,0
CELLA0,1
CELLA0,2
CELLA0,3
CELLA0,4
CELLA1,0
CELLA1,1
CELLA1,2
CELLA1,3
CELLA1,4
CELLA2,0
CELLA2,1
CELLA2,2
CELLA2,3
CELLA2,4
CELLA3,0
CELLA3,1
CELLA3,2
CELLA3,3
CELLA4,4
Le matrici infatti si possono chiamare anche array
multidimensionali. Gli scopi di una matrice sono molteplici,
immaginiamo ad esempio il gioco degli scacchi, la scacchiera può
essere rappresentata semplicemente con una matrice. La dichiarazione
di una matrice si definisce così: nomevariabile:
array[Altezza,Larghezza] of tipodivariabile; vediamo un
esempio, se volessimo dichiarare la matrice sopra riportata di 5x4
celle dovremmo procedere così: Matrice1:
array[0..4,0..3] of integer;. Anche l'uso non è dissimile
dai vettori monodimensionali, prendiamo come esempio la matrice di
prima e vediamo di riempirla con dei numeri consecutivi.
program
project1;
{$mode
objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes, SysUtils, CustApp
{
you can add units after this };
type
{
TMyApplication }
TMyApplication = class(TCustomApplication)
protected
procedure DoRun; override;
public
end;
{
TMyApplication }
procedure
TMyApplication.DoRun;
var
Matrice: array[0..4,0..3] of integer;
i,j,
contatore: integer;
begin
{
add your program here }
contatore:=0;
for
i:=0 to 4 do
begin
for j:=0 to 3 do
begin
Matrice[i,j]:=contatore;
contatore:=contatore+1;
end;
end;
for
i:=0 to 4 do
begin
write('|');
for j:=0 to 3 do
begin
if (Matrice[i,j]<=9) then
begin
write('0',Matrice[i,j],'|');
end
else
write(Matrice[i,j],'|');
end;
writeln();
end;
//
stop program loop
Terminate;
end;
var
Application: TMyApplication;
{$IFDEF
WINDOWS}{$R project1.rc}{$ENDIF}
begin
Application:=TMyApplication.Create(nil);
Application.Title:='My Application';
Application.Run;
Application.Free;
end.
Se provate a compilare e ad eseguire il codice appena
scritto vedrete il risultato del vostro lavoro.
Esattamente come per i vettori anche le matrici possono
essere statiche o dinamiche, quelle appena dichiarate sono statiche,
ora vediamo le dinamiche. Sostanzialmente cambia in fase di
dichiarazione della variabile, ipotizziamo di voler rifare l'esempio
di poco fa sulla matrice statica con una dinamica la dichiarazione
della variabile di nome matrice verrebbe così modificata: Matrice:
array of array of integer;. Dopodichè dobbiamo definire
quanto è grossa la matrice, ma lo facciamo nella fase esecutiva in
questa maniera SetLength(Matrice,5,4).
Insomma se dovessimo riscrivere il programma con una matrice dinamica
il codice sarebbe il seguente:
program
project1;
{$mode
objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes, SysUtils, CustApp
{
you can add units after this };
type
{
TMyApplication }
TMyApplication = class(TCustomApplication)
protected
procedure DoRun; override;
public
end;
{
TMyApplication }
procedure
TMyApplication.DoRun;
var
Matrice: array of array of integer;
i,j,
contatore: integer;
begin
{
add your program here }
SetLength(Matrice,5,4);
contatore:=0;
for
i:=0 to 4 do
begin
for j:=0 to 3 do
begin
Matrice[i,j]:=contatore;
contatore:=contatore+1;
end;
end;
for
i:=0 to 4 do
begin
write('|');
for j:=0 to 3 do
begin
if (Matrice[i,j]<=9) then
begin
write('0',Matrice[i,j],'|');
end
else
write(Matrice[i,j],'|');
end;
writeln();
end;
//
stop program loop
Terminate;
end;
var
Application: TMyApplication;
{$IFDEF
WINDOWS}{$R project1.rc}{$ENDIF}
begin
Application:=TMyApplication.Create(nil);
Application.Title:='My Application';
Application.Run;
Application.Free;
end.
Provate a compilare e ad eseguire il programma e capirete cosa abbiamo/avete fatto.
Written by xinyiman Ottobre 19, 2011, 09:11:00 am23555 ViewsRating: 0 (0 Rates)Print
Fino ad adesso abbiamo visto dei tipi di dati semplici,
delle variabili mono-valore, infatti in base alle conoscenze fino a
qui acquisite se dovessimo immettere dieci valori numerici e
mantenerli in memoria avremmo dovuto dichiarare 10 variabili diverse,
ad esempio variabile1, variabile2, fino a variabile10.
Con i vettori o array questo problema è facilmente
superabile perché con una sola dichiarazione si possono memorizzare
più valori. Per capire meglio come ciò è possibile si può
immaginare la memoria come un insieme di tante celle, se dichiaro una
variabile come fino ad ora visto occupo una di queste celle, invece
se dichiari un vettore è come occupare da una a N celle consecutive.
Quindi ricapitolando se volessimo realizzare l'esempio di prima con
questa soluzione dovremmo dichiarare la variabile così variabile1:
Array[0..9] of integer. In questo modo abbiamo
metaforicamente ma neanche poi tanto dichiarato che 10 celle della
memoria si chiamano variabile1, e per poter leggere o cambiare il
valore di ogni singola cella usiamo un contatore da 0 a 9 ovvero
l'identificativo di ogni singola cella del valore.
Vediamo un esempio per capire meglio come utilizzare gli
array. Ovviamente apriamo una nuova "Console Application" e la
compiliamo in modo che sia tale e quale a questo codice qui sotto.
Bene quello che è stato aggiunto al codice iniziale
sono la dichiarazione di queste due variabili
variabile1: array[0..9] of integer;
i:
integer;
e queste righe di codice.
for
i:=0 to 9 do
begin
variabile1[i]:=i+10;
end;
for
i:=0 to 9 do
begin
writeln('Il valore della cella ', i,'
e'':',variabile1[i]);
end;
Come possiamo vedere la parte importante è
nell'esecuzione dei due cicli for. Il primo immette nelle celle del
vettore un valore che varia da 10 a 19 e nel secondo ciclo scrivo a
video questi 10 valori contenuti in variabile1. Un'altra cosa
importante da notare è che in fase di dichiarazione bisogna anche
dire al programma di che tipo è il vettore, nel nostro caso è
integer.
Bene quello che fino ad ora si è detto sui vettori si
può classificare come "vettori statici", ora vedremo anche
quelli dinamici. Si differenziano uno dall'altro dalla mancata
dichiarazione della lunghezza del vettore. Un vettore statico infatti
si dichiara così: nomevariabile: array[lunghezza] of
tipodivariabile; mentre un vettore dinamico si dichiara
così: nomevariabile: array of tipodivariabile;.
Vediamo ora un esempio per capire come si usano. Dopo aver dichiarato
la seguente variabile così: Variabile1: array of
integer; bisogna inserire il codice sottostante nella fase
esecutiva del programma.
SetLength(Variabile1,6);
for
i:=0 to 5 do
begin
Variabile1[i]:=i;
end;
for
i:=0 to 5 do
begin
writeln('Valore 1: ',Variabile1[i]);
end;
La prima cosa che bisogna notare è la procedura
SetLength che serve a stabilire quanto è lungo il vettore, perché
nel caso di un vettore statico una volta stabilita la lunghezza del
vettore quello rimane per tutta l'esecuzione del programma, mentre
per i vettori dinamici la lunghezza del vettore può variare
resettandone la lunghezza. Per il resto è tutto uguale ai vettori
statici.
Questo blog non rappresenta una testata giornalistica poiché viene
aggiornato senza alcuna periodicità. Non può pertanto considerarsi un
prodotto editoriale ai sensi della legge n. 62/2001.
Questo sito utilizza cookie, anche di terze parti, per offriti servizi in linea con le tue preferenze. Chiudendo questo banner, scorrendo questa pagina, cliccando su un link o proseguendo la navigazione in altra maniera, acconsenti all’uso dei cookie.