Function Pointers on "C++ Primer Plus" Confusing Me

Here is what is confusing me:

1
2
3
const double * f1(const double ar[], int n);
const double (*f2)(const double ar[], int n);
const double f3(const double ar[], int n);


What is the difference between the first and second function?

From my eyes, the first function(f1) is a function that returns a pointer of type double with the function name of f1.
The second function(f2) returns type double and I have no idea what (*f2) in this definition.
The third function is just a regular function returning type double with the name of f3.

const double *(*p1)(const double *, int) = f1;
I am just mind boggled of how this looks. I can see that "const double *" represents that it is a pointer of type double, but the name (*p1) yet again confuses me. I know in the end though that all it does is point to f1, I just don't understand how it looks.
Last edited on
This

const double (*f2)(const double ar[], int n);

is a definition of pointer to function that has return type const double and has two parameters of type const double [] and int.

This

const double *(*p1)(const double *, int) = f1;

is a definition of pointer to function that has return type const double * and has the same parameters as in the definition above. This pointer is initialized by the address of the function f1.

Last edited on
Okay so I made a function:

1
2
3
4
5
const int * add(int a, int b)
{
	int * ptr = new int (a + b);
	return ptr;
}


The program compiles but logically, would this be valid? Since in this example it returns a type int * instead of a const int *?
I have not understood how this question is related with the previous question.
As for this function definition I do not see any sense to return const int * do not seeing the context where such a function can be used. So if to speak about the logical validity we should know relative which context it is logically valid.
Last edited on
What I meant was, I was just wondering(from my previous post) in the terms of "valid" that if I should be returning a int * or const int * because shouldn't the return value match the type definition?


Sorry about the relativity to the first question, I am currently learning about function pointers at the current moment and just a little confused about it especially the pointer to pointer parts.

I understand that const double *(*p1)(const double *, int) = f1; has a return value type of const double * but why is the * in p1 needed? What if I took it out? How would that be read to the C++ compiler? What would the C++ compiler think?
Last edited on
As i said it depends on the purpose of the function.
As for the C++ compiler then it does not think. It simply compiles your code.
Okay, well what would my compiler see that as, not in terms of sight, but logic, if I were to write the following code: const double * p1(const double *, int) saying I no longer want p1 to be a pointer.

With that code the compiler lets me compile it, but when I try to initialize it to something, it says "p1 may not be initialized". So what is happening there?
Last edited on
I have understood nothing. The compiler will say nothing. It simply will compile the function definition because it satisfies the C++ syntax.

EDIT: you may not to use the same identifies for an object and for a function name in the same declaration region. So the compiler will issue an error if p1 will be defined as a function pointer and a function name at the same time.
Last edited on
> const double *(*p1)(const double *, int) = f1;
> I am just mind boggled of how this looks. I can see that "const double *" represents that it is a ptr of type double,
> but the name (*p1) yet again confuses me.

Let us look at this from first principles.

int foo(double) ;

foo is a function which takes one parameter of type double and returns a value of type int.
foo has a type; it is 'unary function taking a parameter of type double and returning an int' or simply int(double)

int bar(double) ;

foo and bar are of the same type.

1
2
3
int* baz(double) ;
int *baz(double) ;
int * baz(double) ;


baz is also a function, but the type of baz is different; it is int*(double), it returns a pointer to int.
It does not matter how you place white space while writing baz, the * binds to the left.

Now, say, we wand to define a pointer to a function which can point to foo.
The type of the ptr that we need is 'pointer to int(double)'
ie. 'pointer to unary function taking a parameter of type double and returning an int'

This won't do at all: int *ptr(double) ;
Here, ptr is of the same type as baz; the * binds to the int; we might as well have written int* ptr(double) ;

Instead, we want the * to bind to ptr; to say that ptr is a pointer.

We can do this in two ways.

One, create a type alias for the type of the function foo:

1
2
3
typedef int type_of_foo(double) ;
using type_of_foo = int(double) ; // C++11
using type_of_foo = decltype(foo) ; // C++11 


type_of_foo is an alias, another name by which we can refer to int(double), the type of the function.

And now, we can write

type_of_foo* ptr = &foo ; // type of ptr is 'pointer to int(double)'

ptr is a pointer to a function, and it is initialized to point to foo.

ptr = &bar ; this too is fine, bar is a function of the same type, and ptr now points to bar.

The other (somewhat clumsier) way is to use parantheses to change the binding of the *

int (*ptr)(double) = &foo ; // type of ptr is 'pointer to int(double)'

Because of the paranthesis, the * binds to ptr and not to int.



> The program compiles but logically, would this be valid?
> Since in this example it returns a type int * instead of a const int *?

For an implicit conversion, a (top level) const qualifier may be added.
If T is some type, there is an implicit conversion from T* to const T*

1
2
3
int i = 7 ;
int* p = &i ;
const int* pc = p ; // fine, conversion adds the const qualifier 


However, a const qualifier can't be dropped implicitly.

p = pc ; // *** error, conversion requires dropping the const qualifier
Last edited on
Function pointer is a variable. It is not a function. The value that it holds is an address of a function. When one does have condition that determines what to do:
1
2
3
4
5
6
7
8
9
10
11
for ( size_t i = 0; i < Count; ++i )
{
  if ( test )
  {
    result = foo( i * 42.0 );
  }
  else
  {
    result = bar( i * 42.0 );
  }
}

One could rearrange code to:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
if ( test )
{
  for ( size_t i = 0; i < Count; ++i )
  {
    result = foo( i * 42.0 );
  }
}
else
{
  for ( size_t i = 0; i < Count; ++i )
  {
    result = bar( i * 42.0 );
  }
}

Or, one could use a function pointer:
1
2
3
4
5
6
int (*ptr)(double) = test ? &foo : &bar;

for ( size_t i = 0; i < Count; ++i )
{
  result = ptr( i * 42.0 );
}


Callback can make use of function pointers. You can have a library code that you cannot change, but you should be able to customize it somehow, for the library cannot possibly know what you are up to. Therefore, the library function takes your function as function pointer and "calls back", i.e. executes your code.

Function pointers are standard C, but C++ has "classes" too that allow more ways to achieve similar things. Polymorphism and objects that behave like functions. Plenty of the C++ standard library algorithms accept function objects (aka functors). Callbacks.
"C++ Primer Plus", you say? This book has a significantly bad review. Try "C++ Primer", which is by a different author and has a much better review.
Topic archived. No new replies allowed.