Интерфейс
с программами и подпрограммами, написанными на разных языках
программирования.
Указатели на функции.
Рассматриваются вопросы взаимодействия между программами и подпрограммами, написанными на разных языках программирования.
1) Указатели на функции.
Каждая функция характеризуется типом возвращаемого значения, именем и сигнатурой (количеством, порядком следования и типом операндов). Таким образом, сигнатура – это список параметров функции.
При использовании имени функции без последующих скобок и параметров, этоимя выступает в качестве указателя на функцию и его значением служит адрес размещения функции в памяти. Это значение может быть присвоено указателю, который затем можно использовать при вызове функции. Однако в функции, вызываемой через это определение, должны быть тот же тип и сигнатура. Таким образом указатель на функцию можно определить так:
<тип возвращаемого значения функции> (*<имя _ указателя>)
(<спецификация параметров>).
Например, создадим пустое меню для вызова некоторых функций:
сhar FileName[30]; //обрабатываемая строка с инициализацией
void act1 (char *name);
void act2 (char *name);
void act3 (char *name);
typedef void (*MENU) (char *) // тип MENU указателей на функцию с
// возвращаемым значением VOID и с одним операндом типа VOID
MENU MenuAct[3]={act1,act2,act3} //инициализация таблицы адресов
Void main()
{ int num;
cout << “\n Введите номер пункта меню”;
cin>>num;
(*MenuAct[num-1])(FileName);
}
Как видим, в данной программе создан набор функций одного типа и сигнатуры. Используя данный массив указателей на эти функции, можем их выполнить.
Аналогично предыдущему примеру можно решить алгебраическое уравнение методом деления пополам на отрезке от float A до float B с точностью float E.
#include <stdlib.h>
#include <stdio.h>
float f (float x)
{return x*x*x*x*10-X*5+3;} //исследуемая функция
typedef float (*PointFunc) (float); //предопределение функции
float des(PointFunc f,float A,float B,float E)
{ float x,y,c,Fx,Fy,Fc;
x=A; y=B; Fx=(*f)(x); Fy=(*f)(y);
if (Fx*Fy>0.0)
{ printf (“неверный интервал решения\n”)
exit(1);
} // выход в случае ошибки
do
{ c=(y-x)/2;
Fc=(*f)(c);
if (Fc*Fx>0){x=c; Fx=Fc;}
else
{y=c; Fy=Fc;}
} while (Fc!=0||y-x>E);
return c;
}
void main()
{ float result;
result=res(f,0.0,2.0,1e-5);
printf (“result= %f ”,result);
}
В С функции сами по себе не являются переменными, но как мы уже видели, можно определить указатель на функцию, который может быть может быть присвоен функции, установлен в массиве указателей, передан другой функции, быть возвращаемым значением функции и т.д. Ниже в качестве примера показана модификация процедуры сортировки таким образом, что дополнительный аргумент N позволяет использовать числовую или лексикографическую сортировку.
Лексикографическое сравнение двух линий выполняется с помощью функции стандартной библиотеки STRCMP, но возвращаемое ей значение такое же как и в функции NUMCMP.
#include <stdio.h>
#include <string.h>
#defineMAXLINES 5000 /* max количество сортируемых линий */
char *lineptr[MAXLINES]; /*указатели на линии текста*/
int readlines (char *lineptr[], int nlines);
void writelines (char *lineptr[], int nlines);
void qsort(void *lineptr[], int left, int right,
int (*comp) (void *, void *));
int numcmp (char *, char *);
/* сортировка вводимых строк */
main (int argc, char *argv[])
{ intnlines; /*число вводимых строк */
intnumeric = 0; /* 1если числовая сортировкаt */
if (argc>1 && strcmp(argv[1], "-n") == 0)
numeric = 1;
if ((nlines = readlines (lineptr, MAXLINES)) >= 0)
{ qsort( (void **) lineptr, 0, nlines-1,
int (*)(void*, void*))(numeric?numcmp:strcmp));
writelines (lineptr, nlines);
return 0;
} else
{ printf ("input too big to sort\n");
return 1;
}
}
QSORT написана так что может выполняться с любым типом данных, а не только с цифровыми данными. Как следует из прототипа QSORT требует для работы массив указателей, двух целых чисел и функции с двумя аргументами-указателями. Генерированный тип – VOID*, и затем преобразуется к нужному типу операцией преобразования.
/*qsort: sort v[left]...v(right] Into increasing order*/
void qsort(void *v[], int left, int right,
int (*comp) (void *, void *))
{ int i, last;
void swap (void >v[], int, int);
if (left >= right) /*ничего не делать, если в массиве */
return; /* меньше двух элементов */
swap(v, left, (left + right)/2);
last = left;
for (i = left+1; i <= right; i++)
if ((*comp)(v[i]. v[leftl) < 0)
swap(v, ++last, i);
swap(v, left, last);
qsort(v, left, last-1, comp);
qsort(v, last+1, right, comp);
}
Декларация должна выполняться с некоторой осторожностью.
int (*comp) (void *, void *)
которая означает, что COMP это указатель на функцию с двумя аргументами типа VOID* и возвращает INT. Выражение
if ((*comp)(v[i], v[left]) < 0
включает декларацию указателя на функцию COMP, которая и будет вызвана
(*comp) (v[i], v[left])
Скобки необходимы, чтобы правильно определить входящие элементы.
int *comp(void *, void *) /* WRONG */
#include <stdlib.h>
/* numcmp: выполняет цифровое сравнение s1 и s2 */
int numcmp (char *s1, char *s2)
{ double v1, v2;
v1 = atof (s1);
v2 = atof (s2);
if (v1 < v2)
return -1;
else if (v1 > v2)
return 1;
else
return 0;
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.