Entiendo que puedo usar punteros para las funciones.¿Para qué sirven los punteros de función y cómo los usaría?
¿Alguien puede explicar por qué uno los usaría y cómo? Un código de ejemplo corto me sería muy útil.
Entiendo que puedo usar punteros para las funciones.¿Para qué sirven los punteros de función y cómo los usaría?
¿Alguien puede explicar por qué uno los usaría y cómo? Un código de ejemplo corto me sería muy útil.
Un caso simple es el siguiente: tiene una serie de operaciones (funciones) según su lógica comercial. Tiene una función de hash que reduce un problema de entrada a una de las funciones de lógica de negocios. Un código limpio tendría una matriz de indicadores de función, y su programa deducirá un índice de esa matriz de la entrada y la llamará.
Aquí es un ejemplo de código:
typedef void (*fn)(void) FNTYPE;
FNTYPE fn_arr[5];
fn_arr[0] = fun1; // fun1 is previously defined
fn_arr[1] = fun2;
...
void callMyFun(string inp) {
int idx = decideWhichFun(inp); // returns an int between 0 and 4
fn_arr[idx]();
}
Pero, por supuesto, las devoluciones de llamada son el uso más común. Código de muestra a continuación:
void doLengthyOperation(string inp, void (*callback)(string status)) {
// do the lengthy task
callback("finished");
}
void fnAfterLengthyTask(string status) {
cout << status << endl;
}
int main() {
doLengthyOperation(someinput, fnAfterLengthyTask);
}
Otro uso para los punteros es iterar listas o matrices.
No para punteros de función. Lea la pregunta. –
usando punteros a función en iteradores es perfectamente válido. Hay un ejemplo aquí: http://stackoverflow.com/questions/840501/how-do-function-pointers-in-c-work/840669#840669 –
Un caso de uso bastante común es una función de devolución de llamada. Por ejemplo, si carga algo desde un DB, puede implementar su función de carga para que informe el progreso a una función de devolución de llamada. Esto se puede hacer con punteros a funciones.
Uno de mis favoritos. ¡Pero no solo para informar el progreso, sino para pasar todos los registros! –
Este es un caso de uso muy común de hecho. –
Devolución de llamada. Hago una llamada asíncrona a un fragmento de código y quiero que me avise cuando termine, puedo enviarle un puntero a la función para llamar una vez que haya terminado.
Utiliza un puntero de función cuando necesita dar un método de devolución de llamada. Uno de los ejemplos clásicos es registrar manejadores de señales - la cual función se llama cuando el programa se pone SIGTERM (Ctrl-C)
He aquí otro ejemplo:
// The four arithmetic operations ... one of these functions is selected
// at runtime with a switch or a function pointer
float Plus (float a, float b) { return a+b; }
float Minus (float a, float b) { return a-b; }
float Multiply(float a, float b) { return a*b; }
float Divide (float a, float b) { return a/b; }
// Solution with a switch-statement - <opCode> specifies which operation to execute
void Switch(float a, float b, char opCode)
{
float result;
// execute operation
switch(opCode)
{
case '+' : result = Plus (a, b); break;
case '-' : result = Minus (a, b); break;
case '*' : result = Multiply (a, b); break;
case '/' : result = Divide (a, b); break;
}
cout << "Switch: 2+5=" << result << endl; // display result
}
// Solution with a function pointer - <pt2Func> is a function pointer and points to
// a function which takes two floats and returns a float. The function pointer
// "specifies" which operation shall be executed.
void Switch_With_Function_Pointer(float a, float b, float (*pt2Func)(float, float))
{
float result = pt2Func(a, b); // call using function pointer
cout << "Switch replaced by function pointer: 2-5="; // display result
cout << result << endl;
}
Usted puede aprender más acerca de los punteros de función aquí http://www.newty.de/fpt/index.html
Si está más familiarizado con los lenguajes orientados a objetos, puede pensar que es la forma en que C implementa el strategy design pattern.
Sería +1 si el lenguaje C tuviera 'cout << endl' (y también su código C++ debe ser' using namespace std; 'para que funcione) –
¿Dónde está la mención de' opcode' en su 'Switch_With_Function_Pointer() 'función? –
@Joy - En la declaración 'switch()'. –
Vamos a hacer una función map
-como para C.
void apply(int *arr, size_t len, int (*func)(int))
{
for(size_t i = 0; i < len; i++)
arr[i] = func(arr[i]);
}
De esta manera, podemos transformar una función que trabaja en números enteros para trabajar en series de números enteros. También podríamos hacer una versión similar:
void apply_enumerated(int *arr, size_t len, int (*func)(size_t, int))
{
for(size_t i = 0; i < len; i++)
arr[i] = func(i, arr[i]);
}
Esto hace lo mismo, pero permite que nuestra función para saber qué elemento que está.Podríamos utilizar esto, por ejemplo:
int cube(int i) { return i * i * i }
void print_array(int *array, size_t len, char *sep)
{
if(sep == NULL) sep = ", ";
printf("%d", *array);
for(size_t i = 1; i < len; i++) printf("%s%d", sep, array[i])
}
#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
int main(void)
{
int array[5] = { 1, 2, 3, 4, 5 };
print_array(array, ARRAY_SIZE(array), NULL);
apply(array, ARRAY_SIZE(array), cube);
print_array(array, ARRAY_SIZE(array), NULL);
return 0;
}
Ese código imprimirá:
1, 2, 3, 4, 5
1, 8, 27, 64, 125
Para nuestro ejemplo de enumeración:
int mult(size_t i, int j) { return i * j }
// print_array and ARRAY_SIZE as before
int main(void)
{
int array[5] = { 1, 2, 3, 4, 5 };
print_array(array, ARRAY_SIZE(array), NULL);
apply_enumerated(array, ARRAY_SIZE(array), mult);
print_array(array, ARRAY_SIZE(array), NULL);
return 0;
}
Esta impresora:
1, 2, 3, 4, 5
0, 2, 6, 12, 20
Como un ejemplo más real del mundo, un st la biblioteca de anillo podría tener una función que aplica una función que opera en caracteres únicos a todos los caracteres de la cadena. Un ejemplo de tales funciones son las funciones de biblioteca estándar toupper()
y tolower()
en ctype.h
- podríamos usar esta función string_apply()
para hacer que una función string_toupper()
sea fácil.
Me sorprende que nadie haya mencionado "máquinas de estado". Los punteros de función son una forma muy común de implementar máquinas de estado para tareas como el análisis sintáctico. Ver por ejemplo: link.
Una muy buena y fácil de entender tutorial: http://www.newty.de/fpt/index.html
Espero que esto ayude.
Para el código, consulte la respuesta de qrdl al state machines tutorials.
He utilizado una variante de su método para implementar un menú para una pantalla LCD que tengo en una placa. Muy muy útil, hace que la codificación sea mucho más limpia y fácil de leer. El uso de punteros de función hace que la expansión del número, los nombres y el orden de los menús sea muy fácil, y oculta todos esos detalles de la función de llamadas de nivel superior que solo ve 'hey, aquí escribo en la pantalla LCD'.
Mire la función de biblioteca estándar 'qsort()' y vea si eso lo ayuda. –
http://stackoverflow.com/questions/840501/how-do-function-pointers-in-c-work/840669#840669 –
También se utilizan mucho bajo el capó de los sistemas operativos .. Al igual que he creado un sistema operativo con el marco del controlador con muchos punteros a las funciones. Son muy útiles porque son como los métodos "virtuales/abstractos", excepto que debes controlarlo y administrarlo ... – Earlz