5

I have read about syntax of function pointers and I can't make to work in my code.

This video explains that the syntax is:

type func0(type0 arg0, ..., typen argn){
    // do something
    return a_thing;
}

Then for passing function pointers in another function is:

type func1((*func0)(type0 arg0, ..., typen argn), another args){  
    //do something
    func0(arg0, ..., argn);    
    return a_thing;
}

But then, I read the first answer about How do function pointers in C work?, and the syntax is:

type func1((*func0)(type0 arg0, ..., typen argn), another args) {    
    //do something
    (*func0)(arg0, ..., argn);
    return a_thing;
}

which makes sense because you are dereferencing the pointer, which you are passing. Lastly, the first answer in C function pointers invocation syntax explain that the syntax can be:

&func
func
*func
**func

and I don't understand which info is correct. I have the code:

double *func1((*func0)(double), double *var) {
    double *temp = malloc(some_size);
    for(int i = 0; i < some_cycles; ++i) {
        temp[i] = (*func0)(var[i]);
    }
    return temp;
}

And it throws the error a value of type "double *" cannot be assigned to an entity of type "double"

EDIT:

For anyone wanted to see the real code, was that:

tensor_t *applyBinOpTensor(double *(operation)(double, double), tensor_t *tensor, double operand){

    size_t total_size = indiceProduct(*tensor->shape);
    double *values = malloc(total_size * sizeof(*values));

    for(size_t i = 0; i < total_size; ++i){
        values[i] = (*operation)(tensor->values[i], operand);
    }
    return initializeTensor(values, tensor->shape);
}

As you can see, all the problem was that I typed double *(operation)(double, double) instead of double (*operation)(double, double).

Thanks to all for your answers. I learned a lot, and sorry for my misspeling.

