struct - сортировка c-строки с помощью qsort - PullRequest
2 голосов
/ 27 ноября 2009

Я сортирую кучу IP-адресов, но по какой-то причине они приходят в неправильном порядке. Я не совсем уверен, где может быть проблема.

66.249.71.3      
190.148.164.245  
207.46.232.182   
190.148.164.245  
190.148.164.245  
202.154.114.253
190.148.164.245  
190.148.164.245  
66.249.71.3      
190.148.164.245  
202.154.114.253

Вот так я их сортирую.

typedef struct {
    char *ip;
} mystruct;

/* qsort */
int struct_cmp(const void *a, const void *b)
{
    mystruct *ia = (mystruct *)a;
    mystruct *ib = (mystruct *)b;
    return strcmp(ia->ip, ib->ip);
} 
...
qsort(a_struct, 11, sizeof(mystruct*), struct_cmp);
for(..){
    printf("%s\n",a_struct[i]->ip);
}

Любая помощь будет признательна. Спасибо

Ответы [ 3 ]

7 голосов
/ 27 ноября 2009

У вас есть массив указателей на mystruct с, но qsort с этой функцией сравнения может ожидать простой массив mystruct с. Чтобы отсортировать массив mystruct*, вам нужно добавить еще один уровень косвенности в функцию сравнения:

int struct_cmp(const void *a, const void *b) {
    mystruct *ia = *(mystruct **)a;
    mystruct *ib = *(mystruct **)b;
    return strcmp(ia->ip, ib->ip);
}
3 голосов
/ 27 ноября 2009

Вы сортируете IP-адреса в виде строк. Это на самом деле сработало бы, если бы они были нормализованы: вместо 66.249.71.3 у вас должно быть 066.249.071.003, если вы хотите, чтобы это работало.

Я думаю, что вам лучше всего использовать функцию, которая преобразует точечный IP-адрес в 32-разрядное целое число, а затем сортировать их, используя полученные целые числа в качестве ключа сортировки.

Вы должны быть в состоянии использовать inet_addr(), чтобы сделать это преобразование. Добавьте это к вашей программе:

#include <arpa/inet.h>

Документация здесь .

2 голосов
/ 28 ноября 2009

Существует как минимум два способа исправить код сортировки. Один из них - изменить функцию сравнения, чтобы она соответствовала вызову qsort (); другой - исправить вызов qsort () для сопоставления с компаратором. Правильное исправление зависит от определения массива, но самое простое объявление - это массив структур (а не указателей структур). Следовательно, этот рабочий код - который использует оригинальный компаратор, но другой вызов qsort ():

#include <stdlib.h>
#include <stdio.h>

typedef struct {
    char *ip;
} mystruct;

static mystruct a_struct[] =
{
    "66.249.71.3",
    "190.148.164.245",
    "207.46.232.182",
    "190.148.164.245",
    "190.148.164.245",
    "202.154.114.253",
    "190.148.164.245",
    "190.148.164.245",
    "66.249.71.3",
    "190.148.164.245",
    "202.154.114.253",
};

/* qsort */
static int struct_cmp(const void *a, const void *b)
{
    mystruct *ia = (mystruct *)a;
    mystruct *ib = (mystruct *)b;
    return strcmp(ia->ip, ib->ip);
}

static void print_list(mystruct *list, int n)
{
    int i;
    for (i = 0; i < n; i++)
        printf("%2d: %s\n", i, list[i].ip);
}

#define DIM(x)  (sizeof(x)/sizeof(*(x)))

int main(void)
{
    print_list(a_struct, DIM(a_struct));
    qsort(a_struct, DIM(a_struct), sizeof(mystruct), struct_cmp);
    print_list(a_struct, DIM(a_struct));
}

Это просто оставляет нам отсортированный по буквам и цифрам массив значений со всеми адресами «190.xyz», появляющимися перед остальными, и т. Д. Исправление, которое требует более сложного компаратора - одно решение, для которого Стивеха в своем ответе .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...