¿Cómo se pasa una función como parámetro en C?

8 minutos de lectura

avatar de usuario
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?

  • 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)) y void (*funcA())() para typedef void funcB(); void funcA(funcB) y funcB 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 y bsearch para ver ejemplos de cómo se hace esto.

    – Bob Jarvis – Слава Україні

    15 de febrero de 2021 a las 12:45

avatar de usuario
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 funcpasá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 funcLa 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);
  }
}

Fuente

  • 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 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 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

avatar de usuario
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

avatar de usuario
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

avatar de usuario
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();
}

avatar de usuario
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));

avatar de usuario
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.

¿Ha sido útil esta solución?