Читать книгу 📗 "Linux программирование в примерах - Роббинс Арнольд"
size_t nmembОбщее число элементов в массиве.
size_t sizeРазмер каждого элемента массива. Лучший способ получения этого значения — оператор С
sizeofint (*compare)(const void*, const void*)Возможно устрашающее объявление указателя функции. Оно говорит, что «
compareconst void*intБольшая часть работы заключается в написании соответствующей функции сравнения. Возвращаемое значение должно имитировать соответствующее значение
strcmp()doubleint dcomp(const void *d1p, const void *d2p) { const double *d1, *d2; d1 = (const double*)d1p; /* Привести указатели к нужному типу */ d2 = (const double*)d2p; if (*d1 < *d2) /* Сравнить и вернуть нужное значение */ return -1; else if (*d1 > *d2) return 1; else if (*d1 == *d2) return 0; else return -1; /* NaN сортируется до действительных чисел */}Это показывает общий стереотип для функций сравнения: привести тип аргументов от
void*Для чисел с плавающей точкой простое вычитание, подобное '
return *d1 - *d26.2.1.1. Пример: сортировка сотрудников
Для более сложных структур требуются более сложные функции. Например, рассмотрите следующую (довольно тривиальную)
struct employeestruct employee {char lastname[30];char firstname[30];long emp_id;time_t start_date;};Мы могли бы написать функцию для сортировки сотрудников по фамилии, имени и идентификационному номеру:
int emp_name_id_compare(const void *e1p, const void *e2p) { const struct employee *e1, *e2; int last, first; e1 = (const struct employee*)e1p; /* Преобразовать указатели */ e2 = (const struct employee*)e2p; if ((last = strcmp(e1->lastname, e2->lastname)) != 0) /* Сравнить фамилии */ return last; /* Фамилии различаются */ /* фамилии совпадают, сравнить имена */ if ((first = strcmp(e1->firstname, e2->firstname)) != 0) /* Сравнить имена */ return first; /* Имена различаются */ /* имена совпадают, сравнить номера ID */ if (e1->emp_id < e2->emp_id) /* Сравнить ID сотрудника */ return -1; else if (e1->emp_id == e2->emp_id) return 0; else return 1;}Логика здесь проста: сначала сравниваются фамилии, затем имена, а затем номера ID, если два имени совпадают. Используя для строк
strcmp()При сравнении ID сотрудников нельзя просто использовать вычитание: представьте, что
longintintЗАМЕЧАНИЕ. Возможно, мы остановились при сравнении имен, в этом случае все сотрудники с совпадающими фамилиями и именами оказались бы сгруппированы, но никак не отсортированы
Это важный момент
qsort()Просто используя другую функцию, мы можем отсортировать сотрудников по старшинству:
int emp_seniority_compare(const void *e1p, const void *e2p) { const struct employee *e1, *e2; double diff; /* Привести указатели к нужному типу */ e1 = (const struct employee*)e1p; e2 = (const struct employee*)e2p; /* Сравнить времена */ diff = difftime(e1->start_date, e2->start_date); if (diff < 0) return -1;