2012-01-04 4 views
2

У меня массив из следующих структурКак отсортировать массив структур в C?

typedef struct _my_data_ 
{ 
    unsigned int id; 
    double latitude; 
    double longitude; 
    unsigned int content_len; 
    char* name_dyn; 
    char* descr_dyn; 
} mydata; 

и хотел бы отсортировать его по возрастанию по ID. Я читал, что можно сортировать массивы с помощью функции qsort qsort, но я не уверен, как правильно ее использовать при сортировке структур.

Любая помощь будет оценена по достоинству.

+5

Вы написали функцию, которая может сказать вам, какая из двух заданных структур имеет большее или меньшее поле 'id'? – sarnold

ответ

16

Вам нужна функция компаратора структуры, которая соответствует прототипу функции ожидаемой qsort(), а именно:

int md_comparator(const void *v1, const void *v2) 
{ 
    const mydata *p1 = (mydata *)v1; 
    const mydata *p2 = (mydata *)v2; 
    if (p1->id < p2->id) 
     return -1; 
    else if (p1->id > p2->id) 
     return +1; 
    else 
     return 0; 
} 

Если вы когда-нибудь более сложному критерий сортировки, это еще хорошая основа, потому что вы можете добавить вторичные критерии, используя тот же скелет:

int md_comparator(const void *v1, const void *v2) 
{ 
    const mydata *p1 = (mydata *)v1; 
    const mydata *p2 = (mydata *)v2; 
    if (p1->latitude < p2->latitude) 
     return -1; 
    else if (p1->latitude > p2->latitude) 
     return +1; 
    else if (p1->longitude < p2->longitude) 
     return -1; 
    else if (p1->longitude > p2->longitude) 
     return +1; 
    else 
     return 0; 
} 

Очевидно, что это повторяется столько критериев, сколько вам нужно. (? strcmp()) Если вам нужно вызвать функцию для сравнения значений, назовем его один раз, но назначить возвращение к локальной переменной и использовать его дважды:

int md_comparator(const void *v1, const void *v2) 
{ 
    const mydata *p1 = (mydata *)v1; 
    const mydata *p2 = (mydata *)v2; 
    int rc; 
    if (p1->latitude < p2->latitude) 
     return -1; 
    else if (p1->latitude > p2->latitude) 
     return +1; 
    else if (p1->longitude < p2->longitude) 
     return -1; 
    else if (p1->longitude > p2->longitude) 
     return +1; 
    else if ((rc = strcmp(p1->name_dyn, p2->name_dyn)) < 0) 
     return -1; 
    else if (rc > 0) 
     return +1; 
    else 
     return 0; 
} 

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

int md_comparator(const void *v1, const void *v2) /* BAD */ 
{             /* BAD */ 
    const mydata *p1 = (mydata *)v1;    /* BAD */ 
    const mydata *p2 = (mydata *)v2;    /* BAD */ 
    return(p1->id - p2->id);      /* BAD */ 
}             /* BAD */ 

плохо, если id беззнаковый (разность двух целых чисел без знака никогда не бывает отрицательная), и при условии переполнения, если целые числа подписаны и большой величины и противоположных знаков.

+0

Спасибо за ваш комментарий и +1 кстати! –

+0

Большое спасибо за ваш ответ, я сейчас попробую этот код. – beta

+1

Размышления о 'if 'id' unsigned': поскольку return является' int', значение 'unsigned' будет преобразовано в' int', поэтому оно может стать отрицательным. Однако, если 'id' был' unsigned long' или 'unsigned long long' и' sizeof (long)> sizeof (int) ', тогда вы были бы уязвимы для какого-то очень странного поведения. Наблюдение, что явный механизм возвращения ± 1 всегда работает, остается точным; «вычитание» не работает, если сравнение двух неподписанных величин не является строго точным. –

Смежные вопросы