Allocazione dinamica della memoria per il nodo nell'elenco collegato
Perché quando devo dichiarare un puntatore a un nodo (head) devo allocare anche memoria con malloc
o calloc
per esso? Ho visto che il codice che genera un elenco (non importato qui) funziona bene anche senza allocare memoria per esso e solo dichiarando node *head
.
typedef struct str_node{
int data;
struct str_node *next;
}node;
int main(){
node *head;
head = (node*) malloc(sizeof(node));
head = NULL;
E perché quando alloco memoria come sopra devo scrivere (node*)
? Non è già assegnato a un nodo struct poiché lo sto facendo in testa? Qual è esattamente il significato di quella riga di codice? Inoltre quando scrivo head = NULL
imposto l'indirizzo della testina del puntatore a NULL o cosa?
Risposte
Questo frammento di codice
node *head;
head = (node*) malloc(sizeof(node));
head = NULL;
produce una perdita di memoria.
All'inizio è node
stata allocata una memoria per un oggetto del tipo e il suo indirizzo è stato assegnato al puntatorehead
head = (node*) malloc(sizeof(node));
e subito dopo il valore del puntatore è stato sovrascritto.
head = NULL;
Di conseguenza, l'indirizzo della memoria allocata è andato perso e la memoria allocata non può essere liberata.
Lo snippet di codice non ha alcun senso. Basterà scrivere
node *head = NULL;
In questo caso avrai inizialmente un elenco vuoto.
E perché quando alloco la memoria come sopra devo scrivere (nodo *)?
La funzione malloc
restituisce un puntatore del tipo void *
. Un puntatore del tipo void *
può essere assegnato a un puntatore di qualsiasi altro tipo di oggetto. Quindi in C il casting è ridondante.
In C ++ devi esplicitamente lanciare un puntatore del tipo void *
al tipo del puntatore all'oggetto a cui void *
è assegnato il puntatore del tipo .
Inoltre quando scrivo head = NULL imposto l'indirizzo del puntatore head a NULL o cosa?
Non hai impostato l'indirizzo del puntatore stesso. Il puntatore è stato assegnato dal compilatore e ha la durata di archiviazione automatica. Imposta il valore della variabile head
che ha il tipo node *
su NULL.
In C, i puntatori sono valori, proprio come gli interi. Quando scrivi:
int a;
a = 3;
si memorizza il valore 3 nella variabile a
.
Quando scrivi:
int* p;
p = NULL;
si memorizza il valore NULL
nella variabile p
. Non c'è niente di speciale nei puntatori. L'assegnazione non dipende in alcun modo dal valore di p
, cioè da cosa potrebbe o non potrebbe indicare. (In questo caso, non punta a nulla, ma è irrilevante.)
malloc
restituisce un puntatore a una regione di memoria, che come discusso sopra è un valore. Il puntatore non ha metadati intrinseci; malloc
non richiede alcuna informazione oltre la dimensione della regione di memoria. In particolare, non sa (o si preoccupa) per cosa verrà utilizzata la regione di memoria. Una volta prodotto quel valore, puoi gestirlo come meglio credi, ad esempio:
int* p;
p = malloc(sizeof *p);
Poiché p
è dichiarato come un puntatore a un int
, ci si aspetta che la memoria puntata da p
possa contenere un int
. (Non ancora, ma potrebbe.) Ma puoi passare il puntatore (come valore) senza che abbia alcun effetto sull'intero (se presente) memorizzato nella memoria a cui punta. Ad esempio, dopo
int* q = p;
q
e p
punta alla stessa memoria.
Se trovi qualcosa di confuso, è probabilmente perché ti aspetti che un puntatore sia qualcosa di diverso da un semplice valore. Tuttavia, sono valori semplici e hai bisogno di un modello mentale basato su quella semplice realtà.