7
  • 3
    Please edit and show a minimal reproducible example Commented Jan 24, 2024 at 12:17
  • 1
    Wher is function return type? And thorw the error the code you presented is missing }} and #include <stdlib.h>. Could you please post real full code example? Commented Jan 24, 2024 at 13:09
  • 1
    Please try to write syntactilly correct code. Your code has unmatched curly braces { in the wierdest places, so it is impossible to be sure what you mean. And please indent your code correctly. Commented Jan 24, 2024 at 13:10
  • I have this question that's kind of related. Might be worth a read too: C++ Function call via an object with public member pointer to function, without using dereference operator. The function pointer call syntax is really interesting. See the bottom of my question. Commented Jan 24, 2024 at 17:11
  • @KamilCuk #include <stdlib.h> is in my code. I already posted the example in the question. It's the last onwe Commented Jan 24, 2024 at 23:07

5 Answers 5

4

To pass a function pointer to a function is relatively easy.

Given some function pointer:

int (*fptr) (int, double);

Just squeeze the same syntax into the parameter list:

void some_func (int some_param, int (*fptr)(int, double), int some_other_param);

It turns more confusing when you try to return a function pointer. Lets take the above function and move the function pointer from the parameter list to the return type:

int (*some_func(int some_param, int some_other_param)) (int, double);

Yep, unreadable gibberish...


Now what can we actually learn from this?

  • Whoever invented the function pointer syntax in C were confused.
  • People who write code like the above are confused.
  • People who try to learn function pointer syntax will get confused.
  • If you have actually learnt the syntax, you have spent way too much time on nonsense, that could have been spent on better things.

Always use typedef. Period.

typedef int func_t (int, double);

void some_func (int some_param, func_t* fptr, int some_other_param);

func_t* some_func (int some_param, int some_other_param);
Sign up to request clarification or add additional context in comments.

4 Comments

If I could upvote this more than once I would. I learned to use a typedef fairly early on and so have never been able to read function pointer syntax. I regard that as time well not spent.
Upvoted. For function typedefs though, I prefer typedefing to a function pointer, not a function, since functions automatically adjust to pointers anyway, and have no real "copy by value" concept I'm aware of. So I'd recommend this: typedef int (*func_t)(int, double);. Then, I'd use it in functions as void some_func(func_t func);, or func_t some_func();. And whether you do a call as some_func(my_func); or some_func(&my_func); makes no difference, since taking the address is optional due to the automatic adjustment of a function to a function pointer.
Very informative. Thanks. I'd accept this answer because its the more voted, but the other replies are also good.
@GabrielStaples Hiding a pointer behind a typedef is bad practice since it makes the code harder to read. Not doing so makes the function pointer syntax 100% equivalent with object pointer syntax. Particularly in terms of qualifiers. With a pointer hidden behind a typedef, fptr const is confusing and will trip most readers of your code. Whereas fptr* const is perfectly readable.
2

They are best understood from a syntactical perspective. Say you have the functions foo and bar, sharing a common prototype:

int foo(float a, double b);
int bar(float c, double d);

Now we can declare a function pointer of type int (*)(float, double):

int (*fptr)(float, double) = NULL;

Now, fptr can be assigned foo or bar:

fptr = foo;
...
fptr = bar;
fptr(2.0f, 3.0); /* indirect function call through the pointer */
(*fptr)(2.0f, 3.0); /* same */

For convenience, you can typedef that type to avoid having to type int (*)(float, double) all over the place:

typedef int (*fptr_t)(float, double);

After this, fptr_t will be a shorthand type for a function pointer with such a prototype.

1 Comment

Thanks for your reply. I liked your typedef
1

But then, I read the firss answer about How do function pointers in C work?, and the syntax is:

type func1((*func0)(type0 arg0, ..., typen argn), another args){

//do something
(*func0)(type0 arg0, ..., typen argn);

return a_thing;
}

No, syntax for function call via the function pointer is invalid. You want to pass something to it, not de declare function pointer again. Also you miss the return type of the function in function pointer parameters declaration

 type func1(type1 (*func0)(type0 arg0, ..., typen argn), another args){

 func0(par1, ..., parn);

you can also use this form

 (*func0)(par1, ..., parn);

as they equivalent.

and I dont understand which info is correct. I have the code:

double *func1((*func0)(double), double *var){
    double *temp = malloc(some_size);

    for(int i = 0; i < some_cycles; ++i){    
         temp[i] = (*func)(var[i]);

    return temp;

Your function pointer parameter is called func0 and you use func. Also the function parameter declaration is invalid as it requires the return value too. The correct function definition:

#define some_cycles 10

double *func1(double (*func0)(double), double *var)
{
    double *temp = malloc(some_cycles * sizeof(*temp));

    for(int i = 0; i < some_cycles; ++i){
        temp[i] = func0(var[i]);
    }

    return temp;
}

Comments

1

How to make the question code executable

I have tested your code and made some changes to it so that it can be executed:

#include <stdlib.h>
#include <stdio.h>

int some_cycles = 10;

//*********************************************************
// I HAVE ADDED THIS FUNCTION TO PASS IT AS FIRST ARGUMENT
// OF YOUR FUNCTION func1
//*********************************************************
double f(double d) {
    d++;
    return d;
}

//*********************************************************
// THIS IS YOUR FUNCTION
//*********************************************************
double *func1(double (*func0)(double), double *var){
    double *temp = malloc(some_cycles * sizeof(double));

    for(int i = 0; i < some_cycles; ++i){
        temp[i] = (*func0)(var[i]);
    }

    // I HAVE ADDED THE FOLLOWING for loop WITH printf() TO THE BODY
    // OF YOUR FUNCTION TO SHOW THE CONTENT OF THE LOCAL ARRAY temp
    for(int i = 0; i < some_cycles; ++i){
        printf("%f\n", temp[i]);
    }

    return temp;
}


//*********************************************************
// THIS IS THE MAIN FUNCTION
//*********************************************************
int main (int argc, char **argv) {
    double var[] = {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0};
    func1(f, var);
    return 0;
}

The output of the code execution

If you compile and execute the previous code the output is:

1.000000
2.000000
3.000000
4.000000
5.000000
6.000000
7.000000
8.000000
9.000000
10.000000

Errors in the question code

I would like to highlight two errors in your code:

1. you have to use func0 in the body of your for loop (and not func which is not declared anywhere)

2. you missed the type double in the definition of the first argument of the function func1; so you have to use:

double (*func0)(double)

and not:

(*func0)(double)

Comments

0

Then for passing function pointers in another function is:


func0(type0 arg0, ..., typen argn);

No, to call a function, you use only the arguments, not the types:

func0(arg0, ..., argn);

Lastly, the first answer in [C function pointers invocation syntax][3] explain that the syntax can be:

&func
func
*func
**func

Any of these will work. The specified operand for a function call is a pointer to a function, so &func(arguments) is the “most direct” way to use the function call operator, (…). However, functions are automatically converted to pointers to functions. So func(arguments) works because it is automatically converted to &func(arguments).

The rule is that whenever a function is used in an expression other than has the operand of sizeof (which causes an error) or as the operand of unary &, it is converted to a pointer to the function (C 2018 6.3.2.1 4). This is also why you can use *func and **func. In (*func)(arguments), func is not the operand of sizeof or &, so it is converted to a pointer to the function. Then * takes the pointer and produces what it references, which is the function. Then this function is also not the operand of sizeof or &, so it is also converted to a pointer to the function. The result is as if the code were <code>&func(<i>arguments</i>)</code>, which is correct for a function call.

Similarly, in (**func)(arguments), this automatic conversion occurs three times. No matter how many times you apply *, the result will be automatically converted back to a pointer to the function.

I have the code:

double *func1((*func0)(double), double *var){

double *temp = malloc(some_size);

for(int i = 0; i < some_cycles; ++i){
temp[i] = (*func)(var[i]);

You have some mistake in posting this code, because there is no func declared before (*func)(var[i]), and there is a missing }. The error message you are getting looks like attempting to use some function declared to return double *, which func1 is declared to return. You will need to fix up the code in the question before the error can be explained.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.