Как сделать сортировку qsort структуры по элементу поля, которое является массивом целых чисел на Си?

Рейтинг: 0Ответов: 1Опубликовано: 28.05.2023

У меня есть структура человека и ввод 12 таких человек с клавиатуры.

typedef struct
{
    char surname[30];
    char name[20];
    char znak_zodiaka[10];
    int birthday_date[3];
}znak;

...
znak znaks[12];

Нужно отсортировать этих людей по дате рождения по возрастанию (если годы равны, сравнивать месяцы, а если и они равны, то сравнивать дни). Для даты рождения есть в структуре массив int birthday_date[3], в который записывалась информация в виде день.месяц.год.

Я понимаю, что нужно сделать qsort(znaks, 12, sizeof(znak), compare_age), но как реализовать сам компаратор compare_age?

Я пробовала так

int compare_age(const void* a, const void* b)
{
    znak* znak_a = (znak*)a;
    znak* znak_b = (znak*)b;
    if (znak_a->birthday_date[2] > znak_b->birthday_date[2])
        return (znak_b->birthday_date - znak_a->birthday_date);
    else if (znak_a->birthday_date[2] < znak_b->birthday_date[2])
        return (znak_a->birthday_date - znak_b->birthday_date);
    else
    {
        if (znak_a->birthday_date[1] > znak_b->birthday_date[1])
            return (znak_b->birthday_date - znak_a->birthday_date);
        else if (znak_a->birthday_date[1] < znak_b->birthday_date[1])
            return (znak_a->birthday_date - znak_b->birthday_date);
        else
        {
            if (znak_a->birthday_date[0] > znak_b->birthday_date[0])
                return (znak_b->birthday_date - znak_a->birthday_date);
            else if (znak_a->birthday_date[0] <= znak_b->birthday_date[0])
                return (znak_a->birthday_date - znak_b->birthday_date);
        }
    }

}

Но сортировка идет неверно. Полный код

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <locale.h>
#include <windows.h>
#include <math.h>
#define LEN 12

typedef struct
{
    char surname[30];
    char name[20];
    char znak_zodiaka[10];
    int birthday_date[3];
}znak;
int compare_age(const void* a, const void* b)
{
    znak* znak_a = (znak*)a;
    znak* znak_b = (znak*)b;
    if (znak_a->birthday_date[2] > znak_b->birthday_date[2])
        return (znak_b->birthday_date - znak_a->birthday_date);
    else if (znak_a->birthday_date[2] < znak_b->birthday_date[2])
        return (znak_a->birthday_date - znak_b->birthday_date);
    else
    {
        if (znak_a->birthday_date[1] > znak_b->birthday_date[1])
            return (znak_b->birthday_date - znak_a->birthday_date);
        else if (znak_a->birthday_date[1] < znak_b->birthday_date[1])
            return (znak_a->birthday_date - znak_b->birthday_date);
        else
        {
            if (znak_a->birthday_date[0] > znak_b->birthday_date[0])
                return (znak_b->birthday_date - znak_a->birthday_date);
            else if (znak_a->birthday_date[0] <= znak_b->birthday_date[0])
                return (znak_a->birthday_date - znak_b->birthday_date);
        }
    }

}
int main(void)
{
    /*Для русифицирования символов*/
    setlocale(LC_ALL, "RUS");
    SetConsoleCP(1251);
    SetConsoleOutputCP(1251);

    znak znaks[LEN];
    char buf[100];
    int col_mans = 0;

    for (int i = 0; i < LEN; i++)
    {
        printf("\t\t\tЧеловек № %d\n", i+1);

        printf("Введите фамилию: (Если хотите прервать ввод, введите \"!\"\") ");
        scanf_s("%s", buf, 100);
        /*Прерывание*/
        if (strstr(buf, "!") != NULL) break;
        strcpy(znaks[i].surname, buf);

        printf("\nВведите имя: ");
        scanf_s("%s", buf, 100);
        strcpy(znaks[i].name, buf);

        printf("\nВведите знак зодиака: ");
        scanf_s("%s", buf, 100);
        strcpy(znaks[i].znak_zodiaka, buf);

        printf("\nВведите дату рождения через пробел [дд мм гггг]: ");
        scanf_s("%d %d %d", &(znaks[i].birthday_date[0]), &(znaks[i].birthday_date[1]), &(znaks[i].birthday_date[2]));
        col_mans++;
    }
    printf("\n\n\n\t\t\tРезультаты без сортировки\n");
    for (int i = 0; i < col_mans; i++)
    {
        printf("\t\t\tЧеловек № %d\n", i+1);
        printf("Фамилия: %s\nИмя: %s\nЗнак зодиака: %s\nДата рождения: %02d.%02d.%02d\n", znaks[i].surname, znaks[i].name, znaks[i].znak_zodiaka, znaks[i].birthday_date[0], znaks[i].birthday_date[1], znaks[i].birthday_date[2]);
    }
    qsort(znaks, col_mans, sizeof(znak), compare_age);
    printf("\n\n\n\t\t\tРезультаты с сортировкой по дате рождения (возрастание)\n");
    for (int i = 0; i < col_mans; i++)
    {
        printf("\t\t\tЧеловек № %d\n", i + 1);
        printf("Фамилия: %s\nИмя: %s\nЗнак зодиака: %s\nДата рождения: %02d.%02d.%02d\n", znaks[i].surname, znaks[i].name, znaks[i].znak_zodiaka, znaks[i].birthday_date[0], znaks[i].birthday_date[1], znaks[i].birthday_date[2]);
    }
    return 0;
}

Ответы

▲ 0Принят

Ну что же вы такое делаете?...

if (znak_a->birthday_date[2] > znak_b->birthday_date[2])
    return (znak_b->birthday_date - znak_a->birthday_date);
else if (znak_a->birthday_date[2] < znak_b->birthday_date[2])
    return (znak_a->birthday_date - znak_b->birthday_date);

Что вы возвращаете? разность между указателями!

Что-то типа:

if (znak_a->birthday_date[2] != znak_b->birthday_date[2])
    return znak_a->birthday_date[2] - znak_b->birthday_date[2];
else if (znak_a->birthday_date[1] != znak_b->birthday_date[1])
    return znak_a->birthday_date[1] - znak_b->birthday_date[1];
else return znak_a->birthday_date[0] - znak_b->birthday_date[0];

Вот и все сравнение. Как-то так (писалось со скоростью набора и даже не компилировалось :))