функция от функции (вложенной) - си

Искала, как задать функцию от функции.

Вопросы:

  • правилен ли вариант 1,
  • можно ли пользоваться вариантом 2,
  • и если оба неправильные (то есть могут привести к ошибкам), то как надо писать?

Чтобы работало и в C, и в C++, и не только с gcc.

В кн. Кернигана, Ричи "Язык программирования си" 2009 на стр 131 есть пример, но там не очень ясно:

comp — указатель на функцию, (*comp) — сама функция.

Определения функции (*comp) в книге не нашла.

Попыталась написать простой пример, максимально приближенный к книге: вариант 1.

Первая функция - сумма, вторая - квадрат первой.

Но работает (eclipse, gcc, просто C) и так, как во втором варианте: в конце main в printf внутренняя функция вызывается просто как f3, без звездочек.

вариант 1:

int main(int argc, char *argv[]) {
    int a = 2, b = 4;
    int f1(int, int);                                         
    int f2(int x1, int x2, int (* pointer_to_f1)(int, int));  
    int (*p_f1) (int, int);      
    p_f1 = f1;                   
    printf("f2 = %i \n", f2(a, b, p_f1)   );  

    return 0;
};

int f1 (int x1, int x2) {
    return (x1 + x2);
};

int f2(int x1, int x2, int (* pointer_to_f1)(int x1, int x2)) {   
    return ((* pointer_to_f1)(x1, x2)  *  (* pointer_to_f1)(x1, x2));
};

вариант 2:

int main(int argc, char *argv[]) {
    int c = 4, d = 4;
    int f3(int, int);                        
    int f4(int x1, int x2, int f3(int, int));
    printf("f4 = %i \n", f4(c, d, f3)   );  
    return 0;
};

int f3 (int x1, int x2) {
    return (x1 + x2);
};

int f4(int x1, int x2, int f3 (int x1, int x2)) {    
    return (f3(x1, x2)  *  f3(x1, x2));
};

Ответы (2 шт):

Автор решения: Ма Пр

Сделала как могла примерно так, как на странице по Вашей ссылке (https://en.cppreference.com/w/c/algorithm/qsort), так правильно?

int f5 (int x1, int x2) {   
    return (x1 + x2);       
};

int f6(int x1, int x2, int (* pointer_to_f5) (int x1, int x2)) { 
    return (* pointer_to_f5)(x1, x2)  *  (* pointer_to_f5)(x1, x2);
};  // обязательно ли тут писать "(* pointer_to_f5)" (можно ли просто "f5"?)

int main(int argc, char *argv[]) {
    int e = 5, f = 4;
    printf("f6 = %i \n", f6(e, f, f5)   );
    return 0;
};

(но так не получается объявлять в main f5 и f6, если их текст пишу ниже main, то есть всегда удобнее, чтобы main была внизу?)

→ Ссылка
Автор решения: LolPopGames

Оба варианта в вопросе являются полностью правильными

Разберём первый, там станет понятно:

Строчки:

int f1(int, int);                                         
int f2(int x1, int x2, int (* pointer_to_f1)(int, int));

объявляют 2 прототипа (которые обычно принято писать вне определения функций)

И мы даём «обещание»:

«Где-нибудь позже (или раньше) в коде я дам определение этой функции»

Далее в коде:

int (*p_f1) (int, int);      
p_f1 = f1;

Объявляется и инициализируется указатель на функцию (то есть это переменная, занимающая в памяти 2 или 4 байта (в зависимости от архитектуры и компилятора), и она хранит адрес, по которому можно обратиться к функции)

Сперва мы объявляем по синтаксису:

возвращаемый_тип (*имя_указателя)(типы_аргументов)

А потом инициализируем:

p_f1 = f1;
//     ^ из-за того что мы указали без скобок ( f1() ), мы получим адрес функции

Лично я, когда хочу получить адрес функции, обычно добавляю & перед названием (в данном случае будет &f1 (означает одно и тоже))

Ну а указатель на функцию в строчке:

printf("f2 = %i \n", f2(a, b, p_f1)   );

мы передаём как любой другой указатель

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

printf("f2 = %i \n", f2(a, b, f1)   );
//                            ^ или &f1, одно и тоже

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

(*имя_указателя)(параметры)

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

имя_указателя(параметры)

Все вышеперечисленное допустимо и не является ошибкой или особенностью, которую поддерживает, например, только gcc

→ Ссылка