Punteros a funciones en C: ejercicio resuelto con callbacks

Punteros a funciones en C: ejercicio resuelto paso a paso

Si buscas un ejercicio de punteros a funciones en C resuelto, aquí tienes los tres usos más comunes: llamada directa, tabla de funciones y callback en qsort.

Un puntero a función almacena la dirección de una función con una firma concreta. Permite elegir en tiempo de ejecución qué función invocar sin necesidad de switch o if-else.

Firma de un puntero a función

1
tipo_retorno (*nombre)(tipo_param1, tipo_param2, ...);

Por ejemplo, un puntero a función que recibe dos int y devuelve un int:

1
int (*operacion)(int, int);

Enunciado

  1. Define cuatro operaciones aritméticas básicas como funciones independientes.
  2. Llama a una de ellas a través de un puntero a función.
  3. Crea una tabla (array) de punteros a función para recorrer todas las operaciones.
  4. Usa un puntero a función como callback en qsort para ordenar un array de enteros de mayor a menor.

Solución en C

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <stdio.h>
#include <stdlib.h>

/* 1. Funciones aritméticas */
int sumar(int a, int b)    { return a + b; }
int restar(int a, int b)   { return a - b; }
int multiplicar(int a, int b) { return a * b; }
int dividir(int a, int b)  { return (b != 0) ? a / b : 0; }

/* 4. Comparador para qsort: orden descendente */
int comparar_desc(const void *p1, const void *p2) {
    int a = *(const int *)p1;
    int b = *(const int *)p2;
    return b - a;   /* b-a = descendente; a-b = ascendente */
}

int main(void) {
    int x = 12, y = 4;

    /* 2. Llamada a través de puntero */
    int (*op)(int, int) = sumar;
    printf("Puntero a sumar: %d + %d = %d\n", x, y, op(x, y));

    op = multiplicar;
    printf("Puntero a multiplicar: %d * %d = %d\n", x, y, op(x, y));

    /* 3. Tabla de punteros a función */
    int (*tabla[])(int, int) = { sumar, restar, multiplicar, dividir };
    const char *nombres[] = { "suma", "resta", "mult", "div" };

    printf("\nTabla de operaciones con x=%d, y=%d:\n", x, y);
    for (int i = 0; i < 4; i++) {
        printf("  %s -> %d\n", nombres[i], tabla[i](x, y));
    }

    /* 4. qsort con callback */
    int datos[] = { 5, 1, 8, 3, 9, 2 };
    int n = (int)(sizeof(datos) / sizeof(datos[0]));

    qsort(datos, n, sizeof(int), comparar_desc);

    printf("\nArray ordenado descendente: ");
    for (int i = 0; i < n; i++) {
        printf("%d ", datos[i]);
    }
    printf("\n");

    return 0;
}

Resultado esperado

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
Puntero a sumar: 12 + 4 = 16
Puntero a multiplicar: 12 * 4 = 48

Tabla de operaciones con x=12, y=4:
  suma -> 16
  resta -> 8
  mult -> 48
  div -> 3

Array ordenado descendente: 9 8 5 3 2 1

Errores frecuentes

  • Olvidar los paréntesis en la declaración: int *f(int) declara una función que devuelve int*, no un puntero a función.
  • No coincidir la firma del puntero con la firma de la función asignada.
  • Llamar al puntero sin desreferenciarlo: tanto (*op)(x, y) como op(x, y) son válidos en C moderno, pero la segunda forma es más habitual.
  • En qsort, hacer la resta directamente (return a - b) puede desbordarse con enteros grandes; la forma segura es devolver (a > b) - (a < b).

Aplicación práctica

Los punteros a función aparecen en:

  • callbacks de ordenación (qsort, bsearch),
  • sistemas de plugins o estrategias intercambiables,
  • máquinas de estados donde cada estado tiene su propia función de procesamiento,
  • APIs de C que aceptan funciones de usuario (señales, threads).

Siguiente ejercicio recomendado

Práctica guiada y siguiente paso

Si quieres una ruta completa con progresión real de dificultad:

FAQ

¿Cuál es la diferencia entre (*op)(x, y) y op(x, y)?

Ambas formas son equivalentes en C. La primera desreferencia explícitamente el puntero; la segunda usa la notación abreviada que el compilador acepta desde C89. La segunda es más común en código moderno.

¿Puedo pasar un puntero a función como argumento?

Sí. Es el mecanismo de callback: void aplicar(int a, int b, int (*f)(int,int)) { printf("%d\n", f(a, b)); }.

¿Los punteros a función son seguros?

Son seguros siempre que apunten a una función válida. El riesgo es asignarles NULL y llamarlos sin comprobar, o asignar una función con firma incompatible (comportamiento indefinido).