|
|||||||
|
|
|
|||||
|
|
|||||||
Un puntero a función almacena la dirección de memoria de una función.
La principal ventaja del uso de estas variables, es la simplificación del código, sobre todo
cuando se tienen que aplicar diferentes criterios, sobre un conjunto de
elementos como son las estructuras.
int (*ptr_func)(int,int); double (*fptr)(double,int);Asignación
puntero = identificador función
Tal como los demás punteros, sólo se le pueden asignar direcciones de memoria de funciones que retornen
el mismo tipo de dato, y que tengan la misma estructura de la lista de parámetros.
Mas que nada esta
regla se usa para evitar errores de indirección.
La asignación sólo puede realizarse, dentro de la función main o como parámetro a una función.
Al igual que los demás punteros, estos pueden cambiar de dirección cuantas veces se necesite.
Indireccionamiento
puntero(valores de parámetros)
Lo que se hace, es ir a la dirección de memoria y evaluar la función.
Ejemplo
Se implementarán dos funciones suma y resta y un puntero a función ptr,
asignando e indireccionado las dos funciones.
#include<stdio.h>
/* Declaración de funciones (prototipos )*/
int suma(int,int);
int resta(int,int);
/* Declaración del puntero a función */
int (*ptr)(int,int);
int main()
{
int x = 5;
int y = 3;
/* asignación */
ptr = suma;
/* indireccionamiento */
int s = ptr(x,y);
printf("\n La suma es %d ",s);
ptr = resta;
printf("\n La resta es %d ",ptr(x,y));
return 0;
}
/* Implementación de funciones */
int suma(int a,int b)
{
return a + b;
}
int resta(int a,int b)
{
return a - b;
}
Paso de punteros a funciones como parámetros
Una función puede recibir como parámetro este tipo de variable.
La declaración del parámetro se hace como cualquier otro y la indirección se tiene
que hacer con el respectivo nombre del parámetro.
Ejemplo
/* Declaración (prototipo) */
int operacion(int,int, int (*func)(int,int));
/* Implementación */
int operacion(int x,int y, int(*func)(int,int))
{
return func(x,y);
}
/* Llamada a la función */
int s = operacion(3,5,suma);
int r = operacion(6,8,resta);
Uso práctico de los punteros a funciones
Supongamos que tenemos que almacenar un conjunto de productos que tiene como caracteristica su
codigo,venta diaria, cantidad almacenada y variación historica de precio.
No encargan realizar un programa que muestre la mayor venta, cantidad y variación de este conjunto
de productos.
Para este tipo de problema, se opta por hacer un programa de simulación, donde se guardaran en
un arreglo los productos, con datos asignados aleatoriamente.
Definición de la estructura :
typedef struct
{
int codigo;
double variacion;
int venta;
int cantidad;
} TProducto;
Tamaño del arreglo : Se opta por implementar una función que retorne la dirección de memoria de un arreglo de tipo TProducto reservado dinámicamente (memoria).
TProducto *crear_arreglo(int tam)
{
TProducto *aux = (TProducto *) calloc(tam,sizeof(TProducto));
return aux;
}
Asignación aleatoria de datos : La cantidad que varie entre 0 y 100. El codigo para que sea
correlativo se asignan los valores 10,20,30...
La venta entre 0 y 200. Finalmente para asignar al campo variacion los valores entre 0 y 99.9 ,se obtiene
un numero aleatorio entre 0 y 999 y se divide por 10, haciendo la conversión correspondiente.
TProducto *asig_datos(TProducto *arr,int tam)
{
for(int i = 0; i < tam; i++)
{
arr[i].cantidad = rand() % 101;
arr[i].codigo = (i + 1) * 10;
arr[i].variacion = double (rand() % 1000) / 10;
arr[i].venta = rand() % 201;
}
return arr;
}
Busqueda de los mayores : Si no se ocuparan punteros a funciones se tendrían que hacer tres funciones de este tipo :
TProducto buscar_mayor_venta(TProducto *arr ,int n)
{
TProducto mayor = arr[0];
for(int i = 1; i < n; i++)
if ( arr[i].venta > mayor.venta )
mayor = arr[i];
return mayor;
}
¿ Que pasaría si en vez de 3 criterios de comparación fueran 20 ? Rpta : Se tendrían que
hacer 20 funciones de este tipo , cambiando la condición del if para cada campo o la unión de ellos.
¿Que pasa si en vez de buscar el mayor del arreglo, nos pidieran algo que cuesta 30 lineas de codigo ? Rpta : DEMASIADO CODIGO !!
Es precisamente por esto que se opta por los punteros a funciones. La técnica es la siguiente :
Implementar un función que recorra los datos y que evalúe una función de comparación generica. Luego de esto se
implementan funciones de una o dos lineas de codigo , que evalúen la condicion del if.
Función genérica : Pasamos como parámetro el arreglo, su respectivo tamaño y alguna función que compare dos elementos de tipo TProducto.
TProducto buscar(TProducto *arr ,int n, int (*f_comp)(TProducto,TProducto))
{
TProducto mayor = arr[0];
for(int i = 1; i < n; i++)
if ( f_comp(arr[i],mayor) )
mayor = arr[i];
return mayor;
}
Funciones de comparación : Por cada criterio, una función que retorne 1 si a es mayor que b ( en este caso ).
int comp_variacion(TProducto a, TProducto b)
{
return a.variacion > b.variacion;
}
int comp_venta(TProducto a,TProducto b)
{
return a.venta > b.venta;
}
int comp_cantidad(TProducto a,TProducto b)
{
return a.cantidad > b.cantidad;
}
Finalmente, haciendo las asignaciones correctas y algo más, se tiene algo como esto :
#include<stdio.h>
#include<stdlib.h>
typedef struct
{
int codigo;
double variacion;
int venta;
int cantidad;
} TProducto;
/* funciones de comparacion */
int comp_variacion(TProducto, TProducto);
int comp_venta(TProducto,TProducto);
int comp_cantidad(TProducto,TProducto);
/* funcion de busqueda */
TProducto buscar(TProducto * ,int,int (*f_comp)(TProducto,TProducto));
/* funcion de asignacion de memoria para arreglo */
TProducto *crear_arreglo(int);
/* funcion que asigna datos aleatoriamente */
TProducto *asig_datos(TProducto *,int);
int main()
{
printf("\n Programa de simulacion \n");
int tam_arreglo;
printf("\n Ingrese numero de productos : ");
scanf("%d",&tam_arreglo);
TProducto *arreglo = crear_arreglo(tam_arreglo);
arreglo = asig_datos(arreglo,tam_arreglo);
printf("\n Datos : \n\n");
printf("\tcod\tcant\tventa\tvar\n");
for(int i = 0; i < tam_arreglo; i++)
{
printf("\n\t%d",arreglo[i].codigo);
printf("\t%d",arreglo[i].cantidad);
printf("\t%d",arreglo[i].venta);
printf("\t%.1lf%%",arreglo[i].variacion);
}
TProducto aux = buscar(arreglo,tam_arreglo,comp_cantidad);
printf("\n mayor cantidad : %d ",aux.cantidad);
aux = buscar(arreglo,tam_arreglo,comp_venta);
printf("\n mayor venta : %d ",aux.venta);
aux = buscar(arreglo,tam_arreglo,comp_variacion);
printf("\n mayor variacion : %.1lf%% ",aux.variacion);
free(arreglo);
return 0;
}
int comp_variacion(TProducto a, TProducto b)
{
return a.variacion > b.variacion;
}
int comp_venta(TProducto a,TProducto b)
{
return a.venta > b.venta;
}
int comp_cantidad(TProducto a,TProducto b)
{
return a.cantidad > b.cantidad;
}
TProducto buscar(TProducto *arr ,int n, int (*f_comp)(TProducto,TProducto))
{
TProducto mayor = arr[0];
for(int i = 1; i < n; i++)
if ( f_comp(arr[i],mayor) )
mayor = arr[i];
return mayor;
}
TProducto *crear_arreglo(int tam)
{
TProducto *aux = (TProducto *) calloc(tam,sizeof(TProducto));
return aux;
}
TProducto *asig_datos(TProducto *arr,int tam)
{
for(int i = 0; i < tam; i++)
{
arr[i].cantidad = rand() % 101;
arr[i].codigo = (i + 1) * 10;
arr[i].variacion = double (rand() % 1000) / 10;
arr[i].venta = rand() % 201;
}
return arr;
}
Salida del programa :

