2010-10-11 22 views
4

J'ai une question concernant qsort.Problème avec qsort() - Le tri n'est pas fait correctement (C)

C'est un peu bizarre, mais ma fonction qsort ne me donne pas la bonne sortie. La chose étrange est que certaines de mes fonctions de comparaison sont identiques à mes projets passés, mais ils ne me donnent pas la bonne entrée du tout. Je ne suis pas sûr de savoir comment le tester.

Par exemple:

int comp_name_asc(const void *a, const void *b) 
{ 
    const Rec *prec1 = (const Rec *) a; 
    const Rec *prec2 = (const Rec *) b; 
    return strcmp(prec1->name, prec2->name); 
} 

int comp_name_desc(const void *a, const void *b) 
{ 
    const Rec *prec1 = (const Rec *) a; 
    const Rec *prec2 = (const Rec *) b; 
    return strcmp(prec2->name, prec1->name); 
} 

La deuxième fonction doit être à l'ordre décroissant, mais le résultat est identique: il est toujours dans l'ordre croissant. J'ai vérifié pour m'assurer que la bonne fonction est entrée au bon moment. Rec est un typedef pour une structure que j'ai faite, qui a un paramètre char * name.

également (Modifiée pour éviter tout débordement):

int comp_size_asc(const void *a, const void *b) 
{ 
    const Rec *prec1 = (const Rec *) a; 
    const Rec *prec2 = (const Rec *) b; 

    if (prec1->byteSize > prec2->byteSize) 
    return 1; 
    else if (prec1->byteSize < prec2->byteSize) 
    return -1; 
    else 
    return 0; 
} 

Le résultat est tout à fait bizarre, pas croissant ou décroissant (par exemple: 500, 515, 100, 200 ...). byteSize est de type off_t obtenu en faisant:

char *path; // Build the path 
struct stat sb; 
if (lstat(path, &sb) == 0) { 
    // Read sb.st_size 

Je ne suis vraiment pas sûr de savoir comment le débugger. Tout ce que je sais, c'est que la fonction de comparaison appropriée est entrée, et que certaines fonctions de comparaison similaires utilisées dans le passé.

Toute idée ou comment je peux déboguer ce serait la bienvenue. Je vous remercie.

EDIT:

Ajout de l'appel à qsort: (. Chaque fois qu'un élément est ajouté à la matrice, l'indice est incrémenté)

int index = 0; 
Rec **array = (Rec **) malloc(sizeof(Rec *) * capacity); 
// Adds element to the array... 
qsort(array, index, sizeof(Rec *), comp_name_desc); 

Merci.

EDIT:

La solution a été donnée ci-dessous. Je vous remercie!

je devais changer:

const Rec *prec1 = (const Rec *) a; 

à

const Rec *prec1 = *(const Rec **) a; 

à cause de la façon dont je définissais mon tableau. Merci!

+0

Bienvenue sur SO. +1 de moi pour une question bien écrite et un code très bien formaté. – Arun

+1

Pouvez-vous montrer le code où vous appelez qsort()? Dans le cas de la "taille ascendante", les enregistrements sont-ils triés par nom? – psmears

+1

BTW, ce n'est pas une bonne idée d'utiliser la soustraction dans la fonction de comparaison: en cas de dépassement d'entier, vous obtiendrez des comparaisons incohérentes. – zvrba

Répondre

2

Avez-vous un tableau de Rec, ou plutôt un tableau de pointeurs Rec? Je demande parce que la fonction de comparaison obtient comme pointeurs de paramètres dans le tableau, pas directement à vos dossiers.

Voici une démonstration de deux façons:

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

typedef struct Rec { 
    char *name; 
} Rec; 

/* 
* The pointers a and b point directly into the array, 
* where the Records themselves are. 
*/ 
static int 
cmp_Rec_by_name(const void *a, const void *b) { 
    const Rec *rec1 = (Rec *)a; 
    const Rec *rec2 = (Rec *)b; 
    return strcmp(rec1->name, rec2->name); 
} 

/* 
* The pointers point directly into the array, where 
* not the records but pointers to them are. So they 
* are a pointer to a pointer to a record. 
*/ 
static int 
cmp_Rec_ptr_by_name(const void *a, const void *b) { 
    const Rec *rec1 = *(Rec **)a; 
    const Rec *rec2 = *(Rec **)b; 
    return strcmp(rec1->name, rec2->name); 
} 

static void 
sort_Rec(void) { 
    Rec record[3]; 

    record[0].name = strdup("hello"); 
    record[1].name = strdup("world"); 
    record[2].name = strdup("how are you"); 
    qsort(record, 3, sizeof (Rec), cmp_Rec_by_name); 

    for (int i = 0; i < 3; i++) 
    printf("%s\n", record[i].name); 
} 

static void 
sort_Rec_ptr(void) { 
    Rec *(record[3]); 

    record[0] = malloc(sizeof (Rec)); 
    record[1] = malloc(sizeof (Rec)); 
    record[2] = malloc(sizeof (Rec)); 
    record[0]->name = strdup("hello"); 
    record[1]->name = strdup("world"); 
    record[2]->name = strdup("how are you"); 
    qsort(record, 3, sizeof (Rec *), cmp_Rec_ptr_by_name); 

    for (int i = 0; i < 3; i++) 
    printf("%s\n", record[i]->name); 
} 

int 
main() { 
    sort_Rec(); 
    sort_Rec_ptr(); 
    return 0; 
} 
+0

Merci beaucoup, vous avez raison, cela aurait dû être: const Rec * rec1 = * (Rec **) a; Mon problème a été corrigé, merci beaucoup! – Jary

+0

Avec 'const Rec rec1 = * (Rec *) a' vous copiez tout l'enregistrement, mais vous n'en avez pas besoin. C'est pourquoi j'ai utilisé le pointeur de pointeur dans 'cmp_Rec_ptr_by_name'. –

+0

Merci beaucoup! – Jary

1

Vous ne devriez jamais comparer des nombres en les soustrayant l'un à l'autre. Cela entraînera généralement un débordement avec les types signés et ne fonctionnera pas du tout avec les types non signés. Le langage générique pour comparer des nombres avec un résultat tri-état est le suivant

(a > b) - (a < b) 

Sinon, vos fonctions de comparaison ont l'air bien, de sorte que le problème doit être la façon dont vous appelez la fonction de tri.

+0

Merci, je n'y ai pas pensé. Je vais corriger cela avec un autre si sinon, d'autre déclaration. – Jary

0

En entendant ce que le comportement est, une idée pourrait être que les noms ne sont pas réellement les noms, si strcmp() ont les deux arguments échangés et les résultats sont toujours ascendants.Une suggestion pourrait être d'imprimer les noms en utilisant printf, et aussi, réduire les noms à 2 ou 3 (nombre d'enregistrements), pour le rendre plus facile à déboguer et vérifier pourquoi il se comporte comme ça.