Тип указатель: указатели на функции
Цель лекции: изучить указатели на функции и методы передачи функций как параметров, научиться использовать указатели на функции в программных кодах на языке 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; }