Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
struct Elemento {
int valore;
struct Elemento* prossimo;
};
typedef struct Elemento* Lista;
Nei nostri tipi strutturati noi abbiamo finora preso in considerazione il caso dei tipi scalari che quindi hanno
un tipo , un valore e un attributo, poi abbiamo considerato i dati strutturati che sono dati che hanno più
valori: il primo caso studiato sono gli array che hanno un solo tipo, un solo attributo e tanti valori(in
quantità prefissata)abbiamo detto che quando abbiamo un’array di dimensione N noi possiamo gestire
sia una sequenza di N dati, sia sequenze più piccole ma non più grandi.
Poi abbiamo detto che se i dati non sono omogenei ma sono eterogenei (di tipi diversi) facciamo uso delle
struct, però la quantità di dati in una struct è prefissata poiché definita proprio al momento della
dichiarazione . Il caso che ci manca è quello di dati omogenei o eterogenei in quantità variabile(ovvero
modificabile), inoltre dobbiamo fare in modo di occupare istante per istante il quantitativo giusto di
memoria questa soluzione è data dalle liste
Una lista è una sequenza di dati. La lunghezza della lista non è nota all'inizio e può variare liberamente
durante l'esecuzione del programma.
Le liste ci forniscono una soluzione per la riduzione di spreco di memoria nei casi in cui noi non sappiamo
quanto spazio ci servirà in memoria . La lista , siccome non sappiamo quanto essa sarà lunga all’inizio e al
contempo non vogliamo sprecare spazio in memoria, allora può essere inizializzata a NULL che sta ad
indicare proprio che la lista è vuota(viene solo memorizzata solo dove inizia anche se non inizia davvero
infatti per questo ci mettiamo NULL). Poi ammettiamo di memorizzare un numero nella listaandiamo alla
casella (142) (indirizzo) e memorizziamo il numero 1ora succede che per sapere che la nostra lista
comincia alla casella (142) dobbiamo ricordarci dove comincia. Quindi ci prenderemo una variabile, che
memorizziamo nella casella in memoria (1000), che si ricorda dove comincia la nostra lista(nel nostro caso
nella casella 1000 metteremo (memorizzeremo) 142 che ci dice che la nostra lista ha un elemento nella
casella 142).
ADESSO COME FACCIAMO A DIRE CHE LA NOSTRA LISTA POSSIEDE UN SOLO ELEMENTO?
Purtroppo alla casella 1000 non ritroviamo questa informazione poiché la casella 1000 ci dice solo
l’indirizzo di dove sta il primo elemento della lista. Se non ci sono altri elementi allora dobbiamo mettere da
qualche parte l’indicazione che non ci sono altri elementiquesta indicazione viene messa nella casella
(144) Perché non nella 1002? Perchè il nostra lista si trova nell’heap e non nello stackinoltre se
l’avessimo messa nello stack significava che quando noi andavamo a dichiarare un puntatore che sta in
1000 dovevamo dire che non volevamo un puntatore ma due puntatori perché potrebbe avere un
elemento, solo se la nostra lista aveva 100 elementi noi avremmo dovuto dichiarare 100 puntatori quindi
significa che avremmo dovuto dichiarare tanti puntatori quanti sono gli elementi della lista quindi
dovevamo sapere in anticipo quanti puntatori avevamo bisogno(e di conseguenza quanto è lunga una
listaarray)nel modo adottato invece stiamo andando dinamicamente a metterci gli elementi
Lista vuota
struct Elemento {
int valore;
struct Elemento* prossimo;
}
Per definire una lista noi abbiamo bisogno di un puntatore che rappresenta sostanzialmente un indirizzo del
primo elemento della listase la nostra lista è vuota per indicare questo aspetto il mdo
struct Elemento* lista = NULL (in questo modo il compilatore crea una variabile nello stack che si chiama
lista che è l’indirizzo di una struct Elemento e che all’inizio vale NULL)
(1000) NULL
La variabile nella casella 1000 ci dice che la lista inizia a NULL, cioè non inizia proprio (è vuota)
COME QUESTO CONCETTO CHE ABBIAMO APPENA NARRATO PUO’ DIVENTARE UN ALGORITMO? Iniziamo col
dire che un per elemento di una lista non dobbiamo solo dire il valore ma dobbiamo anche indicare la posizione del
successivo quindi scriveremo
struct Elemento {
int valore; //possiamo anche mettere un qualsiasi altro tipo
struct Elemento* prossimo; //In questo modo mettiamo l’indirizzo del prossimo elemento che sarà di
tipo struct Elemento* prossimo; che sta a significare che un elemento è fatto di un valore, come quelli
evidenziati in viola e poi è fatto di variabili di tipo indirizzo evidenziati in marrone che ci dicono la
prossima coppia valore-indirizzo
}
Quindi una struct Elemento è una coppia che comprende sia il valore che il puntatore e questo puntatore è
per l’appunto un puntatore ad una struttura analoga a quella che stiamo definendoma questa cosa non
è vietata? Non è vietato esprimere una struttura in funzione di se stessa? Questa cosa infatti è vietata ma
in tal caso non stiamo definendo una struttura in funzione di se stessa ma di una struttura in funzione di un
intero e di un puntatore ad struttura
Ciò non è vietato perché al compilatore interessa quanto spazio occupa la struttura in memoria e come
deve rappresentare i suoi valori
struct Elemento* occupa in memoria lo spazio necessario per un indirizzo (una macchina a 64 bit sarà
8byte), indipendentemente dal fatto che sia un puntatore proprio a struct Elemento ed è rappresentato
come tutti gli indirizzi come un intero senza segno
Con questa struttura noi possiamo definire tutta lista perché manca l’indirizzo del primo elemento che si
trova nello stack