русс | укр

Языки программирования

ПаскальСиАссемблерJavaMatlabPhpHtmlJavaScriptCSSC#DelphiТурбо Пролог

Компьютерные сетиСистемное программное обеспечениеИнформационные технологииПрограммирование

Все о программировании


Linux Unix Алгоритмические языки Аналоговые и гибридные вычислительные устройства Архитектура микроконтроллеров Введение в разработку распределенных информационных систем Введение в численные методы Дискретная математика Информационное обслуживание пользователей Информация и моделирование в управлении производством Компьютерная графика Математическое и компьютерное моделирование Моделирование Нейрокомпьютеры Проектирование программ диагностики компьютерных систем и сетей Проектирование системных программ Системы счисления Теория статистики Теория оптимизации Уроки AutoCAD 3D Уроки базы данных Access Уроки Orcad Цифровые автоматы Шпаргалки по компьютеру Шпаргалки по программированию Экспертные системы Элементы теории информации

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


Дата добавления: 2015-06-12; просмотров: 757; Нарушение авторских прав


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

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

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

Например,

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(); }



<== предыдущая лекция | следующая лекция ==>
ФУНКЦИИ (дополнительные возможности) | Введение в рекурсивные функции.


Карта сайта Карта сайта укр


Уроки php mysql Программирование

Онлайн система счисления Калькулятор онлайн обычный Инженерный калькулятор онлайн Замена русских букв на английские для вебмастеров Замена русских букв на английские

Аппаратное и программное обеспечение Графика и компьютерная сфера Интегрированная геоинформационная система Интернет Компьютер Комплектующие компьютера Лекции Методы и средства измерений неэлектрических величин Обслуживание компьютерных и периферийных устройств Операционные системы Параллельное программирование Проектирование электронных средств Периферийные устройства Полезные ресурсы для программистов Программы для программистов Статьи для программистов Cтруктура и организация данных


 


Не нашли то, что искали? Google вам в помощь!

 
 

© life-prog.ru При использовании материалов прямая ссылка на сайт обязательна.

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