Опубликован: 02.02.2011 | Уровень: для всех | Доступ: платный
Лекция 6:

Тип указатель: указатели на функции

< Лекция 5 || Лекция 6: 123 || Лекция 7 >
Аннотация: В лекции рассматриваются определение указателя на функцию, способы объявления, адресуемость и обращение к функции через указатель, передачу фактических параметров указателю на функцию, использование указателя на функцию в качестве параметра функции.

Цель лекции: изучить указатели на функции и методы передачи функций как параметров, научиться использовать указатели на функции в программных кодах на языке 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; 
  //определение указателя на функцию 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;
}
< Лекция 5 || Лекция 6: 123 || Лекция 7 >
Денис Курбатов
Денис Курбатов
Владислав Нагорный
Владислав Нагорный

Подскажите, пожалуйста, планируете ли вы возобновление программ высшего образования? Если да, есть ли какие-то примерные сроки?

Спасибо!

Александр Грязнов
Александр Грязнов
Россия, Рязань, РГРТУ, 2014