Punteros a funciones en C

Definición
Los punteros a funciones (pointer to functions, function pointers) proveen una increíble capacidad: la habilidad de llamar a una función desde otra. Este tipo de funciones comúnmente se conoce como callback.

Sintaxis
Antes de revisar su sintaxis, revisemos el prototipo de una función simple:

int sum(int, int);

La definición de sum es la siguiente:

int sum(int a, int b)
{
    return a + b;
}

Ahora bien, para definir un puntero a sum basta con agregar (* function_name) al nombre de la función. Por ejemplo, el siguiente fragmento define un puntero sum_ptr a sum:

int (*sum_ptr)(int, int) = sum;  // note que sum no use va seguido de parentesis

¿Qué significa todo esto? Usualmente se llamaría a la función sum de esta forma:

int suma = sum(10, 20);   // suma = 30

Pero ahora, es posible usar sum_ptr para llamar indirectamente a sum :

int suma = sum_ptr(10, 20);   // suma = 30

¿Redundante? Quizás. Aunque en este ejemplo parece complicar algo sencillo, la verdad es que utilizar punteros a funciones abre posibilidades a nuestros programas al permitir la ejecución de funciones diversas a partir de una misma.

Ejemplo 1. Ordenar un arreglo de enteros

Este ejemplo es clásico y probablemente el mejor para explicar el uso de callbacks. La función qsort es propia de c y permite ordenar un arreglo base. Lo particular de esta función es lo siguiente:

  • El arreglo base puede ser de cualquier tipo (int, char, etc)
  • Dado que base puede ser de cualquier tipo, hace falta definir una función de comparación para indicarle a qsort qué elemento es menor, mayor o igual.

qsort tiene el siguiente prototipo:

void qsort(void *base, 
           size_t nmemb, size_t size,
           int(*compar)(const void *, const void *));

en donde:

  • base Es un puntero al arreglo que se desea ordenar. Note que es de tipo
    void* lo cual significa que qsort no asume ningún tipo particular de arreglo.
  • nmemb Número de elementos del arreglo base.
  • size Tamaño (sizeof) de cada elemento en base. size_t es un alias de unsigned int.
  • compar Define el prototipo de la función callback para el ordenamiento.

Quizá no se ve a simple vista, pero compar recibe dos parámetros, p1 y p2, los cuales son punteros, y devuelve un entero:

int (*compar) (const void *p1, const void *p2))

Otro punto a considerar es que p1 y p2 son argumentos de compar, no de qsort.
Además, tienen el modificador const, lo cual significa que la función callback no debe modificar
a p1 ni p2, ya que este modificador previene su modificación.

El ejemplo completo es el siguiente:

#include <stdio.h>
#include <stdlib.h>

// prototipo de la funcion para
// comparar enteros
int int_cmp(const void *p1, const void *p2);

int main()
{
    // puntero a la function int_cmp
    int (*cmp)(const void *, const void *) = int_cmp;
    
    int arr[]  = {5, 4, 3, 2, 10, 1, 7};
    int nmemb = 7;
    int i;
    
    for (i=0; i<nmemb; i++)
        printf("%d ", arr[i]);


    // los tres casos son equivalentes
    // qsort(arr, nmemb, sizeof(int), int_cmp);       
    // qsort(arr, nmemb, sizeof(int), &int_cmp);
    qsort(arr, nmemb, sizeof(int), cmp);
    
    
    printf("\n");
    for (i=0; i<nmemb; i++)
        printf("%d ", arr[i]);
    
    return 0;
    
}

int int_cmp(const void *p1, const void *p2)
{
    int a = *(int *) p1;
    int b = *(int *) p2;
    
    if (a > b)
        return 1;
    
    if (b < a)
        return -1;
        
    else
        return 0;    
}

La salida del programa es la siguiente:

5 4 3 2 10 1 7 
1 2 3 4 5 7 10
Anuncios

Un comentario en “Punteros a funciones en C

  1. Wow muy buena tu aportación muchas gracias, ando generando punteros a funciones pero dentro de una estructura, generar un objeto incompleto de esos que usa javascript los cuales tienen propiedades con funciones dentro pero sin las propiedades de la POO solo con fines de encapsulación. Yo se que no es mucho pero a lo mejor puede ayudar en alguien, les dejo mi código.

    typedef int (*int_cmp)(const int, const int);
    int int_cmp_imp(const int p1, const int p2)
    {
    return p1 + p2;
    }

    typedef struct Modelo {
    int propiedad1;
    char propiedad2;
    float propiedad3;
    int_cmp cmp;
    }modelo;

    int main() {
    // Esto es opcional pero al final es una funcion callback que tienes que inicializar despues, no encontre
    // como inicializarla al declararla como en el caso de un objeto.
    modelo mimodelo;
    mimodelo.cmp = int_cmp_imp;
    int p1 = 2;
    int p2 = 3;

    printf(“valor de mimodelo.cmp(p1,p2): %d”, mimodelo.cmp(p1,p2));
    }

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s