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

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

Ответов (8)

Решение

Декларация

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

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. Сначала рассмотрим, как будет выглядеть цикл при прямом вызове print:

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

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

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

Источник

Вам нужно передать указатель на функцию . Синтаксис немного громоздкий, но он действительно эффективен, как только вы с ним познакомитесь.

Начиная с C++ 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);
}

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

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

Функции могут быть «переданы» как указатели на функции, в соответствии с ISO C11 6.7.6.3p8: Объявление параметра как« тип возвращающей функции »должно быть скорректировано на« указатель на тип, возвращающий функцию , как в 6.3. .2.1. ". Например, это:

void foo(int bar(int, int));

эквивалентно этому:

void foo(int (*bar)(int, int));

На самом деле это не функция, но это локализованный фрагмент кода. Конечно, он не передает код только результат. Он не будет работать, если будет передан диспетчеру событий для запуска позже (поскольку результат рассчитывается сейчас, а не при возникновении события). Но он локализует ваш код в одном месте, если это все, что вы пытаетесь сделать.

#include <stdio.h>

int IncMultInt(int a, int b)
{
    a++;
    return a * b;
}

int main(int argc, char *argv[])

{
    int a = 5;
    int b = 7;

    printf("%d * %d = %d\n", a, b, IncMultInt(a, b));

    b = 9;

    // Create some local code with it's own local variable
    printf("%d * %d = %d\n", a, b,  ( { int _a = a+1; _a * b; } ) );

    return 0;
}

Я собираюсь объяснить это на простом примере кода, который принимает compare функцию как параметр другой sorting функции. Допустим, у меня есть функция пузырьковой сортировки, которая принимает настраиваемую функцию сравнения и использует ее вместо фиксированного оператора if.

Функция сравнения

bool compare(int a, int b) {
    return a > b;
}

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

Функция пузырьковой сортировки

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

Наконец, main вызывающий функцию пузырьковой сортировки, передавая логическую функцию сравнения в качестве аргумента.

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] << " ";
    }
}

Выход:

Sorted Order
3 6 8 11 12 12 15 18 20 22

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

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<int (char a)> functiontype2;

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