Студопедия
МОТОСАФАРИ и МОТОТУРЫ АФРИКА !!!


Авиадвигателестроения Административное право Административное право Беларусии Алгебра Архитектура Безопасность жизнедеятельности Введение в профессию «психолог» Введение в экономику культуры Высшая математика Геология Геоморфология Гидрология и гидрометрии Гидросистемы и гидромашины История Украины Культурология Культурология Логика Маркетинг Машиностроение Медицинская психология Менеджмент Металлы и сварка Методы и средства измерений электрических величин Мировая экономика Начертательная геометрия Основы экономической теории Охрана труда Пожарная тактика Процессы и структуры мышления Профессиональная психология Психология Психология менеджмента Современные фундаментальные и прикладные исследования в приборостроении Социальная психология Социально-философская проблематика Социология Статистика Теоретические основы информатики Теория автоматического регулирования Теория вероятности Транспортное право Туроператор Уголовное право Уголовный процесс Управление современным производством Физика Физические явления Философия Холодильные установки Экология Экономика История экономики Основы экономики Экономика предприятия Экономическая история Экономическая теория Экономический анализ Развитие экономики ЕС Чрезвычайные ситуации ВКонтакте Одноклассники Мой Мир Фейсбук LiveJournal Instagram

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




Чтобы понять, как работают указатели на функции, надо иметь в виду следующее. По мере компиляции функций исходный код, записанный по правилам языка С++, преобразуется в объектный и устанавливается точка входа, к которой происходит обращение при вызове функции.

Указатель на функцию в программе определяется следующим образом:

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

Например,

float (*PFun) (int, int);

определяет указатель PFun на функцию с двумя целочисленными параметрами, возвращающую одно вещественное значение. Если приведённое выше объявление записать без первых круглых скобок, то есть в виде

float *PFun (int, int);,

то компилятор воспримет его как прототип функции с именем PFun с двумя целочисленными параметрами, возвращающей значение указателя типа float *. Другими словами, это не указатель на функцию.

