2008-08-13 15 views
452

Quiero crear una función que realice una función pasada por parámetro en un conjunto de datos. ¿Cómo pasas una función como parámetro en C?¿Cómo se pasa una función como parámetro en C?

+9

Si está utilizando funciones/matrices como variables, siempre use 'typedef'. –

+2

Lo llamamos [Puntero de función] (http://en.wikipedia.org/wiki/Function_pointer#Example_in_C) – AminM

+0

El nombre de la función debe ser un ponter para la función. La mayoría de las personas que aprenden C cubre qsort tarde o temprano que hace exactamente esto? – mckenzm

Respuesta

583

Declaración

Un prototipo de una función que toma un parámetro de función tiene el siguiente aspecto:

void func (void (*f)(int)); 

Esto indica que el parámetro f será un puntero a una función que tiene un void tipo de retorno y que toma un solo parámetro int. La siguiente función (print) es un ejemplo de una función que se podía pasar a func como parámetro, ya que es del tipo adecuado:

void print (int x) { 
    printf("%d\n", x); 
} 

llamada a función

Cuando se llama a una función con una función parámetro, 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, que pasa a la función de impresión a la misma.

cuerpo de la función

Al igual que con cualquier parámetro, func ahora pueden 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 pasa a los números 0-4. Consideremos, en primer lugar, lo que el bucle se vería como para llamar la impresión directa:

for (int ctr = 0 ; ctr < 5 ; ctr++) { 
    print(ctr); 
} 

Desde func 's declaración de parámetros dice que f es el nombre de un puntero a la función deseada, recordamos en primer lugar que si f es una el apuntador entonces *f es lo que apunta a f (es decir, la función print en este caso). Como resultado de ello, basta con sustituir cada ocurrencia de impresión en el ciclo anterior con *f:

void func (void (*f)(int)) { 
    for (int ctr = 0 ; ctr < 5 ; ctr++) { 
    (*f)(ctr); 
    } 
} 

De http://math.hws.edu/bridgeman/courses/331/f05/handouts/c-c++-notes.html

+27

En su primer y último ejemplo de código, * no es obligatorio. Tanto la definición del parámetro de función como la llamada a la función 'f' pueden tomar' f' 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 a la función. Pero hiere la legibilidad con bastante frecuencia. – Gauthier

+4

Vea [c99, 6.9.1§14] para ejemplos. Ambos son correctos, por supuesto, solo quería mencionar la alternativa. – Gauthier

+3

¿De verdad? ¿La respuesta mejor calificada no hace una sola referencia al uso de un 'typedef' para punteros de función? Lo siento, tengo que votar abajo. –

2

Debe pasar un function pointer. La sintaxis es un poco engorrosa, pero es realmente poderosa una vez que te familiarizas con ella.

102

Esta cuestión ya tiene la respuesta para la definición de los punteros de función, sin embargo, puede ser muy complicado, especialmente si los pasará por su aplicación. Para evitar esta desagradable, le recomendaría que escriba el puntero de la función en algo más legible. Por ejemplo.

typedef void (*functiontype)(); 

Declara una función que devuelve vacío y no toma argumentos.Para crear un puntero de función a este tipo ahora se puede hacer:

void dosomething() { } 

functiontype func = &dosomething; 
func(); 

Para una función que devuelve un int y toma un char que haría

typedef int (*functiontype2)(char); 

y utilizarlo

int dosomethingwithchar(char a) { return 1; } 

functiontype2 func2 = &dosomethingwithchar 
int result = func2('a'); 

Hay bibliotecas que pueden ayudar a convertir los punteros a tipos de letra agradables. ¡La biblioteca boost function es excelente y bien vale la pena!

boost::function<int (char a)> functiontype2; 

es mucho mejor que el anterior.

+0

Si quiere "convertir un puntero de función en un tipo", no necesita la biblioteca de impulso. Solo usa 'typedef'; es más simple y no requiere ninguna biblioteca adicional. – wizzwizz4

40

Desde C++ 11 puede usar functional library para hacer esto de manera breve 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 una sola argumento cuyo primer argumento es de tipo int.

he incluido a continuación un programa de ejemplo:

// 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); 
} 

veces, sin embargo, es más conveniente utilizar 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); 
} 
+20

La pregunta es sobre C; C++ no se aplica aquí. –

+8

La pregunta para C++ (http://stackoverflow.com/questions/6339970/c-using-function-as-parameter) se menciona aquí, por lo que creo que esta respuesta está en su lugar. –

7

Pass dirección de una función como parámetro a otro función como se muestra a continuación

#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 función como parámetro utilizando función de puntero

#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(); 
} 
Cuestiones relacionadas