русс | укр

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

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

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

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


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

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


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


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

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

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

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

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

Например, объявление вида

double (*p_f )(char, double);

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

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

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

Например, имеется функция с прототипом: double f1(char, double); тогда операция

p_f = f1;

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

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

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



или

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

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

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

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

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



или

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

Последняя запись справедлива, так как p_f также является адресом начала функции в оперативной памяти.

Для нашего примера к функции f1 можно обратиться следующими способами:

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

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

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

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

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

и .

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

Тогда в списке параметров функции суммирования достаточно будет указать фактические идентификаторы функций созданного типа p_f.

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

. . .

typedef double (*p_f)(double);

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

double f1(double);

double f2(double);

void main(void)

{

double x, s1, s2;

int n;

puts (" Введите кол-во слагаемых n и значение x: ");

scanf (" %d %lf ", &n, &x);

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

s2 = sum (f2, n, x);

printf("\n\t N = %d , X = %lf ", n, x);

printf("\n\t Сумма 1 = %lf\n\t Сумма 2 = %lf ", s1, s2);

}

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

double sum(p_f fun, int n, double x) {

double s=0;

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

s+=fun(x);

return s;

}

//–––––––––––––– Первое слагаемое –––––––––––––––––––

double f1(double r) {

return r/5.;

}

//–––––––––––––– Второе слагаемое ––––––––––––––––––––

double f2(double r) {

return r/2.;

}

 

В заключение рассмотрим оптимальную передачу в функции одномерных и двухмерных массивов.

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

void main(void)

{

int vect[20];

fun(vect);

}

void fun( int v[ ]) {

}

При использовании в качестве параметра одномерного массива в функцию передается указатель на его первый элемент, т.е. массив всегда передается по адресу и параметр v[ ] преобразуется в *v. Поэтому этой особенностью можно воспользоваться сразу:

void fun( int *v) {

}

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

void fun( int v[20]) {

. . .

}

В случае передачи массива символов, т.е. строки, ее фактическую длину можно определить по положению признака окончания строки (нуль-символа) через стандартную функцию strlen.

 

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

Если размеры известны на этапе компиляции, то

void f1(int m[3][4]) {

int i, j;

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

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

. . . // Обработка массива

}

Двухмерный массив, как и одномерный, также передается как указатель, а указанные размеры используются просто для удобства записи. При этом первый размер массива не используется при поиске положения элемента массива в ОП, поэтому передать массив можно так:

void main(void)

{

int mas [3][3]={{1,2,3}, {4,5,6}};

fun (mas);

}

void fun( int m[ ][3]) {

}

Если же размеры двухмерного массива, например, вводятся с клавиатуры (неизвестны на этапе компиляции), то их значения следует передавать через дополнительные параметры, например:

void fun( int**, int, int);

void main()

{

int **mas, n, m;

...

fun (mas, n, m);

}

void fun( int **m, int n, int m) {

. . . // Обработка массива

}

 



<== предыдущая лекция | следующая лекция ==>
Передача аргументов в функцию | Рекурсивные функции


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


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

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

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


 


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

 
 

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

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