Alcune volte abbiamo bisogno di gestire un numero sconosciuto di dati omogenei, per esempio l'utente inserisca gli alunni della classe, ma che sappiamo noi programmatori a priori di quanti saranno gli elementi che compongono la classe sono 20 o 30 ecc...? A questo problema Delphi ci viene in aiuto con l'allocazione dinamica della memoria che ci consente di allocare memoria a tempo di runtime, e per fare ciò faremo uso delle pile. Una pila è una struttura dati omogenea, sequenziale di tipo LIFO. Una struttura dati sequenziale dato che per conoscere un elemento dobbiamo scorrere la struttura fino alla sua posizione, quindi non vi è la possibilità di accedere direttamente al dato. E di tipo LIFO perché l'ultimo entrato è il primo a uscire*1 (Last Input First Output).

Per poter implementare la pila dobbiamo dichiarare il tipo link che sarà un puntatore a un record Item che sarà formato dai campi di interesso più un campo obbligatorio next di tipo link. I campi di interesso sono i campi per cui c'è l'interesse di creare la lista, nel nostro esempio sarà il nome e il cognome. Tutto questo in Delphi viene tradotto in:

link = ^Item;
Item = Record
	nome:string;
	cognome:string;
	next:link;
end;

Next è il campo di collegamento con il prossimo elemento della pila, dato che noi allochiamo spazio nella memoria centrale a tempo di runtime noi sapremo l'indirizzo del elemento al momento della sua allocazione poi dovremo salvarlo nel campo next del elemento precedente, altrimenti non avremo più la possibilità di accedere a quel elemento è ne tanto meno di sapere il suo indirizzo.

Al momento della creazione della pila non è necessario ma è doveroso inizializzarla al valore nil, questo valore indica che la pila non punta a niente, perché al momento della creazione dentro pila troviamo garbage (sporcizia). E doveroso perché al momento dello scorrimento dovremo cercare questo valore nil per sapere quando la pila finisce. Creare la pila è semplice andate nella sezione var e scrivete Pila:link; questo ci crea un puntatore link, nel metodo FormCreate della MainForm inizializzate la pila a nil ==> pila := nil; Per inserire un nuovo elemento nella pila dovremo far uso di un puntatore ausiliare di tipo link che io chiamerò Paus e di una funzione New(puntatore) che ci consente, al momento di runtime, di allocare lo spazio per il puntatore in memoria centrale. Una procedura che aggiunge un nuovo elemento alla pila seguendo il ragionamento degli alunni potrebbe essere il seguente:

Procedure InsElemento(nome:string;cogn:string;var Pila:link);
var paus:link;
begin
new(paus);
paus^.cognome:= cogn;
paus^.nome:= nome;
paus^.next := pila;
pila := paus;
end;

Con questo codice paus^.next prende l'indirizzo di pila e pila prende lìindirizzo di Paus. Una procedura per scorrere la pila potrebbe essere la seguente:

Procedure ScorriPila(pila:link);s
begin
while pila <> nil do begin		
	pila := pila^.next;
end;
end;

Questa procedura non fa niente se non scorrere la pila, ma potremmo prima di pila := pila^.next; aggiungere delle condizioni per esempio cancellare l'elemento se si ha una determinata condizione, o nel caso di inserimento ordinato nella pila verrà aggiunto un elemento in mezzo, infatti per la cancellazione, inserimento ordinato, visualizzazione di uno o tutti gli elementi si dovrà far uso del funzione di scorrimento, questo perché come ho detto in precedenza questa è una struttura dati di tipo sequenziale. Adesso vedremo la cancellazione di un elemento:

Procedure CancElemento(cogn:string; var Pila:link);
var fcanc:boolean;
patt:link;
pprec:link;
begin
patt:= pila;
fcanc:= false; //una flag che ci consente di sapere se ho cancellato l'elemento
pprec:=nil;

while ((not fcanc) and (patt <> nil)) do begin
	if patt^.cognome = cogn then begin
		fcanc := true;
		if pprec = nil then 
			pila := patt^.next
		else 
			pprec^.next := patt^.next;

 		dispose(patt);
	end
	else begin
		pprec:= patt;
		patt:= patt^.next;
	end; 
end;
end;

Questa procedura cerca all'interno della pila un elemento che contenga dentro il campo cognome il valore cogn che gli passiamo alla stessa per costante, ovviamente qui potremo complicarci e aggiungere anche il nome di modo che se ci fossero due con lo stesso cognome la procedura cancelli solamente quello indicato anche dal nome, in questo caso la procedura cancella il primo elemento che rispetta la condizione. Con la funzione Dispose(puntatore) liberiamo lo spazio in memoria occupato dal puntatore, se noi non mettiamo la funzione dispose lo spazio rimarrebbe comunque utilizzato nella memoria centrale fino al riavvio del computer quando vengono persi tutti i dati nella memoria centrale.Come ultimo esempio farò l'inserimento ordinato dato che la visualizzazione del'interra pila suppongo che sia banale arrivati a questo punto.

Procedure InsOrdinato(Cogn:string;Nome:string; var Pila:link);
var paus,patt,pprec:link;
fins:boolean;
begin
fins:= false; //una flag che ci constente si sapere se ho inserito l'elemento
patt:= pila;
pprec := nil;
if patt <> nil then begin
while ((patt<> nil) and not fins) do begin
if patt^.cognome > cogn then begin
	new(paus);
	paus^.cognome:= cogn;
	paus^.nome:= nome;
	fins:=true;
	if pprec = nil then begin		
		paus^.next := pila;
		pila := paus;
	end
	else begin
		paus^.next := pprec^.next;
		pprec^.next := paus;
	end;
end;
end;
end 
else begin //se la pila è vuota inserisco normalemente
InsElemento(nome,cogn,pila);
end;
end;

Spero questo vi possa aiutare a capire meglio il funzionamento di una pila, e in genere di una struttura dati dinamica che a differenza di una struttura dati statica*2 noi non sapremo mai a priori quanti elementi compongono la struttura ma sappiamo che i dati sono omogenei e appunto l'omogeneità dei dati che ci permette di poter lavorare sulla struttura con tale sicurezza.

*1 il primo a uscire inteso come il primo a cui accediamo.

*2 Una struttura dati statica potrebbe essere un'array