Tipos de Punteros en el Lenguaje C

En el lenguaje C, los punteros son una herramienta fundamental que permite manipular directamente las direcciones de memoria. Para comprender su utilidad, es necesario analizar primero cómo funciona el paso por valor.

Considere el siguiente escenario donde se copia el valor de una variable a otra:

#include <stdio.h>

int main() {
    int valorA = 90;
    int valorB = valorA;

    printf("%d %d\n", valorA, valorB); // Resultado: 90 90

    // %p muestra la dirección en hexadecimal, & obtiene la dirección de memoria
    printf("%p %p\n", (void*)&valorA, (void*)&valorB); // Direcciones diferentes

    return 0;
}

Cuando se ejecuta int valorA = 90, el sistema reserva un espacio en memoria (por ejemplo, en la dirección 0x61FF1C) y almacena el valor 90. Luego, int valorB = valorA asigna una nueva dirección de memoria distinta (como 0x61FF18) y copia el valor 90 en ella.

Esta técnica se conoce como paso por valor. Cada variable ocupa su propia área de memoria, por lo que modificar valorA no afecta a valorB. Sin embargo, cuando se pasa un puntero a una función, los cambios realizados a través de dicho puntero afectan directamente el contenido almacenado en la dirección de memoria original.

En C, todo tipo de dato posee su correspondiente tipo de puntero. Veamos un ejemplo:

#include <stdio.h>

int main() {
    int dato = 90;

    // Un puntero a int solo puede recibir la dirección de una variable de tipo int
    // El operador & obtiene la dirección de memoria de 'dato'
    int* referencia = &dato;

    // Las direcciones de ambas variables son diferentes
    printf("%p %p\n", (void*)&dato, (void*)&referencia);

    // El contenido del puntero es la dirección de 'dato'
    printf("%p\n", (void*)referencia);

    // El operador * permite acceder al valor almacenado en la dirección apuntada
    printf("%d\n", *referencia); // Imprime: 90

    return 0;
}

El puntero referencia almacena como valor la dirección de memoria donde se encuentra dato. Al modificar dato, el cambio es visible al desreferenciar el puntero, ya que ambos apuntan a la misma celda de memoria:

dato = 80;
printf("%d\n", *referencia); // Imprime: 80

Operaciones Aritméticas con Punteros

Los punteros admiten operaciones de incremento y decremento. Dado que los elementos de un arreglo se almacenan de forma contigua en memoria, estas operaciones resultan especialmente útiles para recorrerlos.

int colección[] = {10, 100, 200};
int* puntero = colección; // Apunta al primer elemento del arreglo

Cuando se aplica el operador ++ sobre un puntero, su dirección avanza tantos bytes como ocupe el tipo de dato al que apunta. Por ejemplo, si puntero está en la dirección 0x1133 y el tipo int ocupa 4 bytes:

puntero++; // 0x1133 + 4 = 0x1137

Tras esta operación, el puntero señala al segundo elemento del arreglo. De manera análoga, el operador -- retrocede el puntero según el tamaño del tipo de dato correspondiente.

También es posible sumar o restar valores enteros a un puntero. Por ejemplo, puntero + 2 desplaza la dirección dos posiciones hacia adelante, considerando el tamaño del tipo base.

Consideraciones Adicionales

  • Punteros múltiples: Es posible crear punterso que apunten a otros punteros, permitiendo niveles de indirección adicionales.
  • Punteros como parámetros de funciones: Al recibir un puntero como argumento, la función puede modificar el contenido de la dirección original. Es responsabilidad del programador asegurar que el puntero recibido sea válido.
  • Retorno de punteros en funciones: Una función puede devolver un puntero, pero nunca debe retornar la dirección de una variable local, ya que dicha memoria se libera al finalizar la ejecución de la función.
  • Puntero nulo: Un puntero con valor NULL no apunta a ninguna dirección válida. Es buena práctica inicializar punteros con NULL y verificar su validez antes de utilizarlos para evitar errores de segmentación.

Etiquetas: C Punteros memoria aritmética de punteros Gestión de memoria

Publicado el 6-27 00:39