Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Подбельский Фомин_Программирование на языке СИ_...doc
Скачиваний:
342
Добавлен:
10.08.2019
Размер:
53.81 Mб
Скачать

Библиотечные функции с указателями на функции в параметрах.

Библиотечные функции с указателями на функции в параметрах. Эти функции играют важную роль при решении задач на языке Си. В стандартную библиотеку компилятора с языка Си включены по крайней мере следующие функции:

qsort ( ) - функция быстрой сортировки массива;

search ( ) - функция поиска в массиве элемента с заданными свойствами.

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

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

void qsort(void * base, size_t nelem, size_t width,

int (*fcmp)(const void * pl, const void * p2));

Это прототип функции быстрой сортировки, входящей в стандартную библиотеку функций. Прототип находится в заголовочном файле stdlib.h. Функция qsort( ) сортирует содержимое таблицы (массива) однотипных элементов, неоднократно вызывая функцию сравнения, подготовленную пользователем. Для вызова функции сравнения ее адрес должен заместить указатель fcmp, специфицированный как формальный параметр. При использовании qsort( ) программист должен подготовить таблицу сортируемых элементов в виде одномерного массива фиксированной длины и написать функцию, позволяющую сравнивать два любых элемента сортируемой таблицы. Остановимся на параметрах функции qsort( ):

base - указатель на начало таблицы (массива) сортируемых элементов (адрес нулевого элемента массива);

nelem - количество сортируемых элементов в таблице (целая величина, не большая размера массива) -сортируются первые nelem элементов от начала массива;

width - размер элемента таблицы (целая величина, определяющая в байтах размер одного элемента массива);

fcmp - указатель на функцию сравнения, получающую в качестве параметров два указателя p1, р2 на элементы таблицы и возвращающую в зависимости от результата сравнения целое число:

если *p1 < *р2, функция fcmp ( ) возвращает отрицательное целое < 0;

если *p1 == *p2, fcmp ( ) возвращает 0;

если *p1 > *p2, fcmp ( ) возвращает положительное целое > 0.

При сравнении символ "меньше, чем" (<) означает, что после сортировки левый элемент отношения *p1 должен оказаться в таблице перед правым элементом *р2, т.е. значение *p1 должно иметь меньшее значение индекса в массиве, чем *р2. Аналогично (но обратно) определяется расположение элементов при выполнении соотношения "больше, чем" (>).

В следующей программе функция qsort( ) используется для упорядочения массива указателей на строки разной длины. Упорядочение должно быть выполнено таким образом, чтобы последовательный перебор массива указателей позволял получать строки в алфавитном порядке. Сами строки в процессе сортировки не меняют своих положений. Изменяются только значения указателей в массиве.

Результаты выполнения программы: до сортировки:

Вывод адресов, т.е. значений указателей pc[i], выполняется в шестнадцатеричном виде с помощью спецификации преобразования %р.

Обратите внимание на значения указателей pc[i]. До сортировки разность между рс[1] и рс[0] равна длине строки "One -1" и т.д. После упорядочения рс[0] получит значение, равное исходному значению рс[7], и т.д.

Для выполнения сравнения строк (а не элементов массива рс[ ] ) в функции compare( ) использована библиотечная функция strcmp( ), прототип которой в заголовочном файле string.h имеет вид:

int strcmp(const char *sl, const char *s2);

Функция strcmp( ) сравнивает строки, связанные с указателями s1 и s2. Сравнение выполняется посимвольно, начиная с начальных символов строк и до тех пор, пока не встретятся несовпадающие символы либо не закончится одна из строк.

Прототип функции strcmp( ) требует, чтобы параметры имели тип (const char *). Входные параметры функции compare( ) имеют тип (const void *), как предусматривает определение функции qsort( ). Необходимые преобразования для наглядности выполнены в два этапа. В теле функции compare( ) определены два вспомогательных указателя типа (unsigned long *), которым присваиваются значения адресов элементов сортируемой таблицы (элементов массива рс[ ] ) указателей. В свою очередь, функция strcmp( ) получает разыменования этих указателей, т.е. адреса символьных строк. Таким образом, выполняется сравнение не элементов массива char * рс[ ], а тех строк, адреса которых являются значениями pc[i]. Однако функция qsort() работает с массивом рс[ ] и меняет местами только значения его элементов. Последовательный перебор массива рс[ ] позволяет в дальнейшем получить строки в алфавитном порядке, что иллюстрирует результат выполнения программы. Так как pc[i] - указатель на некоторую строку, то по спецификации преобразования %s выводится сама строка.

Если не использовать вспомогательных указателей pa, pb, то функцию сравнения строк можно вызвать из тела функции compare( ) таким оператором:

return strcmp((char *)(*(unsigned long *)a),

(char *)(*(unsigned long )b));

где каждый указатель (void *) вначале преобразуется к типу (unsigned long *).

Последующее разыменование "достает" из нескольких смежных байтов значение соответствующего указателя pc[i], затем преобразование (char *) формирует такой указатель на строку, который нужен функции strcmp( ).