Как вы передаете функцию в качестве параметра в C?

429

Я хочу создать функцию, которая выполняет функцию, переданную параметром в наборе данных. Как передать функцию в качестве параметра в C?

  • 9
    Если вы используете функции / массивы в качестве переменных, ВСЕГДА используйте typedef .
  • 2
    Мы называем это указатель на функцию
Показать ещё 4 комментария
Теги:
pointers
function
syntax
parameters

5 ответов

589
Лучший ответ

Декларация

Прототип функции, которая принимает параметр функции, выглядит следующим образом:

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

Это означает, что параметр f будет указателем на функцию, которая имеет возвращаемый тип void и принимает один параметр int. Следующая функция (print) является примером функции, которая может быть передана в func в качестве параметра, потому что это правильный тип:

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

Вызов функции

При вызове функции с параметром функции переданное значение должно быть указателем на функцию. Для этого используйте имя функции (без круглых скобок):

func(print);

вызовет func, передав ему функцию печати. ​​

Тело функции

Как и любой параметр, func теперь может использовать имя параметра в теле функции для доступа к значению параметра. Скажем, что func применит функцию, которую она передаст к номерам 0-4. Рассмотрим, во-первых, что цикл будет выглядеть так, чтобы называть печать напрямую:

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

Так как объявление параметра func говорит, что f - это имя указателя на нужную функцию, напомним сначала, что если f является указателем, то *f - это то, что указывает f ( т.е. функция print в этом случае). В результате просто замените каждое появление печати в цикле выше с помощью *f:

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

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

  • 32
    В вашем первом и последнем примерах кода * не является обязательным. И определение параметра функции, и вызов функции f могут принимать f же, как и без *. Возможно, было бы неплохо сделать это так, как вы, чтобы было очевидно, что параметр f является указателем на функцию. Но это часто ухудшает читабельность.
  • 5
    См. [C99, 6.9.1§14] для примеров. И то и другое верно, я просто хотел упомянуть альтернативу.
Показать ещё 10 комментариев
95

У этого вопроса уже есть ответ для определения указателей функций, однако они могут стать очень грязными, особенно если вы собираетесь передавать их вокруг своего приложения. Чтобы избежать этой неприятности, я бы рекомендовал вам ввести указатель функции во что-то более читаемое. Например.

typedef void (*functiontype)();

Объявляет функцию, которая возвращает void и не принимает аргументов. Чтобы создать указатель на этот тип, вы можете:

void dosomething() { }

functiontype func = &dosomething;
func();

Для функции, которая возвращает int и принимает char, вы сделали бы

typedef int (*functiontype2)(char);

и использовать его

int dosomethingwithchar(char a) { return 1; }

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

Существуют библиотеки, которые могут помочь с превращением указателей функций в удобочитаемые типы. Функция boost function является отличной и заслуживает внимания!

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

намного лучше, чем выше.

  • 1
    Если вы хотите «превратить указатель функции в тип», вам не нужна библиотека boost. Просто используйте typedef ; это проще и не требует дополнительных библиотек.
40

С С++ 11 вы можете использовать функциональную библиотеку чтобы сделать это кратким и общим способом. Синтаксис, например,

std::function<bool (int)>

где bool - тип возврата здесь функции с одним аргументом, первый аргумент которой имеет тип int.

Я привел пример программы ниже:

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

Иногда, однако, удобнее использовать функцию шаблона:

// 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);
}
  • 25
    Вопрос о С; C ++ здесь не применяется.
  • 12
    Вопрос для C ++ ( stackoverflow.com/questions/6339970/… ) упоминается здесь, поэтому я думаю, что этот ответ на месте.
Показать ещё 1 комментарий
6

Передайте адрес функции как параметра в другую функцию, как показано ниже

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

Также мы можем передать функцию как параметр, используя указатель функции

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню