Asignación de memoria dinámica para el nodo en la lista vinculada
¿Por qué cuando tengo que declarar un puntero a un nodo (cabeza) también tengo que asignar memoria con malloc
o calloc
para él? Vi que el código que genera una lista (no importado aquí) funciona bien también sin asignarle memoria y simplemente declarando node *head
.
typedef struct str_node{
int data;
struct str_node *next;
}node;
int main(){
node *head;
head = (node*) malloc(sizeof(node));
head = NULL;
¿Y por qué cuando asigno memoria como arriba tengo que escribir (node*)
? ¿No está ya asignado a un nodo de estructura ya que lo estoy haciendo en la cabeza? ¿Cuál es exactamente el significado de esa línea de código? Además, cuando escribo, head = NULL
¿configuro la dirección de la cabeza del puntero en NULL o qué?
Respuestas
Este fragmento de código
node *head;
head = (node*) malloc(sizeof(node));
head = NULL;
produce una pérdida de memoria.
Al principio node
se asignó una memoria para un objeto del tipo y su dirección se asignó al punterohead
head = (node*) malloc(sizeof(node));
e inmediatamente se sobrescribió el valor del puntero.
head = NULL;
Como resultado, la dirección de la memoria asignada se perdió y la memoria asignada no se puede liberar.
El fragmento de código no tiene ningún sentido. Bastará con escribir
node *head = NULL;
En este caso, inicialmente tendrá una lista vacía.
¿Y por qué cuando asigno memoria como arriba tengo que escribir (nodo *)?
La función malloc
devuelve un puntero del tipo void *
. Se void *
puede asignar un puntero de este tipo a un puntero de cualquier otro tipo de objeto. Entonces en C el casting es redundante.
En C ++ tienes que lanzar explícitamente un puntero del tipo void *
al tipo del puntero de objeto al que void *
está asignado el puntero del tipo .
Además, cuando escribo head = NULL, ¿configuro la dirección de la cabeza del puntero en NULL o qué?
No estableció la dirección del puntero en sí. El puntero fue asignado por el compilador y tiene la duración de almacenamiento automático. Establece el valor de la variable head
que tiene el tipo node *
en NULL.
En C, los punteros son valores, al igual que los números enteros. Cuando escribes:
int a;
a = 3;
almacena el valor 3 en la variable a
.
Cuando escribes:
int* p;
p = NULL;
almacena el valor NULL
en la variable p
. Los punteros no tienen nada de especial. La asignación no depende en modo alguno del valor de p
, es decir, de lo que podría o no señalar. (En este caso, no apunta a nada, pero eso es irrelevante).
malloc
devuelve un puntero a una región de memoria, que como se discutió anteriormente es un valor. El puntero no tiene metadatos intrínsecos; malloc
no requiere ninguna información más allá del tamaño de la región de memoria. En particular, no sabe (ni le importa) para qué se utilizará la región de memoria. Una vez que se produce ese valor, puede manejarlo como mejor le parezca, por ejemplo:
int* p;
p = malloc(sizeof *p);
Dado que p
se declara como un puntero a an int
, se espera que la memoria apuntada por p
pueda contener un int
. (Aún no lo hace, pero podría hacerlo). Pero puede pasar el puntero (como un valor) sin que tenga ningún efecto sobre el entero (si lo hay) almacenado en la memoria apuntada. Por ejemplo, después
int* q = p;
q
y p
apuntar a la misma memoria.
Si encuentra algo de esto confuso, probablemente sea porque espera que un puntero sea algo más que un valor simple. Sin embargo, son valores simples y necesitas un modelo mental que se base en esa simple realidad.