Sei sulla pagina 1di 31

Variaciones de las

estructuras de datos base


Unidad 06 - Punteros a
funciones

Profesores

Alfredo Granda
Juan Ramirez

Unidad 06 Variaciones de
las estructuras de datos base
Objetivos

Definicin de punteros a funciones o


demonios.
Declaracin de punteros a funciones.
Funciones como parmetros.
Usos comnes.

Definicin

Punteros a funciones
Un puntero a una funcin es conocido
tambin como Demonio.
Los punteros a funciones son variables
que almacenan la direccin de memoria
de una funcin.
Al igual que un puntero comn que
necesita saber el tipo de dato al que
apunta, el puntero a funcin necesita
conocer el tipo de funcin al que apunta

Declaracin de punteros a
funciones

Sintaxis
Un puntero a una funcin se define de la siguiente manera:
<tipo retorno> (*<nombre>)(<tipo parmetros>);
Por ejemplo:
int (*puntero1)(int, int);
En este caso el puntero con nombre puntero1 podr apuntar a
cualquiera de las siguientes funciones:
int SumaValores(int a, int b);
int RestaValores(int x, int y);
int DameMayor(int numero1, int numero2);

Pero no podr apuntar a las siguientes funciones ya que la estructura


difiere:
void SumaValores(int a, int b);
int SumaValores(double a, double b);

Ejemplo bsico
Hacer un programa en consola que le pida al usuario un nmero N.
Si N es par imprimir los nmeros pares desde 2 hasta N, de lo
contrario imprimir los impares desde 1 hasta N.
void ImprimePares(int N) {
for (int i=2; i<=N; i+=2)
printf("%d\n", i);
}
void ImprimeImpares(int N) {
for (int i=1;i<=N;i+=2)
printf("%d\n", i);
}
int main()
{
int N;
printf("Ingrese N: ");
scanf("%d", &N);
// Declarar puntero a funcion
void (*pfunc)(int);
// Asignar al puntero la funcion correcta
if (N % 2 == 0)
pfunc = ImprimePares;
else
pfunc = ImprimeImpares;
// Invocar a la funcion
pfunc(N);
return 0;
}

Ejemplos de invocacin
void funcion() {
printf("Una funcion X\n");
}
void (*pfunc)() = funcion;
void (**ppfunc)() = &pfunc;
int main()
{
// Tipos de invocacion.
// Todas las lineas a continuacion invocan a la funcion
funcion();
pfunc();
(*pfunc)();
(**ppfunc)();
(*ppfunc)();
return 0;
}

Funciones como parmetros

Funciones como parmetros


La posibilidad de utilizar funciones como
argumentos en la invocacin de otras
funciones, es la principal razn de la
introduccin en el lenguaje de este tipo de
punteros a funciones.
En si consiste en alargar la funcionalidad
de la funcin invocada, ya que a travs de
sus argumentos, puede invocar a otras
funciones.

Sintaxis
La forma en la que definimos una funcin siempre
es igual, lo que cambia es que ahora uno o ms
parmetros a la funcin sern punteros a funciones.
void MiFuncion(int A, bool (*pEsCierto)(int))
Recibe un entero y un puntero a una funcin que tiene
como parmetro un entero y devuelve un booleano.

void Operar(int (*pOpera)(int, int, double))


Recibe un puntero a una funcin que tiene como
parmetro dos enteros y un double y devuelve un
entero.

Utilidad
Sin embargo, la utilidad cobra su
verdadero
significado
cuando
el
argumento no es constante (no se invoca
siempre la misma funcin) sino que es
variable.

Ejemplo
Supongamos que contamos con un arreglo de
enteros llamado vec con una cantidad de
elementos N. Ambas variables han sido
declaradas de forma global por lo que puede
acceder directamente a ellas desde sus funciones.
Implemente las siguientes funciones para consola
utilizando el arreglo:

ImprimirPares
ImprimirImpares
ImprimirMultiplosDe5
ImprimirSiLosDigitosSuman10

void ImprimirPares()
{
for (int i=0; i<N; i++)
if (vec[i] % 2 == 0)
printf("%d\n", vec[i]);
}
void ImprimirImpares()
{
for (int i=0; i<N; i++)
if (vec[i] % 2 != 0)
printf("%d\n", vec[i]);
}
void ImprimirMultiplosDe5()
{
for (int i=0; i<N; i++)
if (vec[i] % 5 == 0)
printf("%d\n", vec[i]);
}
void ImprimirSiLosDigitosSuman10()
{
for (int i=0; i<N; i++) {
if (SumaDigitos(vec[i]) == 10)
printf("%d\n", vec[i]);
}
}

El algoritmo siempre es el mismo.


Lo nico que cambia es la
condicin para detectar si se
imprime o no.

void ImprimirDatos(bool (*DebeImprimir)(int))


{
for (int i=0; i<N; i++)
if (DebeImprimir(vec[i]))
printf("%d\n", vec[i]);
}
bool EsPar(int A)
{
return A % 2 == 0;
}
bool EsImpar(int A)
{
return A % 2 != 0;
}
bool EsMultiploDe5(int A)
{
return A % 5 == 0;
}
bool DigitosSuman10(int A)
{
return SumaDigitos(A) == 10;
}

Utilizando punteros a funciones


podemos crear una funcin
genrica a la que podemos
mandarle cualquiera de los
mtodos para modificar su
resultado.

void ImprimirDatos(bool (*DebeImprimir)(int), void (*HacerAlgo)(int))


