Written by xinyiman Novembre 28, 2011, 04:33:00 pm27145 ViewsRating: (1 Rates)Print
Con le classi si introduce anche il discorso di programmazione orientata agli oggetti (OOP), in quanto il Free Pascal (quindi di rimando anche Lazarus) è considerato tale. Per capire cosa si intende per programmazione orientata agli oggetti ci viene in aiuto Wikipedia ...
Written by xinyiman Ottobre 25, 2011, 12:43:00 pm24175 ViewsRating: (1 Rates)Print
Premessa: molto semplicemente si può immaginare la
memoria come un insieme di celle di vari tipi, che rappresentano le
variabili, ed ognuna di queste celle per essere raggiunta deve avere
un indirizzo che rappresenta la sua posizione all'interno della
memoria. Una volta capito questo concetto si può capire che un
puntatore è semplicemente una variabile che contiene l'indirizzo di
un altra variabile. Questo rende i puntatori uno strumento molto
potente, ma anche molto pericoloso, perché se si commettono errori è
possibile modificare aree di memoria che non volevamo toccare. Per
dichiarare un puntatore è buona norma farlo tramite il costrutto
type che abbiamo già visto precedentemente (in un altro articolo). Facciamo un esempio:
type
PuntatoreAdIntero=^integer;
var
Puntatore:
PuntatoreAdIntero;
oppure si può banalmene scrivere
var
Puntatore:^integer;
Nel primo caso ho definito un tipo di variabile con nome
PuntatoreAdIntero che corrisponde a un puntatore ad integer, poi ho
dichiarato una variabile di nome Puntatore e del tipo appena
dichiarato PuntatoreAdIntero. Nel secondo caso ho dichiarato una
variabile di tipo puntatore ad integer. Quindi come si può dedurre
da i due modi di dichiarare un puntatore per dire che si tratta
effettivamente di un puntatore bisogna usare il simbolo ^ prima del
tipo della variabile da puntare.
Ora che abbiamo dichiarato il puntatore vediamo un po di
codice per capire meglio come utilizzare un puntatore.
{
Dichiaro il tipo di dato PuntatoreAdIntero }
type
PuntatoreAdIntero=^integer;
.
.
.
{
Dichiaro le variabili che mi servono }
var
MiaVariabile: integer;
MioPuntatore: PuntatoreAdIntero;
.
.
.
{
Codice vero e proprio che andremo ad analizzare }
MiaVariabile:=60; { Inizializzo la variabile }
MioPuntatore:=@MiaVariabile; { Il puntatore ora lo
punto alla variabile }
writeln('Il valore puntato è: ', MioPuntatore^); {
Stampo il valore puntato da puntatore }
MiaVariabile:=50;
writeln('Il valore puntato è: ', MioPuntatore^); {
Stampo il valore puntato da puntatore }
Per prima cosa inizializzo la variabile di nome
MiaVariabile a 60, dopodichè dico a MioPuntatore di puntare
all'indirizzo di MiaVariabile, dopodiché stampo a video il contenuto
della variabile puntata, il risultato sarà 60. In seconda battuta
modifico il contenuto di MiaVariabile e ristampo nuovamente il dato
contenuto nella variabile puntata, il risultato sarà 50.
I puntatori possono essere utilizzati su qualsiasi tipo
di variabile, anche sulle variabili realizzate da noi attraverso il
type.
Ad esempio se si realizzasse il tipo di dato animale in
questo modo
type
Animale=record
Anni:
integer;
Tipo:
string;
end;
sarebbe possibile dichiarare un puntatore a tale
variabile e le variabili Var1 e Var2 tramite questo codice
var
MioPuntatore:
^Animale;
Var1:
Animale;
Var2:
Animale;
Poi valorizzerei le due variabili
Var1.Anni:=5;
Var1.Tipo:='cane';
Var2.Anni:=6;
Var2.Tipo:='gatto';
E stamperei a video tramite il puntatore i dati delle
due variabili:
Una volta compilato ed eseguito questo programma il
risultato ottenuto sarà:
Ho un cane di anni: 5
Ho un gatto di anni: 6
Non bisogna lasciarsi trarre in inganno dagli esempi
visti fino ad ora, i puntatori sono molto utili e flessibili come
strumenti, soprattutto se si affrontano tematiche come liste ed
alberi.
Written by xinyiman Ottobre 24, 2011, 02:13:00 pm23801 ViewsRating: 0 (0 Rates)Print
Per funzioni/procedure ricorsive si intendono
funzioni/procedure che al loro interno richiamano loro stesse. Questo
tipo di logica che viene chiamata logica ricorsiva permette un codice
più pulito e più facilmente leggibile. Prendiamo in considerazione
l'esempio principe per capire la ricorsione: il fattoriale.
{La
funzione che permette la fatturazione di un numero}
function
Fatt(numero: integer): longint;
begin
if
numero=1 then
Fatt:=numero
else
Fatt:=(numero)*(Fatt(numero-1));
end;
Come si può vedere la funzione in questione si chiama
Fatt e prende come parametro un numero intero. Ma se andiamo ad
analizzare il codice possiamo trovare la seguente riga come anomala:
Fatt:=(numero)*(Fatt(numero-1)); perché
ritorniamo come valore la moltiplicazione del parametro per il
risultato di una chiamata a se stessa. Cioè all'interno della
funzione Fatt esiste una chiamata alla funzione Fatt. Questo modo di
usare le funzioni/procedure è molto pulito e facile da interpretare,
ma ad esempio rispetto ad un ciclo all'interno di una funzione occupa
più spazio in memoria. Per creare delle buone funzioni/procedure
ricorsive è necessario che le stesse non entrino in un ciclo
infinito, per ciclo infinito si intende che non si verifica mai la
condizione per uscire dal ciclo. Per esempio immaginiamo di aver
dichiarato come variabile globale, quindi visibile anche all'interno
di funzioni, un vettore lungo 50 celle di nome esempioric, e vogliamo
sapere quante celle sono valorizzate con il numero 20; dovremmo
scrivere la seguente funzione non ricorsiva:
function
Conteggia20(): integer;
var
i:
integer;
cont:
integer;
begin
cont:=0;
for
i:=0 to 49 do
begin
if
(esempioric[i]=20) then
begin
cont:=cont+1;
end;
end;
Conteggia20:=cont;
end;
Così facendo abbiamo una funzione che cicla fino a fine
vettore e ogni qual volta incontra un valore 20 all'interno del
vettore incrementa di uno la variabile cont, che corrisponde al
risultato che vogliamo ottenere. Ma questo non è l'unico modo per
scrivere questa funzione, perché con la ricorsione possiamo
ottenere:
function
Conteggia20Ric(indice: integer): integer;
begin
if
indice>=50 then
Conteggia20Ric:=0
else
begin
if (esempioric[indice]=20) then
Conteggia20Ric:=1+Conteggia20Ric(indice+1)
else
Conteggia20Ric:=Conteggia20Ric(indice+1);
end;
end;
Come si può evincere dall'esempio non esiste un ciclo
all'interno della funzione stessa, ma semplicemente la funzione
analizza il valore della prima cella e poi se non si trova all'ultima
cella controlla tramite una chiamata a se stessa (e qui entra in
gioco la ricorsione) il valore della cella successiva. C'è da notare
anche una altra cosa che la seconda funzione scritta (quella
ricorsiva) ha un parametro, che corrisponde alla cella del vettore
che deve analizzare, quindi quando dal programma principale
richiameremo la funzione bisogna passargli come parametro il valore
0.
Written by xinyiman Ottobre 24, 2011, 08:47:00 am24521 ViewsRating: 0 (0 Rates)Print
Per libreria si intende una raccolta di procedure e
funzioni. L'uso delle librerie è molto frequente perché permette di
suddividere la scrittura del codice da uno a più file, in modo da
rendere il codice più leggibile, meglio strutturato e
riutilizzabile. Per realizzare una nuova libreria basta andare su
FILE → NUOVA UNIT dopodichè comparirà questo codice:
unit
Unit2;
{$mode
objfpc}{$H+}
interface
uses
Classes, SysUtils;
implementation
end.
Dove unit è una parola riservata che identifica
l'inizio della nostra libreria e Unit2 rappresenta il nome della
nostra libreria. Nel nostro caso dobbiamo cambiare Unit2 con il nome
che vogliamo dare alla nostra ipotetica libreria, ipotizziamo
FunzioniRiciclabili, si noti che quando si va a salvare la libreria
bisogna dargli lo stesso nome della unit.
Dopodichè esiste un commento che ignoriamo per andare a
vedere la parola riservata interface, dove all'interno di questo
segmento di codice possiamo dichiarare costanti, variabili, funzioni
e procedure visibili dall'esterno della libreria stessa.
Segue poi la parola riservata uses dove all'interno di
questo segmento di codice dobbiamo inserire le librerie che ci
servono per poter compilare le nostre funzioni e procedure.
Infine esiste il blocco implementation end. che
contengono l'implementazione del codice, ovvero dove dobbiamo
scrivere le procedure e le funzioni per intero.
Vediamo ora un esempio pratico, questa librerie che
segue contiene una sola funzione di nome
ContieneCaratteriNonConcessi.
unit
FunzioniRiciclabili;
{$mode
objfpc}{$H+}
interface
function
ContieneCaratteriNonConcessi(MiaStringa: string): integer;
implementation
uses
Crt;
{Mi dice se nella stringa ci sono caratteri
tipo il punto e virgola che non sono ammessi}
function
ContieneCaratteriNonConcessi(MiaStringa: string): integer;
var
i: integer;
lung: integer;
Esci: integer;
begin
lung:=Length(MiaStringa);
i:=1;
Esci:=0;
while ((i<lung) AND (Esci=0)) do
begin
if MiaStringa[i]=';' then
begin
Esci:=1;
end;
i:=i+1;
end;
ContieneCaratteriNonConcessi:=Esci;
end;
end.
Come si può evincere da questo esempio il nome della
libreria è FunzioniRiciclabili e l'unica funzione contenuta al suo
interno lavora sulle stringhe, ovvero in base ad una stringa passata
per parametro che se non contiene il carattere ; allora restituisce
il valore numerico 0, altrimenti restituirebbe 1.
Ora che abbiamo scritto la nostra libreria è importante
riuscire a poterla usare nelle altre unit che compongono il
programma. Per fare ciò bisogna immettere nella sezione uses della
unit in cui vogliamo usare la funzione appena scritta il nome della
libreria appena creata, nel nostro caso sarebbe FunzioniRiciclabili,
e ora possiamo usare la funzione ContieneCaratteriNonConcessi
liberamente.
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.