Punteros a funciones
No existen variables de tipo “función”, pero es posible tener una variable que es un puntero a una función. Esto es especialmente útil como parámetros para funciones. El siguiente es un ejemplo de un función de ordenamiento genérico, es decir permite ordenar objetos de acuerdo a un criterio definido por una función que se se recibe como parámetro:
/* ordena datos de cualquier tipo usando Quicksort */ void swap(void *v[], int i, int j) { void *aux; aux= v[i]; v[i]= v[j]; v[j]= aux; } void qsort(void *a[], int left, int right, int (*compare)(void *, void *)) { int i, last; if (left>=right) return; swap(a, left, (left+right)/2); last= left; /* +--+-----------+--------+--------------+ | |///////////|\\\\\\\\| | +--+-----------+--------+--------------+ left last i right */ for (i= left+1; i<=right; ++i) if ((*compare)(a[i], a[left])<0) swap(a, ++last, i); swap(a, left, last); qsort(a, left, last-1, compare); qsort(a, last+1, right, compare); }
La declaración int (*compare)(void *, void *)
es para declarar un puntero
a una función. Esto se lee de la siguiente forma. Dados 2 punteros a cualquier
tipo p y q, la expresion (*compare)(p, q)
es de tipo int.
Primer ejemplo de uso
El siguiente programa utiliza la función anterior para ordenar líneas lexicográficamente:
#include <stdio.h> #include <string.h> void qsort(void *a[], int left, int right, int (*compare)(void *, void *)); #define ANCHO 1000 #define MAX 10000 int main() { char s[ANCHO]; char *linea[MAX]; int i, j; /* El siguiente es el criterio para las comparaciones */ int (*compare)(void *, void *)= (int (*)(void *, void*)) strcmp; /* Ver nota */ for (i= 0; fgets(s, ANCHO, stdin)!=NULL; ++i) linea[i]= strdup(s); qsort((void **)linea, 0, i-1, compare); for (j= 0; j<i; ++j) fputs(linea[j], stdout); }
La expresión (int (*)(void *, void*))
es un cast. Se necesita
para compatibilizar strcmp con el tipo de la variable asignada.
Si se pasa directamente strcmp a qsort, el compilador podría reclamar conflicto
de tipos.
Otra forma de hacer esto mismo:
typedef int (*Comparator)(void *, void *); void qsort(void *a[], int left, int right, Comparator compare) { ... } int main() { ... Comparator compare= (Comparator)strcmp; ... }
Lo cual es mucho más legible.
Segundo ejemplo de uso
int numcmp(char *s1, char *s2) /* compara numéricamente */ { int i1, i2; i1= atoi(s1); i2= atoi(s2); return i1<i2? -1 : i1==i2? 0 : 1; } main() { char s[ANCHO]; char *linea[MAX]; int i, j; Comparator compare= (Comparator)numcmp; for (i= 0; fgets(s, ANCHO, stdin)!=NULL; ++i) linea[i]= strdup(s); qsort((void **)linea, 0, i-1, compare); for (j= 0; j<i; ++j) fputs(linea[j], stdout); }
Estudie en los apuntes de Patricio Poblete un programa que recibe la opción “-n” para seleccionar el criterio de ordenamiento numérico, mientras que por omisión ordena alfabéticamente.