5.11 Указатели на функции
В Си сама функция не является переменной, но можно определить указатель на функцию и работать с ним, как с обычной переменной: присваивать, размещать в массиве, передавать в качестве параметра функции, возвращать как результат из функции и т. д. Для иллюстрации этих возможностей воспользуемся программой сортировки, которая уже встречалась в настоящей главе. Изменим ее так, чтобы при задании необязательного аргумента -n вводимые строки упорядочивались по их числовому значению, а не в лексикографическом порядке.
Сортировка, как правило, распадается на три части: на сравнение, определяющее упорядоченность пары объектов; перестановку, меняющую местами пару объектов, и сортирующий алгоритм, который осуществляет сравнения и перестановки до тех пор, пока все объекты не будут упорядочены. Алгоритм сортировки не зависит от операций сравнения и перестановки, так что передавая ему в качестве параметров различные функции сравнения и перестановки, его можно настроить на различные критерии сортировки.
Лексикографическое сравнение двух строк выполняется функцией strcmp (мы уже использовали эту функцию в ранее рассмотренной программе сортировки); нам также потребуется программа numcmp, сравнивающая две строки как числовые значения и возвращающая результат сравнения в том же виде, в каком его выдает strcmp. Эти функции объявляются перед main, а указатель на одну из них передается функции qsort. Чтобы сосредоточиться на главном, мы упростили себе задачу, отказавшись от анализа возможных ошибок при задании аргументов.
>#include ‹stdio.h›
>#include ‹string.h›
>#define MAXLINES 5000 /* максимальное число строк */
>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[])
>{
> int nlines; /* количество прочитанных строк */
> int numeric = 0; /* 1, если сорт. по числ. знач. */
> 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("Bведено слишком много строк\n");
> return 1;
> }
>}
В обращениях к функциям qsort, strcmp и numcmp их имена трактуются как адреса этих функций, поэтому оператор& перед ними не нужен, как он не был нужен и перед именем массива.