Второй пример. Объявление char *(*PFun2 (char *, float); определяет указатель Pfun2 на функцию с параметрами типа указатель на char и типа float, возвращающую значение типа указатель на char.

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

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

float Aver (int x, int y)

{ return (x+y)/2.;

}

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

PFun=Aver;

При таком присваивании необходимо соблюдать соответствие типов возвращаемых значений функций (в примере float), количеством (2), порядком следования и типами (int x, int y)параметров для указателей правой и левой частей оператора присваивания. Почему такое присваивание будет корректным? PFun мы объявили как указатель на функцию. По аналогии с массивом имя функции (Aver) без последующих скобок и параметров без дополнительного объявления выступает в качестве указателя на эту функцию, и его значением служит адрес размещения функции в памяти. Хотя функция — это не переменная, она всё равно имеет физическое местоположение в памяти, которое может быть присвоено другому указателю.

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




float Res; Res= (*PFun) (5, 2);

С помощью операции разыменования * обеспечивается обращение по адресу к этой функции. Заметим. что будет ошибкой записать вызов функции без первых скобок в виде:

Res= *PFun (5, 2);

Дело в том, что круглые скобки имеют более высокий приоритет, чем операция обращения по адресу *. Поэтому сначала будет сделана попытка обратиться к функции PFun. А операция разименования будет отнесена к результату этой функции. Но у нас нет функции PFun! Это указатель на функцию, что не одно и то же.

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

float *PFun (int, int)=Aver;

В качестве конкретного практического использования указателя на функцию рассмотрим следующий пример.

Пример 1. (+)Составить функцию, которая по формуле Симпсона вычисляет значение определённого интеграла от произвольной функции одной переменной. Функцию проверить для вычисления двух интегралов:

Формула Симпсона:

n – чётное.

Функция Integral для вычисления определённого интеграла от произвольной функции по формуле Симпсона имеет следующие параметры: пределы интегрирования a и b; количество точек, на которые разбивается отрезок [a, b], котороеобъявлено с типом float, чтобы исключить преобразования типов при реализации алгоритма; указатель на функцию, для которой вычисляется определённый интеграл.

float Integral (float, float, float, float (*Fun)(float));

// Две тестовые функции, для которых вычисляется интеграл.



float Function1(float x){ return (sqrt(1-x*x));

};

float Function2(float x){ return (exp(-x*x));

};

void main()

{ float a,b,n,I;

// Вычисление первого интеграла.

a=-1; b=1; n=100; I=Integral(a,b,n,Function1); cout<<I;

// Вычисление второго интеграла.

a=0; b=1; n=100; I=Integral(a,b,n,Function2); cout<<endl<<I;

getch();

}

// Функция для вычисления интеграла по формуле Симпсона.

float Integral(float a,float b,float n,float (*Fun)(float))

{ float h,s1=0,s2=0;

h=(b-a)/n;

for(int i=2;i<=(n-2);i+=2)

s1+=(*Fun)(a+i*h);

for(int i=1;i<=(n-1);i+=2)

s2+=(*Fun)(a+i*h);

return ((b-a)/(3*n)*((*Fun)(a)+2*s1+4*s2+(*Fun)(b)));

}

§3. Массив указателей на функции.

Указатели на функции могут быть объединены в массивы. Например,

float (*FunArray[5]) (char, char);

описывает массив фиксированной размерности из пяти указателей на функции, каждая из которых имеет два параметра типа char и возвращает значение типа float. Как для обычных массивов, индексация начинается с нуля. Поэтому для обращения к третьей из этих функций потребуется, например, такой оператор:

float f= (*FunArray[2]) (‘A’, ‘B’);

Массив указателей на функции удобно использовать при разработке программ, управление которыми выполняется с помощью меню. Для этого действия, предлагаемые на выбор пользователю программы (например, создание файла, чтение и анализ, корректировка файла), оформляются в виде функций, адреса которых помещаются в массив указателей на функции. Пользователь вводит номер выбираемого пунктаи по нему из массива выбирается соответствующий адрес функции. Обращение к функции по этому адресу обеспечивает выполнение требуемых действий. Благодаря такому методу программирования нет необходимости выбирать соответствующие функции с помощью оператора switch. Общая схема реализации такого подхода иллюстрирует следующая программа:

Пример 1.Статический массив указателей на функции.

void Create (int);

void Read(int);

void Append(int);

void main()

{ const n=3;

// Объявляем массив из трёх указателей на функции

void (*far[n])(char *)= { Create, Read, Append };

int Numf;

char NameOfFile[30];

cout<<”\n 1- CREATE”;

cout<<”\n 2- READ”;

cout<<”\n 3- APPEND”;

cout<<”\n 4- EXIT”;

while (1)

{ while (1)

{ cout<<”\n Item of menu”; cin>>Numf

if (Numf>=1 && Numf<=4) break;

cout<<” \n Error! Repeat/ “;

}

if (Numf==4) break;

else

{cout<<”\n Name of file “;

gets( NameOfFile);

(*far[Numf-1])( NameOfFile);

}

}

}

void Create (int x)

{ cout << " Creating of file"<<endl;

}

void Read (int x)

{ cout << " Reading of file"<<endl;

}

void Append (int x)

{ cout << " Appending of file"<<endl;

}

В этом учебном, искусственном примере объявили массив far из трёх указателей на функции типа void, каждая из которых имеет один входной параметр (физическое имя обрабатываемого файла) типа указателя на строку (char *). Функция ничего не возвращает, а только выводит текст в зависимости от выполняемых над файлом действий. При объявлении массива выполнена инициализация тремя конкретными, определёнными после main(), функциями Create, Read и Append. В цикле вводим номер функции (1, 2, 3 или 4 для выхода) и выполняем одну из трёх функций. В качестве параметра в конкретную функцию передаётся её реальный номер в массиве (1 для Create, 2 для Read, и 3 для Append ). Если введём в качестве номера число 4 выходим из внешнего цикла.

Пример 2. (+)Динамический массив указателей на функции. Для x=0, 0.2, …, 1 вывести таблицу значений трёх функций.

// Тексты двух функций. Третья функция – стандартная cos(x).

double MyExp (double x){

return (exp(x));

};

double Myq(double x){

return x*x;

};

void main()

{ int n; cin>>n;

/* Объявляем и создаём массив указателей на функции с одним вещественным параметром. */

double (*(*fun))(double )= new (double (*[n])(double));

// Элементам созданного массива присваиваем имена функций.

fun[0]= cos;

fun[1]=MyExp;

fun[2]=Myq;

// Цикл для изменения x

for (float x=0; x<1; x+=0.2)

{ printf("%5.1f",x) ;

/* Цикл для вывода значений всех функций для одного фиксированного значения x. */

for(int j=0; j<n; j++)

printf (" %20.6f", fun[j](x));

cout<<endl;

}

getch(); }





Дата добавления: 2015-02-24; просмотров: 996; Опубликованный материал нарушает авторские права? | Защита персональных данных | ЗАКАЗАТЬ РАБОТУ


Не нашли то, что искали? Воспользуйтесь поиском:

Лучшие изречения: На стипендию можно купить что-нибудь, но не больше... 9190 - | 7324 - или читать все...

Читайте также:

 

3.233.219.101 © studopedia.ru Не является автором материалов, которые размещены. Но предоставляет возможность бесплатного использования. Есть нарушение авторского права? Напишите нам | Обратная связь.


Генерация страницы за: 0.009 сек.