Функции, регистрируемые atexit(), вроде sign_off() и too bad(), должны иметь тип void и не принимать аргументов. Обычно они решают вспомогательные задачи, такие как обновление файла мониторинга программы или переустановка переменных среды.
Обратите внимание, что sign off() вызывается даже в случае, когда функция exit() не вызывается явно; причина в том, что exit() неявно вызывается при заверь щении main().
Использование функции exit()
Когда exit() выполняет функции, указанные с помощью atexit(), она предпринимает собственные шаги по очистке. Функция exit() сбрасывает все потоки вывода, закрывает все открытые потоки и закрывает временные файлы, созданные в результате обращений к стандартной функции ввода-вывода tmpfile(). Затем exit() возвращает управление размещаемой среде и по возможности сообщает среде состояние
700 глава 16 завершения. Традиционно программы для Unix применяли 0, чтобы указать на успешное завершение, и ненулевое значение для сообщения об отказе. Коды возврата Unix не обязательно работают со всеми системами, поэтому в ANSI С определен макрос по имени EXIT FAILURE, который может использоваться переносимым образом для обозначения отказа. Аналогично, в ANSI С определен макрос EXIT_SUCCESS для указания на успешное завершение, но exit() также принимает для этой цели значение 0. В рамках стандарта ANSI С применение exit() в нерекурсивной функции main() эквивалентно использованию ключевого слова return. Тем не менее, exit() также завершает программу, когда применяется в функциях, отличных от main().
Функция qsort()
Метод быстрой сортировки входит в число наиболее эффективных алгоритмов сортировки, особенно в случае крупных массивов. Разработанный Чарльзом Энтони Ричардом Хоаром в 1962 году, этот алгоритм разделяет массивы на постоянно уменьшающиеся части, пока не будет достигнут уровень элемента. Сначала массив делится на две части, так что любое значение в одной части меньше любого значения в другой части. Этот процесс продолжается вплоть до момента, когда массив станет полностью отсортированным.
Алгоритм быстрой сортировки реализован в С под именем qsort(). Эта функция сортирует массив объектов данных. Она имеет следующий прототип ANSI:
void qsort (void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
Первый аргумент представляет собой указатель на начало сортируемого массива. Стандарт ANSI С разрешает приведение типа указателя на данные к типу указателя на void, таким образом, позволяя первому фактическому аргументу qsort() ссылаться на массив любого вида.
Во втором аргументе передается количество элементов, подлежащих сортировке. Прототип преобразует это значение в тип size t. Как уже несколько раз упоминалось, size t является целочисленным типом, который возвращается операцией sizeof и определен в стандартных заголовочных файлах.
Из-за того, что функция qsort() преобразует свой первый аргумент в указатель на void, она утрачивает информацию о размере каждого элемента массива. Чтобы скомпенсировать это, следует явно сообщить qsort() размер объекта данных. Именно для такой цели служит третий аргумент. Например, если вы сортируете массив типа double, то в третьем аргументе должны указать sizeof (double).
Наконец, qsort() требуется указатель на функцию, которая будет использоваться для определения порядка сортировки. Функция сравнения должна принимать два аргумента — указатели на два сравниваемых элемента. Она возвращает положительное целое число, если первый элемент должен следовать за вторым, ноль, если элементы одинаковы, и отрицательное целое число, если второй элемент должен следовать за первым. Функция qsort() вызывает эту функцию с передачей ей значений указателей, которые вычисляет на основе другой предоставленной информации.
Форма функции сравнения задана в последнем аргументе прототипа qsort():
int (*compar)(const void *, const void *)
Здесь видно, что последний аргумент qsort() представляет собой указатель на функцию, возвращающую значение int и принимающую два аргумента, каждый из которых является указателем на тип const void. Эти два указателя ссылаются на сравниваемые элементы.
Препроцессор и библиотека С 701
Листинг 16.17 и последующее обсуждение иллюстрируют способ определения функции сравнения и применения функции qsort(). В программе создается массив случайных значений с плавающей запятой, который затем сортируется.
Листинг 16.17. Программа gsorter .с

702 Глава 16
Читать дальше