Los operadores de desreferencia * y de toma de dirección & son algunas de las herramientas fundamentales para trabajar con memoria en C. Permiten un control directo de los datos en memoria, lo que ha hecho de C un lenguaje popular para la programación de sistemas.
Historia de la cuestión:
Desde la aparición del lenguaje C (en la década de 1970) su filosofía ha estado estrechamente relacionada con la gestión de memoria a bajo nivel. Los operadores * y & implementan una técnica de direccionamiento indirecto, utilizada a nivel de procesador, que permite trabajar con punteros, asignar memoria dinámicamente y crear estructuras de datos eficientes.
Problema: Los errores en el uso de estos operadores llevan a numerosos fallos: fugas de memoria, corrupción de datos, fallos de segmentación. El compilador no siempre sinaliza explícitamente estos errores, especialmente si los tipos de punteros coinciden en tamaño, pero difieren en contenido.
Solución: Debemos prestar atención al tipo de puntero, seguir el ciclo de vida de la memoria asignada, realizar la inicialización y liberación correcta, así como verificar la corrección de las operaciones de desreferencia y de las direcciones utilizadas.
Ejemplo de código:
int x = 10; int *p = &x; // toma de dirección int y = *p; // desreferencia (obtenemos el valor en la dirección) // Trabajo con un puntero a un array int arr[3] = {1,2,3}; int *pa = arr; printf("%d", *(pa+1)); // segundo elemento del array
Características clave:
¿Se puede tomar la dirección de una variable temporal, por ejemplo: &(x + y)?
No, no se puede tomar la dirección de una expresión, porque el resultado de la expresión no es un objeto de memoria. La dirección solo se puede tomar de una variable, array o estructura.
Ejemplo de código:
int z = 5; int p = &(z + 1); // Error de compilación
¿En qué se diferencia la desreferencia de un puntero void?
Un puntero de tipo void * no se puede desreferenciar directamente, hasta que se le convierta a un tipo concreto. Este es un puntero universal, pero las operaciones de desreferencia son independientes de tipo solo después de una conversión explícita:
void *pv = &x; int value = *(int*)pv; // OK
¿Se puede desreferenciar un puntero nulo (NULL)?
No, esto lleva a un comportamiento indefinido: corrupción de memoria o término anómalo. Siempre verifica el puntero antes de desreferenciarlo:
int *ptr = NULL; if (ptr) { *ptr = 10; // Nunca se ejecutará }
Un desarrollador toma la dirección de una variable local en la función, la devuelve y luego desreferencia el puntero en el código llamador.
Pros:
Contras:
Se utiliza la asignación dinámica de memoria para una variable, la dirección se devuelve al código llamador y finalmente se libera a través de free.
Pros:
Contras: