Функция как результат другой функции

Последнее обновление: 22.01.2024

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

Например, нам надо выбрать и выполнить одну из трех арифметических операций

#include <stdio.h>

int sum(int x, int y)
{
    return x + y;
}
int subtract(int x, int y)
{
    return x - y;
}
int multiply(int x, int y)
{
    return x * y;
}

//  int choice - выбранный пункт
int (*select(int choice))(int, int)
{
    // возвращаем нужную функцию
    switch (choice)
    {
        case 2:
            return subtract;
        case 3:
            return multiply;
        default:
            return sum;
    }
}
int main(void)
{
    int (*operation)(int, int);    // указатель на выбранную функцию
    operation = select(1);  // получаем указатель на функцию sum - сложение
    int result = operation(6, 4); // выполняем функцию
    printf("result: %d \n", result); // result: 10

    return 0;
}

В данной программе мы предполагаем, что пользователь должен выбрать для выполнения одну из трех функций: sum, subtract, multiply, каждая из которых представляет определенное действие.

Все выбираемые функции имеют один и тот же прототип вида:

int operation(int, int);

То есть возвращают значение типа int и принимают два параметра типа int.

Сам выбор происходит в функции select(). Она возвращает указатель на функцию - по сути выбранную функцию. Посмотрим на ее заголовок:

int (*select(int choice))(int, int)

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

тип_указателя_на_функцию (*select(параметры_функции))(параметры_указателя_на_функцию)

То есть сначала идет возвращаемый тип функции, на который возвращается указатель (в данном случае int)

Далее в скобках идет название самой функции и ее параметры - (*select(int choice)). То есть функция select, которая возвращает указатель на функцию, принимает один параметр - choice - условный номер арифметической функции.

Зтаем идут типы параметров функции, указатель на которую возвращается: (int, int)

То есть в итоге функция select() имеет один параметр choice, который представляет тип int, и возвращает указатель на функцию, которая имеет прототип int action(int, int).

В самой функции select() в зависимости от значения параметра choice возвращаем определенную функцию:

switch (choice)
{
    case 2:
        return subtract;
    case 3:
        return multiply;
    default:
        return sum;
}

В функции main сначала определяем указатель, который соответствует прототипу арифметических функций sum, subtract, multiply:

int (*operation)(int, int);

Далее в этот указатель получаем результат из функции select, передав в нее номер функции:

operation = select(1);

По номеру 1 функция select возвращает функцию sum. Соответственно переменная-указатель operation будет хранить адрес функции sum.

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

int result = operation(6, 4); // выполняем функцию

Подобным образом можно получить и другие функции:

int main(void)
{
    int (*operation)(int, int) = select(2);  // получаем указатель на функцию subtract
    printf("result: %d \n", operation(6, 4)); // result: 2

    operation = select(3);  // получаем указатель на функцию multiply
    printf("result: %d \n", operation(6, 4)); // result: 24
    return 0;
}

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

#include <stdio.h>
 
typedef int (binary_op)(int, int);

int sum(int x, int y) { return x + y;}
int subtract(int x, int y) { return x - y;}
int multiply(int x, int y) { return x * y;}

int operation(binary_op op, int a, int b){ return op(a, b);}

//  int choice - выбранный пункт
binary_op* select(int choice)
{
    // возвращаем нужную функцию
    switch (choice)
    {
        case 2:
            return &subtract;
        case 3:
            return &multiply;
        default:
            return ∑
    }
}
int main(void)
{
    binary_op* operation = select(1);  // получаем указатель на функцию sum - сложение
    int result = operation(6, 4); // выполняем функцию
    printf("result: %d \n", result); // result: 10

    return 0;
}

В данном случае сначала определяем псевдоним binary_op для функции, которая принимает два параметра типа int и возвращает значение типа int:

typedef int (binary_op)(int, int);

Затем мы можем использовать этот тип (или указатель этого типа) в качестве типа результата функции:

binary_op* select(int choice)
{ 
    ..................
}

В функции main получаем указатель на возвращенную функцию в пепеменную operation и вызываем ее:

binary_op* operation = select(1);
int result = operation(6, 4);
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850