{
for (int i=0; i<N; i++)
if (DebeImprimir(vec[i]))
HacerAlgo(vec[i]);
Inclusive se puede
}
bool EsPar(int A)
{
return A % 2 == 0;
}
bool EsImpar(int A)
{
return A % 2 != 0;
}
void ImprimeSoloEnLinea(int A)
{
printf("%d\n", A);
}
void ImprimeConEspacio(int A)
{
printf("%d ", A);
}
void ImprimeEnArchivo(int A)
{
FILE *F = fopen("ARCHIVO.TXT", "at");
fprintf("%d\n", A);
fclose(F);
}

modificar la
funcin para que sea an ms
genrica y no imprima, sino que
haga algo con los datos.

Ejemplo:
ImprimirDatos( EsPar,
ImprimeEnArchivo );

Demonios para mostrar


datos

Demonios para mostrar datos


Supongamos que tenemos una clase que
maneja un vector de enteros y queremos
que los nmeros enteros se muestren en
consola y tambin en el entorno visual
dentro de un listbox.
Como no es posible hacer ambos a la vez,
crearemos dos funciones, una para cada
caso.

class Cvector
{
private:
int *vec;
int ne;
public:
// Mtodos
void MostrarEnConsola()
{
for (int i=0; i<ne; i++)
printf("%d\n", vec[i]);
}
void MostrarEnListBox(ListBox ^lb)
{
for (int i=0; i<ne; i++)
lb->Items->Add(vec[i]);
}
};

// Programa en consola
int main()
{
Cvector *vec = new Cvector();
// Llenar datos
vec->MostrarEnConsola();
delete vec;
}
// Programa con formularios
public ref class Form1 : System::Windows:Forms:Form
{
private:
Cvector *vec;
System::Windows::Forms::ListBox^ listBox1;
public:
Form1()
{
InitializeComponent();
vec = new Cvector();
}
Void button1_Click(Object^ sender, EventArgs^
{
vec->MostrarEnListBox(listBox1);
}
};

e)

Problema de esta solucin


El problema con esta solucin es que no es
genrica, ya que solo permite mostrar los datos
en consola o en un listbox.
Que sucedera si queremos mostrarlos en:

Archivos
GridView
CheckedListBox
Base de datos
ComboBox

La solucin es utilizar punteros a funciones.

class Cvector
{
private:
int *vec;
int ne;
public:
// Mtodos
void MostrarGenerico( void(*pProcesar)(int) )
{
for (int i=0; i<ne; i++)
pProcesar(vec[i]);
}
};

// Programa en consola
void Imprimir(int dato)
{
printf("%d\n", dato);
}
int main()
{
Cvector *vec = new Cvector();
// Llenar datos
vec->MostrarGenerico( Imprimir );
delete vec;
}
//-----------------------------------------------------------------------//-----------------------------------------------------------------------// Programa con formularios
public ref class Form1 : System::Windows:Forms:Form
{
private:
Cvector *vec;
public:
System::Windows::Forms::ListBox^ listBox1;
public:
Form1()
{
InitializeComponent();
vec = new Cvector();
}
Void button1_Click(Object^ sender, EventArgs^
{
vec->MostrarGenerico( Imprimir );
}

e)

};
void Imprimir(int dato)
{
Form1 ^frm = (Form1^)Application::OpenForms["Form1"];
frm->listBox1->Items->Add( dato );
}

Demonios como atributos de


una clase

Demonios como atributos


Es posible definir punteros a funciones como
atributos de una clase para que no sea
necesario enviarlos a una funcin.
El procedimiento es el mismo pero hay que
tener en cuenta de que se deber preguntar si
el demonio es o no NULL antes de intentar
utilizarlo.
Por lo general, los demonios cuando se usan
como atributos deben ser pblicos para que se
puedan modificar.

class Cvector
{
private:
int *vec;
int ne;
public:
void(*OnProcesar)(int);
public:
// Mtodos
Cvector()
{
ne = 0;
OnProcesar = NULL;
}
void MostrarGenerico()
{
for (int i=0; i<ne; i++)
{
if (pProcesar != NULL)
OnProcesar(vec[i]);
}
}
};

// Programa en consola
void Imprimir(int dato)
{
printf("%d\n", dato);
}
int main()
{
Cvector *vec = new Cvector();
vec->OnProcesar = Imprimir;
// Llenar datos
vec->MostrarGenerico();
delete vec;
}

Usos comnes

Usos comnes de punteros a funciones.


Crear clases genricas:
Para crear una clase genrica es necesario
proporcionar algn medio de visualizacin de la
informacin.
Esta puede ser en archivos, consola, entorno visual,
impresora, correo electrnico, etc.
Al ofrecer una funcin con punteros a funcin, el
usuario de mi clase puede elegir como procesar estos
datos.

Crear mtodos y libreras estndares.


Utilizar DLLs
Ordenamiento (Seleccionar el criterio)

Ejercicios

Ejercicio 1 - Parte 1
Realizar un programa en C que almacene la informacin de personas recluidas.
Deber hacer uso de punteros a funciones para reducir el tamao de su cdigo.
Cada preso tendr las siguientes caracterstica:
Numero: (correlativo) 1,2,3,4 ...
Das: 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 das que llevan preso.
b) Promedio de faltas o castigos.
c) Promedio de edad.
d) Nmero del interno con menos edad.
e) Nmero del interno con peor nivel de conducta.
f) Nmero del interno con menor cantidad de faltas.

Ejercicio 1 - Parte 2
Los datos de los presos tienen que estar tabulados de manera similar.
El nmero 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 lmites de la asignacin aleatoria!.
Los promedios debern salir a pantalla slo con un decimal.
El cdigo debe estar bien tabulado.

Potrebbero piacerti anche