Ejercicio : Basandose en lo anterior, realizar un programa en C que almacene la información
de personas recluidas. Cada preso tendrá las siguientes caracteristicas :
numero : (correlativo) 1,2,3,4 ...
dias : que han permanecido recluidos : 1 < dias <= 5000
faltas : o castigos del preso : 0 <= faltas <= 15
edad : 15 <= edad < 65
nivel de conducta : 0 <= conducta <= 100 (0 : peor conducta)
Se piden los siguientes datos :
a ) Promedio de dias que llevan preso.
b ) Promedio de faltas o castigos.
c ) Promedio de edad.
c ) Número del interno con menos edad.
d ) Número del interno con peor nivel de conducta.
* Nota : Los datos de los presos tienen que estar tabulados de manera similar. El numero de
presos que se ingrese por teclado , tiene que depender de una correcta salida a pantalla, que
permita ver los datos y el informe.
Tener cuidado con los límites de la asignación aleatoria!.
Los promedios deberán salir a pantalla sólo con un decimal.
El código debe estar bien tabulado.

Ayuda
Para calcular los promedios :
¿ Que debo hacer ? rpta : hacer una función generica que calcule el promedio.
.- Todos los campos son enteros , eso es bueno !!
¿ Calcular el promedio de qué ? rpta : De tres campos.
¿ O sea tres criterios ? rpta : Si , ver el asunto de los criterios.
¿ En los promedios , hay que comparar ? rpta : Definitivamente NO.
.- Por cada criterio de comparación una función de comparación ... tres campos ...
Solución :
#include<stdio.h>
#include<stdlib.h>
typedef struct
{
int numero;
int dias;
int faltas;
int edad;
int conducta;
} TPreso;
int comp_conducta(TPreso a,TPreso b);
int comp_edad(TPreso a,TPreso b);
int campo_dias(TPreso);
int campo_faltas(TPreso);
int campo_edad(TPreso);
TPreso buscar_menor(TPreso * ,int,int (*f_comp)(TPreso,TPreso));
double promedio(TPreso *, int , int (*f_campo)(TPreso));
TPreso *crear_arreglo(int);
TPreso *asig_datos(TPreso *,int);
int main()
{
printf("\n Programa de simulacion \n");
int tam_arreglo;
printf("\n Ingrese numero de reos : ");
scanf("%d",&tam_arreglo);
TPreso *arreglo = crear_arreglo(tam_arreglo);
arreglo = asig_datos(arreglo,tam_arreglo);
printf("\n Datos : \n\n");
printf("\t num\tdias\tfaltas\tedad\tconducta \n");
for(int i = 0; i < tam_arreglo; i++)
{
printf("\n\t %d",arreglo[i].numero);
printf("\t%d",arreglo[i].dias);
printf("\t%d",arreglo[i].faltas);
printf("\t%d",arreglo[i].edad);
printf("\t%d",arreglo[i].conducta);
}
TPreso aux;
double prom;
prom = promedio(arreglo,tam_arreglo,campo_dias);
printf("\n\n\t Promedio de dias : %.1lf",prom);
prom = promedio(arreglo,tam_arreglo,campo_faltas);
printf("\t Promedio de faltas : %.1lf",prom);
prom = promedio(arreglo,tam_arreglo,campo_edad);
printf("\n\t Promedio de edad : %.1lf",prom);
aux = buscar_menor(arreglo,tam_arreglo,comp_edad);
printf("\t Reo menor edad : %d ",aux.numero);
aux = buscar_menor(arreglo,tam_arreglo,comp_conducta);
printf("\n\t Reo peor conducta : %d \n\n",aux.numero);
free(arreglo);
return 0;
}
int comp_conducta(TPreso a,TPreso b)
{
return a.conducta < b.conducta;
}
int comp_edad(TPreso a,TPreso b)
{
return a.edad < b.edad;
}
int campo_dias(TPreso a)
{
return a.dias;
}
int campo_faltas(TPreso a)
{
return a.faltas;
}
int campo_edad(TPreso a)
{
return a.edad;
}
TPreso buscar_menor(TPreso *arr ,int n, int (*f_comp)(TPreso,TPreso))
{
TPreso menor = arr[0];
for(int i = 1; i < n; i++)
if ( f_comp(arr[i],menor) ) menor = arr[i];
return menor;
}
double promedio(TPreso *arr, int n , int (*f_campo)(TPreso))
{
double s = 0.0;
for(int i = 0; i < n; i++)
s += (double) f_campo(arr[i]) / n;
return s;
}
TPreso *crear_arreglo(int tam)
{
TPreso *aux = (TPreso *) calloc(tam,sizeof(TPreso));
return aux;
}
TPreso *asig_datos(TPreso *arr,int tam)
{
for(int i = 0; i < tam; i++)
{
arr[i].numero = i + 1;
arr[i].dias = 1 + rand() % 5000;
arr[i].faltas = rand() % 16;
arr[i].edad = 15 + rand() % 50;
arr[i].conducta = rand() % 101;
}
return arr;
}