В языке "с" сами функции не являются переменными, ноимеется возможность определить указатель на функцию, которыйможно обрабатывать, передавать другим функциям, помещать вмассивы и т.д. Мы проиллюстрируем это, проведя модификациюнаписанной ранее программы сортировки так, чтобы при заданиинеобязательного аргумента -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для номеров страниц).
* 6. Структуры *
Структура - это набор из одной или более переменных,возможно различных типов, сгруппированных под одним именемдля удобства обработки. (В некоторых языках, самый известныйиз которых паскаль, структуры называются "записями"). Традиционным примером структуры является учетная карточ-ка работающего: "служащий" описывается набором атрибутов та-ких, как фамилия, имя, отчество (ф.и.о.), адрес, код соци-ального обеспечения, зарплата и т.д. Некоторые из этих атри-бутов сами могут оказаться структурами: ф.и.о. Имеет нес-колько компонент, как и адрес, и даже зарплата. Структуры оказываются полезными при организации сложныхданных особенно в больших программах, поскольку во многихситуациях они позволяют сгруппировать связанные данные такимобразом, что с ними можно обращаться, как с одним целым, ане как с отдельными объектами. В этой главе мы постараемсяпродемонстрировать то, как используются структуры. Програм-мы, которые мы для этого будем использовать, больше, чеммногие другие в этой книге, но все же достаточно умеренныхразмеров.