andrewrk
Quiero crear una función que realice una función pasada por parámetro en un conjunto de datos. ¿Cómo se pasa una función como parámetro en C?
Niyaz
Declaración
Un prototipo para una función que toma un parámetro de función se parece a lo siguiente:
void func ( void (*f)(int) );
Esto establece que el parámetro f
será un puntero a una función que tiene un void
tipo de retorno y que toma un solo int
parámetro. La siguiente función (print
) es un ejemplo de una función que podría pasarse a func
como parámetro porque es del tipo adecuado:
void print ( int x ) {
printf("%d\n", x);
}
Llamada de función
Al llamar a una función con un parámetro de función, el valor pasado debe ser un puntero a una función. Use el nombre de la función (sin paréntesis) para esto:
func(print);
Llamaría func
pasándole la función de impresión.
Cuerpo de función
Como con cualquier parámetro, func
ahora puede usar el nombre del parámetro en el cuerpo de la función para acceder al valor del parámetro. digamos que func
aplicará la función que se le pasa a los números 0-4. Considere, primero, cómo se vería el ciclo para llamar a imprimir directamente:
for ( int ctr = 0 ; ctr < 5 ; ctr++ ) {
print(ctr);
}
Ya que func
La declaración de parámetros de dice que f
es el nombre de un puntero a la función deseada, recordamos primero que si f
entonces es un puntero *f
es la cosa que f
apunta a (es decir, la función print
en este caso). Como resultado, simplemente reemplace cada aparición de print en el ciclo anterior con *f
:
void func ( void (*f)(int) ) {
for ( int ctr = 0 ; ctr < 5 ; ctr++ ) {
(*f)(ctr);
}
}
-
En su primer y último ejemplo de código, el * no es obligatorio. Tanto la definición del parámetro de la función como la
f
la llamada de función puede tomarf
tal como está sin *. Sin embargo, podría ser una buena idea hacerlo como lo hace, para que sea obvio que el parámetro f es un puntero de función. Pero daña la legibilidad con bastante frecuencia.– Gauthier
22 de febrero de 2012 a las 12:52
-
Ver [c99, 6.9.1§14] por ejemplo. Ambos son correctos, por supuesto, solo quería mencionar la alternativa.
– Gauthier
22 de febrero de 2012 a las 12:58
-
¿En serio? La respuesta mejor calificada no hace una sola referencia al uso de un
typedef
para punteros de función? Lo siento, tengo que votar negativamente.– Jonathan Reinhart
1 de octubre de 2014 a las 8:03
-
@JonathonReinhart, ¿cuáles serían las ventajas con el enfoque ‘typedef’? Sin embargo, esta versión se ve mucho más limpia y también carece de declaraciones adicionales. bastante principiante aquí.
– Abhinav Gauniyal
22 de febrero de 2015 a las 7:04
-
@JonathonReinhart bien visto; se debe tener en cuenta explícitamente que las definiciones de tipo de puntero ofuscan el código y, por lo tanto, no se deben usar.
–MM
24 de noviembre de 2015 a las 2:39
Ricardo
Desde C++11 puedes usar el biblioteca funcional para hacer esto de una manera sucinta y genérica. La sintaxis es, por ejemplo,
std::function<bool (int)>
donde bool
es el tipo de retorno aquí de una función de un argumento cuyo primer argumento es de tipo int
.
He incluido un programa de ejemplo a continuación:
// g++ test.cpp --std=c++11
#include <functional>
double Combiner(double a, double b, std::function<double (double,double)> func){
return func(a,b);
}
double Add(double a, double b){
return a+b;
}
double Mult(double a, double b){
return a*b;
}
int main(){
Combiner(12,13,Add);
Combiner(12,13,Mult);
}
A veces, sin embargo, es más conveniente usar una función de plantilla:
// g++ test.cpp --std=c++11
template<class T>
double Combiner(double a, double b, T func){
return func(a,b);
}
double Add(double a, double b){
return a+b;
}
double Mult(double a, double b){
return a*b;
}
int main(){
Combiner(12,13,Add);
Combiner(12,13,Mult);
}
-
La pregunta es sobre C; C++ no se aplica aquí.
– Super gato
29/10/2015 a las 23:44
-
La pregunta para C++ (stackoverflow.com/questions/6339970/…) se menciona aquí, por lo que creo que esta respuesta está en su lugar.
– mr_T
24/03/2016 a las 11:00
-
Tal vez la pregunta para C++ no debería mencionarse aquí porque esta pregunta es para C.
–Michael Fulton
19 de abril de 2018 a las 16:22
-
Esta pregunta surgió primero cuando busqué “llamada de función c ++ como parámetro”, por lo que esta respuesta cumple bien su propósito aquí independientemente.
– ufoxDan
7 noviembre 2019 a las 21:50
roo
Esta pregunta ya tiene la respuesta para definir punteros de función, sin embargo, pueden complicarse mucho, especialmente si los va a pasar por su aplicación. Para evitar este inconveniente, le recomendaría que escriba def el puntero de función en algo más legible. Por ejemplo.
typedef void (*functiontype)();
Declara una función que devuelve void y no acepta argumentos. Para crear un puntero de función a este tipo, ahora puede hacer:
void dosomething() { }
functiontype func = &dosomething;
func();
Para una función que devuelve un int y toma un carácter, harías
typedef int (*functiontype2)(char);
y para usarlo
int dosomethingwithchar(char a) { return 1; }
functiontype2 func2 = &dosomethingwithchar
int result = func2('a');
Hay bibliotecas que pueden ayudar a convertir los punteros de función en buenos tipos legibles. Él función de impulso ¡La biblioteca es excelente y vale la pena el esfuerzo!
boost::function<int (char a)> functiontype2;
es mucho mejor que el anterior.
-
Si desea “convertir un puntero de función en un tipo”, no necesita la biblioteca boost. Solo usa
typedef
; es más simple y no requiere bibliotecas adicionales.– wizzwizz4
09/04/2016 a las 11:50
-
¿La biblioteca boost no es C++? ¿Por qué lo mencionas en una pregunta C?
– 12431234123412341234123
2 de octubre de 2020 a las 12:48
-
Para las funciones que usan una convención de llamada diferente, coloque la convención de llamada antes del primer *. Me gusta esto:
typedef void(__stdcall* funcPtr)(int arg1, int arg2);
– Dwedit
19 sep 2021 a las 18:04
Yogeesh HT
Aprobar dirección de una función como parámetro de otra función Como se muestra abajo
#include <stdio.h>
void print();
void execute(void());
int main()
{
execute(print); // sends address of print
return 0;
}
void print()
{
printf("Hello!");
}
void execute(void f()) // receive address of print
{
f();
}
También podemos pasar la función como parámetro usando puntero de función
#include <stdio.h>
void print();
void execute(void (*f)());
int main()
{
execute(&print); // sends address of print
return 0;
}
void print()
{
printf("Hello!");
}
void execute(void (*f)()) // receive address of print
{
f();
}
Hemanth Kollipara
Voy a explicar con un código de ejemplo simple que toma un compare
funcionar como parámetro de otro sorting
función. Digamos que tengo una función de clasificación de burbujas que toma una función de comparación personalizada y la usa en lugar de una declaración if fija.
Función de comparación
bool compare(int a, int b) {
return a > b;
}
Ahora, el tipo de burbuja que toma otra función como su parámetro para realizar la comparación
Función de clasificación de burbujas
void bubble_sort(int arr[], int n, bool (&cmp)(int a, int b)) {
for (int i = 0;i < n - 1;i++) {
for (int j = 0;j < (n - 1 - i);j++) {
if (cmp(arr[j], arr[j + 1])) {
swap(arr[j], arr[j + 1]);
}
}
}
}
Finalmente, el main
que llama a la función de clasificación de burbujas pasando la función de comparación booleana como argumento.
int main()
{
int i, n = 10, key = 11;
int arr[10] = { 20, 22, 18, 8, 12, 3, 6, 12, 11, 15 };
bubble_sort(arr, n, compare);
cout<<"Sorted Order"<<endl;
for (int i = 0;i < n;i++) {
cout << arr[i] << " ";
}
}
Producción:
Sorted Order
3 6 8 11 12 12 15 18 20 22
Las funciones se pueden “pasar” como punteros de función, según ISO C11 6.7.6.3p8: “Una declaración de un parámetro como ”tipo de devolución de función” se ajustará a ”apuntador a tipo de devolución de función”, como en 6.3.2.1. “. Por ejemplo, esto:
void foo(int bar(int, int));
es equivalente a esto:
void foo(int (*bar)(int, int));
san_groceon
Tienes que pasar un puntero de función. La sintaxis es un poco engorrosa, pero es realmente poderosa una vez que te familiarizas con ella.
Si está usando funciones/matrices como variables, SIEMPRE use
typedef
.– Pato mugido
13 de enero de 2014 a las 21:09
lo llamamos Puntero de función
– AminM
1 de abril de 2014 a las 11:11
@MooingDuck No estoy de acuerdo con su sugerencia, y su sugerencia carece de razonamiento para respaldar la conclusión. personalmente prefiero nunca usando typedef en punteros de función, y creo que hace que el código sea más claro y fácil de leer.
– andrewrk
16 de diciembre de 2015 a las 22:26
@andrewrk: Tú prefieres
void funcA(void(*funcB)(int))
yvoid (*funcA())()
paratypedef void funcB(); void funcA(funcB)
yfuncB funcA()
? No veo el lado positivo.– Pato mugido
16 de diciembre de 2015 a las 23:27
Ver las funciones de la biblioteca estándar
qsort
ybsearch
para ver ejemplos de cómo se hace esto.– Bob Jarvis – Слава Україні
15 de febrero de 2021 a las 12:45