Тип указатель: указатели на функции
Цель лекции: изучить указатели на функции и методы передачи функций как параметров, научиться использовать указатели на функции в программных кодах на языке C++.
Функции, как и элементы данных, имеют адреса. Адресом функции является адрес памяти, с которого начинается машинный код функции.
Для того, чтобы использовать в программе указатель на функцию, необходимо выполнить следующие действия:
- принять адрес функции;
 - объявить указатель на функцию;
 - использовать указатель на функцию для вызова этой функции.
 
Каждая функция характеризуется типом возвращаемого значения, именем и списком типов ее параметров. Если имя функции использовать без последующих скобок и параметров, то оно будет выступать в качестве указателя на эту функцию, и его значение будет определяться как адрес размещения функции в памяти (первый байт). Это значение можно будет присвоить другому указателю. Тогда этот новый указатель можно будет использовать для вызова функции. Указатель на функцию как переменная вводится отдельно от определения и объявления (прототипа) какой-либо функции.
Указатель на функцию – переменная, которая содержит адрес некоторой функции. Соответственно, косвенное обращение по этому указателю представляет собой вызов функции.
Синтаксис определения указателя на функцию:
тип_функции(*имя_указателя)(спецификация_параметров)
где тип_функции – определяет тип возвращаемого функцией значения; имя_указателя – идентификатор; спецификация_параметров – определяет состав и типы параметров функции.
Например:
int (*pf)(); // без контроля параметров вызова int (*pf)(void); // без параметров, с контролем по прототипу int (*pf)(int, char*); // с контролем по прототипу
В соответствии с принципом контекстного определения типа данных эту конструкцию следует понимать так: pf – переменная, при косвенном обращении к которой вызывается функция с соответствующим прототипом, например int_F(int, char*), то есть pf содержит адрес функции или указатель на функцию. Следует обратить внимание на то, что в определении указателя присутствует прототип – указатель ссылается не на произвольную функцию, а только на одну из функций с заданной схемой формальных параметров и результата.
В определении указателя количество и тип параметров должны совпадать с соответствующими типами в определении функции, на которую ставится указатель.
Например,
int (*func1Prt)(char);
задает определение указателя func1Prt на функцию с параметром типа char, возвращающую значение типа int.
Важнейшим элементом в определении указателя на функцию являются круглые скобки. Так следующий фрагмент:
int *func(char);
это не определение указателя, а объявление (прототип) функции c именем func и параметром типа char, возвращающей значение указателя типа int *. В этом случае указатель указывает на значение функции.
Если же выполнить объявление:
char *(*func2Prt)(char *,int);
то определение указателя func2Prt на функцию с параметрами типа указатель на char и типа int, возвращающую значение типа указатель на char.
Синтаксис вызова функции с помощью указателя:
(*имя_указателя)(список_фактических_параметров);
значением имя_указателя служит адрес функции, а с помощью операции разыменования * обеспечивается обращение по адресу к этой функции.
Арифметические операции над указателями на функции запрещены.
Указатели на функции в основном используются в следующих случаях.
- Многие библиотечные функции в качестве аргумента получают указатель на функцию. Например, функция сортировки qsort() получает четвертым аргументом указатель на составляемую пользователем функцию сравнения сортируемых элементов.
 - Использование указателей на функции в качестве аргументов позволяет разрабатывать универсальные функции, реализующие известные алгоритмы или методы. Например, функции численного решения уравнений, интегрирования и дифференцирования.
 - Указатели на функции могут использоваться для косвенного вызова резидентных программ, точка входа в которые записана в известное место памяти, например, по одному из неиспользуемых векторов прерываний.
 
В определении указателя на функцию тип возвращаемого значения, а также типы, количество, последовательность параметров должны совпадать с соответствующими типами и характеристиками параметров тех функций, адреса которых предполагается присваивать вводимому указателю при инициализации или с помощью оператора присваивания.
Пример 1.
//Определение и использование указателей на функции
#include "stdafx.h"
#include <iostream>
using namespace std;
//Определение и использование указателей на функции
void f1(); //объявление (прототип)функции f1
void f2(); //объявление (прототип)функции f2
int _tmain(int argc, _TCHAR* argv[]) {
  void (*ptr)(); //ptr - указатель на функцию
  f2(); //явный вызов функции f2
  ptr=f2;//указателю присваивается адрес функции f2
  (*ptr)();
  //вызов функции f2 по ее адресу с разыменованием указателя
  ptr=f1;//указателю присваивается адрес функции f1
  (*ptr)();
  //вызов функции f1 по ее адресу с разыменованием указателя
  ptr(); // вызов функции f1 без разыменования указателя
  system("pause");
  return 0;
}
//описание функции f1 и f2
void f1() { 
  cout << "Выполняется f1\n"; 
}
void f2() { 
  cout << "Выполняется f2\n"; 
}Пример 2.
//Вариант 1 использования указателя на функцию
#include "stdafx.h"
#include <iostream>
using namespace std;
float plus(float, float); //Объявление (прототип) функции
int _tmain(int argc, _TCHAR* argv[]){
  float x=2.1, y=4.89;
  float (*func)(float,float);
  //определение указателя func на функцию
  printf("Сумма равна %.3f\n",plus(x,y));
  func=plus; 
  //указателю присвоить адрес func точки входа в функцию plus
  // Используем указатель на функцию  
  printf("Сумма = %.3f\n",func(x,y));
  system("pause");
  return 0;
}
//Описание функции сложения двух аргументов
float plus(float a, float b) {
  return a+b; 
}
//Вариант 2 использования указателя на функцию
#include "stdafx.h"
#include <iostream>
using namespace std;
float plus(float, float); //Объявление (прототип)функции
int _tmain(int argc, _TCHAR* argv[]){
  float x=2.1, y=4.89;
  float (*func)(float, float)=+ 
  //определение указателя на функцию plus
  printf("Сумма равна %.3f\n",plus(x,y));
  //указателю присвоить адрес точки входа в функцию plus (Используем указатель на функцию)
  printf("Сумма = %.3f\n",func(x,y));
  system("pause");
  return 0;
}
//Описание функции сложения двух аргументов
float plus(float a, float b) {
  return a+b;
}