C + + delves into function pointers

Basic knowledge of function pointer

The address of a function is the starting address of the memory where its machine language code is stored.

How to use function pointers:

  • Get the address of the function
  • Declare a function pointer
  • Use function pointers to call functions

Get function address

Get the function address, just use the function name.

think(); // function
think   // Function address
process(think);   //Pass the address of the think function
process(think());  //  Pass the return value of the think function

Declare function pointer

Declaring a function pointer is the same as declaring a data type pointer. You must specify the function type pointed to by the pointer, that is, the return type and the characteristic (parameter list).

double pam(int);    // prototype function
double (*pf)(int);   // Declare function pointer

void estimate(int lines, double (*pf)(int));  // Declared in parameter

It can be understood here that (* pf) replaces pam,

(* pf) is the function name,

pf is the function pointer.

Note the parentheses:

double (*pf)(int);   // Function pointer
double *pf(int);     // pf is a function that returns a double pointer

Function pointer call function

(* pf) plays the same role as the function name, which can be regarded as the function name

double pam(int);
double (*pf)(int);
pf = pam;    // pf points to the pam() function
double x = pam(4);   // Function name call
double y = (*pf)(5);   // Function pointer call
 actually, C++Allow direct use pf call
double y = pf(5);   // Function pointer call, the effect is the same as above

Example:

// fun_ptr.cpp -- pointers to functions
#include <iostream>
double betsy(int);
double pam(int);


// second argument is pointer to a type double function that
// takes a type int argument
void estimate(int lines, double (*pf)(int));


int main()
{
	using namespace std;
	int code;
	cout << "How many lines of code do you need? ";
	cin >> code;
	cout << "Here's Betsy's estimate:\n";
	estimate(code, betsy);
	cout << "Here's Pam's estimate:\n";
	estimate(code, pam);
	return 0;
}

double betsy(int lns)
{
	return 0.05 * lns;
}

double pam(int lns)
{
	return 0.03 * lns + 0.0004 * lns * lns;
}

void estimate(int lines, double (*pf)(int))
{
	using namespace std;
	cout << lines << " lines will take ";
	cout << (*pf)(lines) << " hour(s)\n";
}

Explore function pointers in depth

Take a look at the function prototypes below. They have the same return type and signature

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

The feature marks look different, but they are actually the same

If you need to declare a function pointer pointing to the above function, such as the pointer name pa, you can replace the function name with (* pa).

const double * (*p1)(const double *, int n);

Initialize while declaring
const double * (*p1)(const double *, int n) = f1;

utilize C++11 Automatic type inference can simplify code
auto p2 = f2;

Next, let's look at the following statement:

cout << (*p1)(av, 3) << ": " << *(*p1)(av, 3) << endl;
cout << p2(av, 3) << ": " << *p2(av, 3) << endl;

It can be seen from the previous introduction of basic knowledge that (* p1)(av, 3) and p2(av, 3) are the calls of functions f1() and f2() respectively, and av (double array) and 3 are parameters.

The return value type of the function const double * (i.e. the address of the return value), plus a *, you can get the actual return value.

(*p1)(av, 3)   // Call f1() to return an address
p2(av, 3)      // Call f2() to return an address

*(*p1)(av, 3)   // Return value of f1()
*p2(av, 3)      // Return value of

Function pointer array

Given the need to use three functions, it is much more convenient to declare an array of function pointers. The statement is as follows:

const double * (*pa[3])(const double * , int) = {f1, f2, f3};   // Declaration and initialization

**Note: * operator [] takes precedence over, pa[3] is an array containing three elements, and * pa[3] is an array containing three pointers.

Can I use auto here? No. Auto can only be used for single value initialization, not initialization list. However, after declaring the array pa, you can use Auto to declare arrays of the same type.

auto pb = {f1, f2, f3};     // error
auto pb = pa;               // correct

pa[i] and pb[i] represent pointers in an array, so you can use any function call notation for them

const double * px = pa[0](av, 3);  //Call function
const double * py = (*pb[1])(av, 3);  // Call function

To get the actual return value, you can use the operator*

double x = *pa[0](av, 3);
double y = (*pb[1])(av, 3);

Pointer to array of function pointers

You can also create pointers to the entire array. First, the array name is a pointer (pointing to the first element), and pa contains three function pointers, so the array name pa is a pointer to the function pointer. That is, pa is a pointer to a pointer. In addition, because it is a single value initialization, you can use auto.

auto pc = &pa;   // Using c+11 characteristics

