2009-11-05 5 views
3

Voici mon code:Comment trier correctement les chaînes en C?

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

int cmp(const void *a, const void *b) { 
    const char **ia = (const char **)a; 
    const char **ib = (const char **)b; 
    return strcmp(*ia, *ib); 
} 

void print_array(char **array, size_t len) { 
    size_t i; 
    for(i=0; i<len; i++) { 
     printf("%s, ", array[i]); 
    } 
    putchar('\n'); 
} 

int main(int argc, char *argv[]) { 

     char *strings[] = { "z1.doc", "z100.doc", "z2.doc", "z3.doc", "z20.doc"}; 
     size_t strings_len = sizeof(strings)/sizeof(char *); 
     print_array(strings, strings_len); 
     qsort(strings, strings_len, sizeof(char *), cmp); 
     print_array(strings, strings_len); 

     system("PAUSE"); 
     return 1; 
} 

la sortie réelle est

z1.doc, z100.doc, z2.doc, z20.doc, z3.doc 

et je veux que ce soit

z1.doc, z2.doc, z3.doc, z20.doc, z100.doc 

Qu'est-ce que je fais mal?

+0

Yikes! Tellement d'étoiles! 'const char * ia = a;'/* ... */'retourne strcmp (ia, ib);' – pmg

+0

Entré à ceci à http://www.mail-archive.com/[email protected] /msg23829.html: Explorer utilise la fonction StrCmpLogicalW() dans shlwapi.dll pour trier les noms de fichiers dans l'ordre "logique". L'ordre de tri exact n'est pas garanti et peut changer avec chaque version de Windows ou service pack! –

+1

@pmg: C'est incorrect. Le faire comme vous le suggérez entraînera sûrement un défaut de segmentation. La variante alternative serait 'const char * ia = * (const char **) a; ...; retourner strcmp (ia, ib); ', mais absolument pas ce que vous suggérez. – AnT

Répondre

3

Changer votre comparateur dire:

return (atoi(*ib + 1) - atoi(*ia + 1)); 
+0

presque, il tri mais en réserve ... merci – netdur

+1

cela ne fonctionnera que s'il n'y a qu'un seul numéro dans le nom de fichier et tous les caractères sont identiques. il ne fonctionnera pas correctement pour "z1aa.doc", "z1zz.doc", "z1bb.doc".il ne fonctionnera pas pour "z10_10.doc" et "z10_5.doc", etc. – progrmr

+0

return (atoi (* ia + 1) - atoi (* ib + 1)); – netdur

4

La sortie réelle est correcte, la chaîne "z100.doc" est inférieure à "z2.doc". Le strcmp compare caractère par caractère et quand il arrive à '1' c'est moins de '2' et il s'arrête là, donc z100 < z2.

Si vous nommez les fichiers z001.doc, z002.doc, z003.doc, z020.doc, z100.doc, ils seront triés comme vous le souhaitez.

+2

Ce n'est pas que la sortie est incorrecte, juste indésirable. –

+0

-1 Renommer les fichiers n'est pas la réponse à cette question. L'OP veut faire du travail pour l'utilisateur, ne pas obliger l'utilisateur à travailler (inutile) pour que ses fichiers soient affichés correctement. Toute personne qui remet cela en question ne comprend pas le concept de «convivialité d'interface» - personne d'autre que nous ne s'attend à ce que les programmeurs classent les listes dans l'ordre dans lequel trie le 'strcmp()'. –

+0

Je suis d'accord mais la question est de savoir comment Trier correctement les chaînes. – progrmr

1

Vous voulez un algorithme de tri naturel par opposition à l'algorithme de tri ASCIIbetical fourni par défaut. Voir Jeff's blog entry pour une longue diatribe à ce sujet, et quelques liens sympas aux implémentations de cet algorithme naturel. Juste comme un avertissement, l'implémentation correcte (par opposition à la réponse hacky que vous avez acceptée) est assez compliquée, alors n'essayez pas de l'implémenter vous-même, prenez l'implémentation et l'utilisation de quelqu'un d'autre (domaine public ou licence libérée) à la place.

Questions connexes