Modulo 07: Punteros en C

Idea central

Un puntero es una variable que guarda una direccion de memoria, no un valor directo. Esto permite que una funcion modifique variables del llamador, recorrer arrays de forma eficiente y construir estructuras de datos dinamicas. Sin punteros no hay paso por referencia, no hay arrays dinamicos, no hay C real.

Que aprendes

ConceptoPara que sirve
Operador & (direccion)Obtener la direccion de memoria de una variable
Operador * (desreferencia)Leer o escribir el valor en la direccion guardada
Declarar un punteroint *p; — p guarda direcciones de int
Pasar por referenciaQue una funcion modifique la variable del llamador
Relacion puntero-arrayEl nombre de un array ES un puntero a su primer elemento
Aritmetica de punterosp+1 avanza un elemento (no un byte) del tipo apuntado

Explicacion

Categoria 1 — Direccion y desreferencia

Patron conceptual: cada variable vive en una celda de memoria con una direccion unica. &x da esa direccion; *p accede al contenido de la celda apuntada.

int x = 42;
int *p = &x;   // p guarda la direccion de x
printf("%p\n", (void *)p);  // imprime la direccion (ej: 0x7ffd...)
printf("%d\n", *p);         // imprime 42 (valor en esa direccion)
*p = 100;                   // modifica x a traves del puntero
printf("%d\n", x);          // imprime 100

Regla de lectura: lee int *p como “p es un puntero a int”.


Categoria 2 — Paso por referencia

Patron: para que una funcion modifique una variable del llamador, recibe su direccion (int *) y usa * para acceder.

void doblar(int *n) {
    *n = *n * 2;  // modifica la variable original
}
 
int main(void) {
    int x = 5;
    doblar(&x);   // pasas la direccion, no el valor
    printf("%d\n", x);  // 10
    return 0;
}

Sin & en la llamada y sin * en la funcion: la funcion recibe una copia y el original no cambia.


Categoria 3 — Relacion puntero-array

Patron: arr (sin corchetes) es equivalente a &arr[0]. Se puede recorrer un array con aritmetica de punteros.

int arr[4] = {10, 20, 30, 40};
int *p = arr;          // equivale a &arr[0]
printf("%d\n", *p);    // 10
printf("%d\n", *(p+2)); // 30
p++;                   // avanza al siguiente int (4 bytes)
printf("%d\n", *p);    // 20

p + i es la direccion del elemento i-esimo; *(p+i) equivale a arr[i].


Worked example

Problema: escribir una funcion swap que intercambie dos enteros, y otra rango que devuelva el maximo y el minimo de un array por referencia. Mostrar ambos resultados.

#include <stdio.h>
 
/* Intercambia los valores de a y b a traves de punteros */
void swap(int *a, int *b) {
    int tmp = *a;
    *a = *b;
    *b = tmp;
}
 
/*
 * Recorre el array con un puntero.
 * Escribe el maximo en *pmax y el minimo en *pmin.
 */
void rango(int *arr, int n, int *pmax, int *pmin) {
    *pmax = arr[0];
    *pmin = arr[0];
    int *p = arr + 1;          // puntero al segundo elemento
    int *fin = arr + n;        // puntero "pasado el ultimo"
    while (p < fin) {
        if (*p > *pmax) *pmax = *p;
        if (*p < *pmin) *pmin = *p;
        p++;                   // avanza un int hacia adelante
    }
}
 
int main(void) {
    // --- Paso 1: swap ---
    int x = 3, y = 9;
    printf("Antes:  x=%d  y=%d\n", x, y);
    swap(&x, &y);
    printf("Despues: x=%d  y=%d\n", x, y);
 
    // --- Paso 2: rango ---
    int datos[6] = {4, 1, 9, 2, 7, 3};
    int maximo, minimo;
    rango(datos, 6, &maximo, &minimo);
    printf("Max=%d  Min=%d\n", maximo, minimo);
 
    return 0;
}

Traza mental paso a paso:

  1. swap(&x, &y)a apunta a x, b apunta a.
  2. tmp = *a guarda 3. *a = *b pone 9 en x. *b = tmp pone 3 en.
  3. rango recibe el array como puntero; p empieza en arr+1 = segundo elemento.
  4. El bucle compara *p contra *pmax y *pmin, actualizando cuando toca.
  5. Al salir, maximo y minimo tienen los valores correctos porque se pasaron sus direcciones.

Salida esperada:

Antes:  x=3  y=9
Despues: x=9  y=3
Max=9  Min=1

Errores tipicos en C

#ErrorEjemplo incorrectoPor que falla
1Puntero sin inicializarint *p; *p = 5;p contiene basura; escribe en memoria aleatoria → comportamiento indefinido
2Olvidar & al pasar por referenciadoblar(x) en vez de doblar(&x)La funcion recibe copia; el original no cambia
3Olvidar * al desreferenciar*p = p + 1 en vez de *p = *p + 1Suma 1 a la direccion, no al valor; probablemente warning de tipos
4Aritmetica fuera del arrayp = arr + 10 con array de 5Puntero fuera de rango; leer *p es comportamiento indefinido
5Confundir p++ con (*p)++p++ cuando quieres incrementar el valorp++ avanza el puntero (cambia a que celda apunta); (*p)++ incrementa el valor guardado

Ejercicios

Practica lo de este módulo. Cada enlace abre el ejercicio con su enunciado, diagrama de flujo, explicación y el código listo para copiar.

Conexiones