Язык С

       

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


В языке "с" сами функции не являются переменными, но имеется возможность определить указатель на функцию, который можно обрабатывать, передавать другим функциям, помещать в массивы и т.д. Мы проиллюстрируем это, проведя модификацию написанной ранее программы сортировки так, чтобы при задании необязательного аргумента -N она бы сортировала строки ввода численно, а не лексикографически. Сортировка часто состоит из трех частей - сравнения, ко- торое определяет упорядочивание любой пары объектов, перес- тановки, изменяющей их порядок, и алгоритма сортировки, осу- ществляющего сравнения и перестановки до тех пор, пока объекты не расположатся в нужном порядке. Алгоритм сортиров- ки не зависит от операций сравнения и перестановки, так что, передавая в него различные функции сравнения и перестановки, мы можем организовать сортировку по различным критериям. Именно такой подход используется в нашей новой программе сортировки. Как и прежде, лексикографическое сравнение двух строк осуществляется функцией STRCMP, а перестановка функцией SWAP; нам нужна еще функция NUMCMP, сравнивающая две строки на основе численного значения и возвращающая условное указа- ние того же вида, что и STRCMP. Эти три функции описываются в MAIN и указатели на них передаются в SORT. В свою очередь функция SORT обращается к этим функциям через их указатели. мы урезали обработку ошибок в аргументах с тем, чтобы сосре- доточиться на главных вопросах.

#DEFINE LINES 100 /* MAX NUMBER OF LINES TO BE SORTED */

MAIN(ARGC, ARGV) /* SORT INPUT LINES */ INT ARGC; CHAR *ARGV[]; \( CHAR *LINEPTR[LINES]; /* POINTERS TO TEXT LINES */ INT NLINES; /* NUMBER OF INPUT LINES READ */ INT STRCMP(), NUMCMP(); /* COMPARSION FUNCTIONS */ INT SWAP(); /* EXCHANGE FUNCTION */ INT NUMERIC = 0; /* 1 IF NUMERIC SORT */

IF(ARGC>1 && ARGV[1][0] == '-' && ARGV[1][1]=='N') NUMERIC = 1; IF(NLINES = READLINES(LINEPTR, LINES)) >= 0) \( IF (NUMERIC) SORT(LINEPTR, NLINES, NUMCMP, SWAP); ELSE SORT(LINEPTR, NLINES, STRCMP, SWAP); WRITELINES(LINEPTR, NLINES); \) ELSE PRINTF("INPUT TOO BIG TO SORT\N"); \)


Здесь STRCMP, NIMCMP и SWAP - адреса функций; так как извес- тно, что это функции, операция & здесь не нужна совершенно аналогично тому, как она не нужна и перед именем массива. Передача адресов функций организуется компилятором. Второй шаг состоит в модификации SORT:

SORT(V, N, COMP, EXCH) /* SORT STRINGS V[0] ... V[N-1] */ CHAR *V[]; /* INTO INCREASING ORDER */ INT N; INT (*COMP)(), (*EXCH)(); \( INT GAP, I, J;

FOR(GAP = N/2; GAP > 0; GAP /= 2) FOR(I = GAP; I < N; I++) FOR(J = I-GAP; J >= 0; J -= GAP) \( IF((*COMP)(V[J], V[J+GAP]) <= 0) BREAK; (*EXCH)(&V[J], &V[J+GAP]); \) \)

Здесь следует обратить определенное внимание на описа- ния. Описание

INT (*COMP)()

говорит, что COMP является указателем на функцию, которая возвращает значение типа INT. Первые круглые скобки здесь необходимы; без них описание

INT *COMP()

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



IF (*COMP)(V[J], V[J+GAP]) <= 0)

полностью согласуется с описанием: COMP - указатель на функ- цию, *COMP - сама функция, а

(*COMP)(V[J], V[J+GAP])

- обращение к ней. Круглые скобки необходимы для правильного объединения компонентов. Мы уже приводили функцию STRCMP, сравнивающую две строки по первому численному значению:

NUMCMP(S1, S2) /* COMPARE S1 AND S2 NUMERICALLY */ CHAR *S1, *S2; \( DOUBLE ATOF(), V1, V2;

V1 = ATOF(S1); V2 = ATOF(S2); IF(V1 < V2) RETURN(-1); ELSE IF(V1 > V2) RETURN(1); ELSE RETURN (0); \)

Заключительный шаг состоит в добавлении функции SWAP, переставляющей два указателя. Это легко сделать, непосредст- венно используя то, что мы изложили ранее в этой главе.

SWAP(PX, PY) /* INTERCHANGE *PX AND *PY */ CHAR *PX[], *PY[]; \( CHAR *TEMP;

TEMP = *PX; *PX = *PY; *PY = TEMP; \) Имеется множество других необязятельных аргументов, ко- торые могут быть включены в программу сортировки: некоторые из них составляют интересные упражнения.

Упражнение 5-11

--------------- Модифицируйте SORT таким образом, чтобы она работала с меткой -R, указывающей на сортировку в обратном (убывающем) порядке. Конечно, -R должна работать с -N.



Упражнение 5-12

--------------- Добавьте необязательный аргумент -F, объединяющий вместе прописные и строчные буквы, так чтобы различие регистров не учитывалось во время сортировки: данные из верхнего и нижне- го регистров сортируются вместе, так что буква 'а' прописное и 'а' строчное оказываются соседними , а не разделенными це- лым алфавитом.

Упражнение 5-13

--------------- Добавьте необязательный аргумент -D ("словарное упорядо- чивание"), при наличии которого сравниваются только буквы, числа и пробелы. Позаботьтесь о том, чтобы эта функция рабо- тала и вместе с -F.

Упражнение 5-14

--------------- Добавьте возможность обработки полей, так чтобы можно было сортировать поля внутри строк. Каждое поле должно сор- тироваться в соответствии с независимым набором необязатель- ных аргументов. (предметный указатель этой книги сортировал- ся с помощью аргументов -DF для категории указателя и с -N для номеров страниц).




    Содержание раздела