You can declare it yourself without using auto. At this point, you need to declare that this is a pointer, not an array, which means you need to add an operator * somewhere.

*pd[3] indicates that pd is an array containing three pointers

*(pd)[3] represents pd a pointer to an array containing three elements

Therefore, my statement is as follows

const double * (*pa[3])(const double *, int) = {f1, f2, f3};
const double * (*(*pd)[3])(const double *, int) = &pa;   // Change pa to (* pb)

======================
const double *           // return type
(const double * , int)   // For parameter list
(*pd)[3]      // pd is a pointer to an array of three elements
(*(*pd)[3])   // pd is a pointer to an array of three pointers
const double * (*(*pd)[3])(const double * , int)  
              // pd is a pointer to an array of three function pointers

There are two ways to call functions

(*(*pd)[3])(av , 3);  
// or
(*pd)[3](av , 3);

At this time, the return address of the function, that is, the pointer. To obtain the return value of the calling function, you can use the operator*

*(*(*pd)[3])(av , 3);
// or
*(*pd)[3](av , 3);

Note: the difference between pa and & pa. pa is an array name. Namely & pa [0]

**&pa == *pa == pa[0]

Example:

// arfupt.cpp -- an array of function pointers
#include <iostream>
// various notations, sam signatures
const double* f1(const double ar[], int n);
const double* f2(const double[], int n);
const double* f3(const double*, int);

int main()
{
	using namespace std;
	double av[3] = { 1112.3, 1542.6, 2227.9 };

	// pointer to a function
	const double* (*p1)(const double*, int) = f1;  // Pointer F1 to function declaration ()
	auto p2 = f2;  //  c++11 automatic type deduction

	cout << "Using pointers to functions:\n";
	cout << " Address Value\n";
	cout << (*p1)(av, 3) << ": " << *(*p1)(av, 3) << endl;  // Return value address: return value

	//pa an array of pointers    
	const double* (*pa[3])(const double*, int) = {f1, f2, f3}; // Function pointer array

	auto pb = pa;

	cout << "\nUsing an array of pointers to functions:\n";
	cout << " Address Value\n";
	for (int i = 0; i < 3; i++)
	{
		cout << pa[i](av, 3) << ": " << *pa[i](av, 3) << endl;
	}
	cout << "\nUsing an array of pointers to functions:\n";
	cout << " Address Value\n";
	for (int i = 0; i < 3; i++)
	{
		cout << pb[i](av, 3) << ": " << *pb[i](av, 3) << endl;
	}


	cout << "\nUsing an array of pointers to functions:\n";
	cout << " Address Value\n";
	// a easy to declare pc
	auto pc = &pa;         // Pointer to function pointer array
	cout << (*pc)[0](av, 3) << ": " << *(*pc)[0](av, 3) << endl;

	// a hard way to declare pd
	const double* (*(*pd)[3])(const double*, int) = &pa;  // Pointer to function pointer array
	const double* pdb = (*pd)[1](av, 3);
	cout << pdb << ": " << *pdb << endl;
	cout << (*(*pd)[2])(av, 3) << ": " << *(*(*pd)[2])(av, 3) << endl;

	return 0;
}

const double* f1(const double ar[], int n)
{
	return ar;
}
const double* f2(const double ar[], int n)
{
	return ar+1;
}
const double* f3(const double ar[], int)
{
	return ar + 2;
}

Output results

Using pointers to functions:
 Address Value
000000370F72F908: 1112.3

Using an array of pointers to functions:
 Address Value
000000370F72F908: 1112.3
000000370F72F910: 1542.6
000000370F72F918: 2227.9

Using an array of pointers to functions:
 Address Value
000000370F72F908: 1112.3
000000370F72F910: 1542.6
000000370F72F918: 2227.9

Using an array of pointers to functions:
 Address Value
000000370F72F908: 1112.3
000000370F72F910: 1542.6
000000370F72F918: 2227.9

Simplify with typedef

typedef is used to create type aliases, which can be used to create aliases for function pointer types

typedef const double * (*p_fun)(const double *, int);  // p_fun now a type name
p_fun p1 = f1;   // p1 points to the f1() function

//Function pointer array
p_fun pa[3] = {f1, f2, f3};   // pa an array of 3 function pointers
p_fun (*pd)[3] = &pa;         // pd points to an array of 3 function pointers

Using typedef can reduce the amount of code and make the program easier to understand.

Refer to C++ Primer Plus

Keywords: C++

Added by gerbs987 on Sat, 12 Feb 2022 17:22:03 +0200