Указатели на функции

Операция typedef

Любому типу данных, как стандартному, так и определенному пользователем, можно задать новое имя с помощью операции

typedef < тип > < новое_имя >;

Введенный таким образом новый тип используется аналогично стандартным типам, например, введя пользовательские типы:

typedef int INT;

typedef char Mass_str[100];

декларации идентификаторов введенных типов имеют вид:

INT i, j; → две переменные i и j типа int;

Mass_str str[10]; → массив str из 10 строк по 100 символов.

В языке Си идентификатор функции является константным указателем на начало функции в оперативной памяти и не может быть значением переменной. Но имеется возможность декларировать указатели на функции с которыми можно обращаться как с переменными (например, можно создать массив, элементами которого будут указатели на функции).

Рассмотрим методику работы с указателями на функции:

1. Как и любой объект языка Си, указатель на функции необходимо декларировать. Формат объявления указателя на функции следующий:

тип (* переменная-указатель ) (список параметров);

т.е. декларируется указатель, который можно устанавливать на функции, возвращающие результат указанного типа и имеют указанный список параметров. Наличие первых круглых скобок обязательно, так как без них –это декларация функции, которая возвращает указатель на результат своей работы указанного типа и имеет указанный список параметров. Например, объявление вида:

float (*p_f) (char, float);

говорит о том, что декларируется указатель p_f, который можно устанавливать на функции, возвращающие вещественный результат и имеющие два параметра: первый – символьного типа, а второй – вещественного типа.

2. Идентификатор функции является константным указателем, поэтому для того чтобы установить переменную-указатель на конкретную функцию, достаточно ей присвоить идентификатор этой функции:

переменная-указатель = имя_функции;

Например, имеется функция с прототипом

float f1 (char, float);

тогда операция

p_f = f1;

установит указатель p_f на данную функцию.

3. Вызов функции после установки на нее указателя выглядит так:

(*переменная-указатель)(список аргументов);

или

переменная-указатель (список аргументов);

После таких действий кроме стандартного обращения к функции

имя_функции(список аргументов);

появляется еще два способа вызова функции:

(*переменная-указатель)(список аргументов);

или

переменная-указатель (список аргументов);

Последнее справедливо, так как p_f также является адресом начала функции в оперативной памяти. Для нашего примера к функции f1 можно обратиться следующими способами:

f1(‘z’, 1.5); // Обращение к функции по имени

(* p_f)(‘z’, 1.5); // Обращение к функции по указателю

p_f(‘z’, 1.5); // Обращение к функции по имени указателя

4. Пусть имеется вторая функция с прототипом:

float f2 (char, float);

тогда, переустановив указатель p_f на эту функцию:

p_f = f2;

имеем опять три способа ее вызова:

f2(‘z’, 1.5); // по имени функции

(* p_f)(‘z’, 1.5); // по указателю на функцию

p_f(‘z’, 1.5); // по имени указателя на функцию

Основное назначение указателей на функции – это обеспечение возможности передачи идентификаторов функций в качестве параметров в функцию, которая реализует некоторый вычислительный процесс, используя формальное имя вызываемой функции.

Примеры работы с функциями

Пример указатель на функцию:

Написать функцию вычисления суммы sum, обозначив слагаемое формальной функцией fun(x), а при вызове функции суммирования передавать через параметр реальное имя функции, в которой запрограммирован явный вид этого слагаемого. Например, пусть требуется вычислить две суммы:

Поместим слагаемые этих сумм в пользовательские функции f1 и f2. При этом для удобства работы воспользуемся операцией typedef, введем пользовательский тип данных: указатель на функции, который можно устанавливать на функции, возвращающие результат, указанного типа, и имеющие указанный список параметров:

typedef тип_результата (* переменная-указатель)(параметры);

Тогда в списке параметров функции суммирования достаточно указывать фактические имена функций данного типа. Программа для решения данной задачи может быть следующей:

#include <iostream.h>

typedef float (*p_f)(float); // Декларация указателя на функциию

float sum(p_f fun, int, float); // Декларации прототипа функции

float f1(float); // Декларации прототипа функции

float f2(float); // Декларации прототипа функции

void main(void)

{

float x, s1, s2;

int n;

cout<<" Введите кол-во слагаемых n: "

cin>>n;

cout<<" Введите значение x: ";

cin>>x;

s1=sum(f1, 2*n, x);

s2=sum(f2, n, x);

cout<<"\nN = "<< n;

cout <<"\nX = "<< x;

cout<<"\nСумма 1 = "<< s1<<' ';

cout<< "\nСумма 2 = "<< s2<<' ';

}

// Функция вычисления суммы, первый параметр которой – формальное имя функции, //имеющей тип, введенный с помощью операции typedef

float sum(p_f fun, int n, float x)

{

float s=0;

for(int i=1; i<=n; i++) s+=fun(x);

return s;

}

float f1(float r) // Первое слагаемое

{

return (r/5.);

}

float f2(float r) // Второе слагаемое

{

return (r/2.);

}

Пример передача в функцию двухмерного массива:

Ввести массив NxN (не больше 50) целых чисел, в функции подсчитать сумму его положительных элементов.

#include <iostream.h>

void vvod(int, int, int a2[ ][50]); // прототип функции ввод массива

int summa(int, int, int a1[ ][50]); // прототип функции поиск суммы

void main(void)

{

int a[50][50];

int i,j,Nstr,Nstb;

cout<<"\n Введите количество строк матрицы (<50) ";

cin>>Nstr;

cout<<"\n Введите количество столбцов матрицы (<50) ";

cin>>Nstb;

vvod(Nstr,Nstb,a); // вызов функции ввод массива

cout<<"\a\n Сумма = "<< summa(Nstr,Nstb,a); // вызов функции поиск суммы и вывод на экран

cout<< "\nPress any key... ";

}

void vvod(int nstr, int nstb, int a2[][50]) // функция ввод массива

{

int i,j;

cout<<"\n Введите массив \n";

for(i=0; i<nstr; i++)

for(j=0; j<nstb; j++)

{

cout<<"a["<<i+1<<"]["<<j+1<<"]= ";

cin>>*(*(a2+i)+j);

}

}

int summa(int nstr, int nstb, int a1[ ][50]) //функция поиск суммы

{

int i,j,s;

cout<<"\n Функция summa ";

for (s=0,i=0; i<nstr; i++)

for (j=0;j<nstb;j++)

if (a1[i][j]>0) s+=a1[i][j];

return s;

}

Пример передача в функцию двухмерного массива (с динамическим выделением памяти):

Ввести массив NxN (не больше 50) целых чисел, в функции подсчитать сумму его положительных элементов.

#include <iostream.h>

#include <conio.h>

void vvod(const int, const int, int **a2); // прототип функции ввод массива

void summa(const int, const int, int **a1); // прототип функции поиск суммы

void main(void)

{

int i,j,Nstr, Nstb;

cout<<"\n Введите количество строк матрицы (<50)\n";

cin>>Nstr;

cout<<" Введите количество столбцов матрицы (<50)\n";

cin>>Nstb;

int **a;

// выделение памяти под матрицу а

a=new int* [Nstr];

for(i=0; i<Nstr; i++)

a[i]=new int[Nstb];

vvod(Nstr,Nstb,a); // вызов функции ввод массива

summa(Nstr,Nstb,a); // вызов функции поиск суммы

}

void vvod(const int nstr, const int nstb, int **a2) // функция ввод массива

{

int i,j;

cout<<"\n Введите массив \n";

for(i=0; i<nstr; i++)

for(j=0; j<nstb; j++)

{

cout<<"a["<<i+1<<"]["<<j+1<<"]= ";

cin>>*(*(a2+i)+j);

}

}

void summa(const int nstr, const int nstb, int **a1) //функция поиск суммы

{

int i,j,s;

cout<<"\n Функция summa ";

for (s=0,i=0; i<nstr; i++)

for (j=0;j<nstb;j++)

if (*(*(a1+i)+j)>0) s+=*(*(a1+i)+j);

cout<<"\n Сумма = "<< s <<" \n Press any key... ";

}


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: