IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

Tri fusion sur un fichier texte


Sujet :

C

  1. #1
    Membre régulier Avatar de mikhailo
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    78
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Mars 2010
    Messages : 78
    Points : 75
    Points
    75
    Par défaut Tri fusion sur un fichier texte
    Bonjour,

    J'ai un petit souci avec le code que j'ai pondu. Voici le problème: je bosse sur un projet qui implique de gérer un dictionnaire, sous forme de fichier texte qui fait environ 500k lignes. Le problème, c'est que certaines lignes sont mal classées suivant l'ordre de la fonction strcmp(); ce qui implique qu'il faut trier le dictionnaire avant de l'utiliser. J'ai implémenté un "tri à bulles" ( http://fr.wikipedia.org/wiki/Tri_%C3%A0_bulles ) sur le fichier texte, mais comme vous devez vous douter, la complexité de l'algo étant en O(n²), pour un fichier de 500k lignes il faut environ une semaine d'exécution non-stop. Donc pas bon.

    Du coup, je bosse sur un autre algo de tri, "tri fusion" ( http://fr.wikipedia.org/wiki/Tri_fusion ) qui, lui, est en O(n*log(n)). Le problème, c'est l'implémentation, car il s'agit d'un fichier texte... J'ai donc tenté la solution consistant à le copier dans un char** et ensuite faire tourner l'algo dessus (chaque ligne du dico étant affectée à une ligne du tableau donc), mais comme je ne suis pas super à l'aise avec ce format de données, mon prog me fait un SegFault sans que je sache trop pourquoi. Voici mon code (les quelques printf sont là pour essayer de traquer le bug):




    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/stat.h>
     
     
     
     
    /*
    Les deux listes sont déjà triées dans l'ordre croissant de strcmp()
    */
    char** fusionListes(char* liste1[], char* liste2[])
    {
    	int i = 0;
    	int j = 0;
    	int k = 0;
    	char** tableau = (char**)malloc(sizeof(tableau));
     
    	while ((liste1[i] != NULL) || (liste2[j] != NULL))
    	{
    		if (strcmp(liste1[i], liste2[j]) == 1)
    		{
    			tableau[k] = liste2[j];
    			j++;
    		}
    		if (strcmp(liste1[i], liste2[j]) == -1)
    		{
    			tableau[k] = liste1[i];
    			i++;
    		}
    		if (strcmp(liste1[i], liste2[j]) == 0)	
    		{
    			tableau[k] = liste1[i];
    			k++;
    			tableau[k] = liste2[j];
    		}
    		k++;
    	}
    	return tableau;
    }
     
     
     
     
     
     
     
     
     
     
     
    /*
    Tri fusion (récursif): http://fr.wikipedia.org/wiki/Tri_fusion#Tri.2C_proc.C3.A9dure_compl.C3.A8te
    */
    char** triFusion(char** tableau, long int length)
    {
    	char* aux = (char*)malloc(200);
     
    	if (length == 2)
    	{
    		if (strcmp(tableau[0], tableau[1]) > 0)
    		{
    			strcpy(aux, tableau[1]);
    			strcpy(tableau[1], tableau[0]);
    			strcpy(tableau[0], aux);
    		}
    	}
    	else
    	{
    		int i = 0;
    		int half = (int)(length/2)+1;
    		char* tableau1[half];
    		char* tableau2[half];
    		printf("avant le premier for\n");
    		for (i = 0; i < half; i++)
    		{
    			printf("liste1[%d] = %s, liste[%d] = %s\n", i, tableau1[i], i, tableau[i]);
    			strcpy(tableau1[i], tableau[i]);
    			printf("liste1[0] = %s", tableau1[0]);
    		}
    		printf("avant le deuxième for\n");
    		for (i = half; i < length; i++)
    		{
    			strcpy(tableau2[i], tableau[i]);
    		}
    		printf("avant l'appel récursif de triFusion\n");
    		tableau = fusionListes(triFusion(tableau1, half), triFusion(tableau2, half));
    	}
    	return tableau;
    }
     
     
     
     
     
     
     
     
     
     
     
    int main(int argc, char** argv)
    {	
    	if (argc != 2)
    	{
    		printf("ERREUR: argument doit etre du type \"fichier en entree\".\n");
    		return 0;
    	}
     
    	int i = 0;
    	long int nombre_lignes = 1;
    	char ligne_lue[200];
    	char c[0];
     
    	char* resultat = (char*)malloc(10*sizeof(*resultat));
    	strcpy(resultat, argv[1]);
    	strcat(resultat, "sorted.txt");
     
    	FILE* fichier = NULL;
    	fichier = fopen(argv[1], "r");
     
    	while ((c[0] = fgetc(fichier)) != EOF)
    	{
    		if (c[0] == '\n') 
    		{
    			nombre_lignes++;
    		}
    	}
    	fseek(fichier, 0, SEEK_SET);
    	printf("le fichier %s contient %d lignes! c'est cool\n", argv[1], (int)nombre_lignes);
     
    	char** tableau = (char**)malloc(sizeof(tableau));
     
    	while (fgets(ligne_lue, 200, fichier) != NULL)
    	{
    		printf("tableau[0] = %s, ligne_lue = %s", tableau[0], ligne_lue);
    		printf("dans le while...\n");
    		strcpy(tableau[i], ligne_lue);
    		printf("i = %d, tableau[i] = %s, ligne_lue = %s", i, tableau[i], ligne_lue);
    		i++;
    	}
     
    	printf("nombre_lignes = %d\n", (int)nombre_lignes);
    	char** liste = triFusion(tableau, nombre_lignes);
    	printf("après appel à triFusion\n");
    	FILE* output_fichier = NULL;
    	output_fichier = fopen(resultat, "w");
     
    	for (i = 0; i < nombre_lignes; i++)
    	{
    		fprintf(fichier, "%s", liste[i]);
    	}
     
    	printf("tri terminé! :'-)\n");	
     
    	fclose(fichier);
    	fclose(output_fichier);
    	return 0;
    }


    Si une âme charitable pouvait me conseiller, ce serait super!
    "Les hommes et les femmes qui, sans bouger de leur bureau ou de leur bibliotheque, sans développer leur puissance corporelle et leurs infinies dimensions, parviennent, par une opération de la conscience, à une tristesse pessimiste qui se pretend lucide ne font que constater, sans le savoir, que toute identification du multiple de la vie à la vacuite de la conscience mène inévitablement à ce pessimisme et cette impuissance."

    extrait de "La fragilité" de Benasayag

  2. #2
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 689
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 689
    Points : 30 983
    Points
    30 983
    Billets dans le blog
    1
    Par défaut
    Salut

    Repéré 4 grosses failles dans le main
    1) tu alloues 10 caractères pour "resultat" et tu y copies allègrement argv[1] en y rajoutant ensuite "sorted.txt". A mon avis, tout ça ça fait beaucoup plus que 10
    A ce propos, tes deux instructions peuvent être remplacées par sprintf(resultat, "%ssorted.txt", argv[1])

    2) tu alloues mal tableau. A mon avis, si ton tableau doit stocker "nombre_lignes" lignes, alors il faut le lui dire
    tableau=malloc(nombre_lignes * sizeof(char *))
    (au fait, pourquoi nombre_lignes est initialisé à 1 ??? et pourquoi tu utilises fgetc() pour compter le nb de lignes et non fgets() ??? et pourquoi tu castes nombre_lignes en int à l'affichage ???)

    3) maintenant que tableau est prêt pour stocker "nombre_lignes", il faut ensuite allouer chaque tableau[i] pour qu'il puisses, lui, stocker la ligne
    tableau[i]=malloc((strlen(ligne_lue) + 1) * sizeof(char))

    4) gaffe à la mémoire - 500000 lignes à 200 caractères par ligne => 100 000 000c = 95Mo. Ca peut passer mais si ton fichier grossit...

    Ensuite le détail
    1) il faut penser à libérer la mémoire allouée. Toujours !!! C'est un réflexe à avoir. Même si ton programme se termine et que la mémoire est libérée d'office (surtout qu'à une époque, sous Windows, c'était pas le cas)

    2) il faut aussi toujours tester chaque allocation car elle aussi peut échouer

    3) pourquoi t'embêter à implémenter toi-même tes algos de tri alors que la librairie possède la fonction qsort() déjà implémentée ? http://www.linux-kheops.com/doc/man/...3/qsort.3.html
    Te suffit d'appeler qsort en lui passant
    - le tableau à trier
    - le nb d'éléments
    - la taille d'un élément
    - un pointeur sur la fonction permettant de comparer 2 éléments. Cette fonction doit avoir les caractéristiques suivantes
    - recevoir deux pointeurs sur deux éléments à comparer
    - renvoyer -1 si e1 < e2, 0 si e1=e2 et 1 si e1 > e2 (règle pouvant être inversée si on veut un tri décroissant)
    Tout ce qui te reste à faire, c'est décrire la fonction. Etant donné que tu te proposes de trier ton tableau de pointeurs sur chaque ligne du fichier, tu peux utiliser la fonction suivante
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    int cmp(char **x, char **y)
    {
            return strcmp(*x, *y);
    }
    Et tout ton tri se réduira ensuite en une instruction
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    qsort(tableau, nombre_lignes, sizeof(char *), cmp)
    Voici d'ailleurs un petit programme que j'ai tapé vite fait pour me trier un petit fichier d'au plus 10 lignes
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    int cmp(char **x, char **y)
    {
    	return strcmp(*x, *y);
    }
     
    int main()
    {
    	FILE *fp;
    	char **tableau;
    	int i, max;
    	char ligne[200];
     
    	tableau=malloc(10 * sizeof(char*));
     
    	fp=fopen("fic", "r");
    	i=0;
    	while (fgets(ligne, 200, fp) != NULL)
    	{
    		tableau[i]=malloc((strlen(ligne) + 1) * sizeof(char));
    		strcpy(tableau[i], ligne);
    		i++;
    	}
    	max=i;
     
    	printf("Avant le tri\n");
    	for (i=0; i < max; i++)
    		printf("%d: %x, %s", i , tableau[i], tableau[i]);
     
    	qsort(tableau, max, sizeof(char*), cmp);
     
    	printf("Après le tri\n");
    	for (i=0; i < max; i++)
    	{
    		printf("%d: %x, %s", i , tableau[i], tableau[i]);
    		free(tableau[i]);
    	}
    	free(tableau);
    }
    4) la méthode utilisée pour allouer ton tableau (compter le nb d'éléments puis allouer d'un coup) n'est pas la meilleure. Ca marche ici parce que tu traites un fichier donc tu peux revenir au début mais si tu devais stocker un flux d'infos arrivant via un canal particulier, tu peux pas compter le nb d'éléments du flux puis revenir au début (sauf si tu stockes le flux dans un fichier)
    Généralement, la méthode d'allocation est la suivante
    - je définis une variable "taille alloué" et une variable "indice en cours" tous à 0
    - je lis l'info à stocker
    - si "indice en cours" = "taille alloué" alors
    - j'augmente taille alloué de "n" (à toi de définir ce n comme tu le sens)
    - je réalloue une zone correspondant à "taille allouée" (s'il s'agit de la première allocation, realloc passe la main à malloc)
    - fin si
    - je stocke l'info dans l'élément "indice en cours"
    - "indice en cours" s'incrémente
    De cette façon, t'es certain d'avoir toujours l'espace pour stocker "n" éléments et la variable "indice_en_cours" te donnera au final le nombre réel d'éléments qu'il y a dans ton tableau

    Voici le même programme que tout à l'heure mais programmé dans cette optique. Maintenant il peut trier un fichier de taille inconnue (et donc il devrait pouvoir te trier ton fichier sans soucis)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    typedef struct {
    	char **tab;
    	size_t ind;
    	size_t alloc;
    } t_memory;
     
    int cmp(char **x, char **y)
    {
    	return strcmp(*x, *y);
    }
     
    int main()
    {
    	FILE *fp;
    	t_memory tableau;
    	int i, max;
    	char ligne[200];
     
    	tableau.tab=NULL;
    	tableau.ind=0;
    	tableau.alloc=0;
     
    	fp=fopen("fic", "r");
    	while (fgets(ligne, 200, fp) != NULL)
    	{
    		if (tableau.ind == tableau.alloc)
    		{
    			tableau.alloc+=10;
    			tableau.tab=realloc(tableau.tab, tableau.alloc * sizeof(char*));
    		}
     
    		tableau.tab[tableau.ind]=malloc((strlen(ligne) + 1) * sizeof(char));
    		strcpy(tableau.tab[tableau.ind], ligne);
    		tableau.ind++;
    	}
     
    	printf("Avant le tri\n");
    	for (i=0; i < tableau.ind; i++)
    		printf("%d: %x, %s", i , tableau.tab[i], tableau.tab[i]);
     
    	qsort(tableau.tab, tableau.ind, sizeof(char*), cmp);
    	printf("Après le tri\n");
    	for (i=0; i < tableau.ind; i++)
    	{
    		printf("%d: %x, %s", i , tableau.tab[i], tableau.tab[i]);
    		free(tableau.tab[i]);
    	}
    	free(tableau.tab);
    }
    Toutefois j'ai pas eu le courage d'implémenter la gestion de l'allocation ratée. De toute façon, si un malloc/realloc rate, on nettoie ce qui a déjà été alloué et on arrête tout.

    5) si t'es sur un unixlike, t'as à ta disposition la commande "sort" déjà programmée et tout ton programme devient inutile
    sort fic -o fic
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  3. #3
    Membre régulier Avatar de mikhailo
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    78
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Mars 2010
    Messages : 78
    Points : 75
    Points
    75
    Par défaut
    Salut, merci beaucoup pour ta réponse!


    Alors:

    Les quatre grosses failles dans le main:

    1° C'est très vrai, et c'est corrigé;

    2° Pour l'allocation du tableau: yes sir!
    Pourquoi nombre_lignes initialisé à 1 <<< parce que les éditeurs de texte ont tendance à rajouter une ligne vide à la fin du fichier, en tout cas gedit le fait;
    Pourquoi fgetc() et pas fgets() <<< parce que je n'y avais pas pensé; c'est corrigé!
    Pourquoi je caste <<< parce que dans le doute, nombre_lignes est un long int, et je n'avais pas encore découvert que l'on pouvait utiliser %ld au lieu de %d dans ce cas là =/

    3° Merci... effectivement je n'y avais pas pensé du tout, étant assez novice de C. J'ai trouvé pour régler ce problème la fonction asprintf(), qui alloue automatiquement la taille nécessaire.

    4° Gaffe à la mémoire: yes sir!



    Dans le détail:
    1) Libérer la mémoire: yes sir! Sans faute la prochaine fois

    2) Tester les allocations: yes sir!

    3) Utiliser qsort: j'ai vu sur le net que ça existait, mais j'ai voulu coder la fonction moi-même par intérêt "sportif"... Merci pour ta suggestion, je ferai comme ça si je n'arrive pas à débugger mon code, parce que maintenant que j'ai corrigé les problèmes d'allocation, j'ai encore quelques bugs avec l'affectation.
    A priori, pour adapter ton code il suffit que je fasse une fonction qui compte le nombre de lignes (avec fgets, cette fois-ci ^^), non?

    4) Merci pour l'explication, je comprends et j'apprends =)

    5) Ouaip, je suis sur un linux (ubuntu, le linux noob-friendly ^^), et j'ai déjà testé la fonction sort. Il me semble qu'aucune de ses options ne fait le tri utilisant l'ordre de strcmp()... mais je vais retester, au cas où.
    "Les hommes et les femmes qui, sans bouger de leur bureau ou de leur bibliotheque, sans développer leur puissance corporelle et leurs infinies dimensions, parviennent, par une opération de la conscience, à une tristesse pessimiste qui se pretend lucide ne font que constater, sans le savoir, que toute identification du multiple de la vie à la vacuite de la conscience mène inévitablement à ce pessimisme et cette impuissance."

    extrait de "La fragilité" de Benasayag

  4. #4
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 689
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 689
    Points : 30 983
    Points
    30 983
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par mikhailo Voir le message
    Pourquoi nombre_lignes initialisé à 1 <<< parce que les éditeurs de texte ont tendance à rajouter une ligne vide à la fin du fichier, en tout cas gedit le fait;
    Hum, aucun éditeur de texte bien fait ne rajoute de ligne vide à la fin. En tout cas gedit ne le fait pas (sauf si toi tu tapes un "return" en plus).
    Par ailleurs t'as raisonné à l'envers. Si tu veux pas traiter la dernière ligne (qui de toute façon sera comptée avec ton fgetc/fgets), faut décrémenter la variable à la fin. Quoi qu'il en soit, c'est toujours dangereux de décider arbitrairement d'ignorer un cas qui ne se produit pas forcément.

    Citation Envoyé par mikhailo Voir le message
    3° Merci... effectivement je n'y avais pas pensé du tout, étant assez novice de C. J'ai trouvé pour régler ce problème la fonction asprintf(), qui alloue automatiquement la taille nécessaire.
    Ok - Il y a aussi readline() qui le fait. Mais attention, asprintf() c'est d'abord printf(). Et printf() c'est très très long (toi qui a aussi un soucis de rapidité, tu devrais t'y intéresser)
    Moi je reste avec mes bon vieux malloc et strcpy de base.

    Citation Envoyé par mikhailo Voir le message
    3) Utiliser qsort: j'ai vu sur le net que ça existait, mais j'ai voulu coder la fonction moi-même par intérêt "sportif"
    Ok - Eclate-toi alors.

    Citation Envoyé par mikhailo Voir le message
    A priori, pour adapter ton code il suffit que je fasse une fonction qui compte le nombre de lignes (avec fgets, cette fois-ci ^^), non?
    Exact. Moi j'ai mis 10 mais tu peux rajouter le compteur au début. Ou alors y aller franco avec 550000 (comme ça t'es certain de stocker tout ton fichier)

    Citation Envoyé par mikhailo Voir le message
    4) Merci pour l'explication, je comprends et j'apprends =)
    Et là, plus la peine de compter...

    Citation Envoyé par mikhailo Voir le message
    5) Ouaip, je suis sur un linux (ubuntu, le linux noob-friendly ^^), et j'ai déjà testé la fonction sort. Il me semble qu'aucune de ses options ne fait le tri utilisant l'ordre de strcmp()... mais je vais retester, au cas où.
    Ah si!!! sort trie le fichier selon l'ordre ascii des lignes qui le composent. Ca peut poser des problèmes pour un fichier qui ne contient que du nombre, style
    1
    2
    10
    où si on oublie de mettre l'option "-n" on aura 10 se retrouvant entre le 1 et le 2 mais pas pour un fichier texte.
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  5. #5
    Membre régulier Avatar de mikhailo
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    78
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Mars 2010
    Messages : 78
    Points : 75
    Points
    75
    Par défaut
    Pour sort, je viens de refaire le test, et voilà le résultat:

    123
    abba
    afterchezlulu
    dix-huit
    ôter
    raton-laveur
    term_signal
    tèrm_signal
    vingt-quatre
    zorro
    Ce qui n'est pas l'ordre ascii... Car en ascii, "ôter" avec son caractère accentué sera classé tout à la fin du fichier, après le "z", ce qui est le cas pour strcmp().
    De plus, sort a l'air de considérer que le caractère vide est "supérieur" aux autres, car par ex il classe "ote" après "otes" (testé sur un autre fichier); et les autres options n'y font rien (sauf pour l'emplacement des nombres).

    Je vais utiliser ta fonction avec qsort, je pense, ce sera le mieux
    "Les hommes et les femmes qui, sans bouger de leur bureau ou de leur bibliotheque, sans développer leur puissance corporelle et leurs infinies dimensions, parviennent, par une opération de la conscience, à une tristesse pessimiste qui se pretend lucide ne font que constater, sans le savoir, que toute identification du multiple de la vie à la vacuite de la conscience mène inévitablement à ce pessimisme et cette impuissance."

    extrait de "La fragilité" de Benasayag

  6. #6
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Points : 4 637
    Points
    4 637
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    1) tu alloues 10 caractères pour "resultat" et tu y copies allègrement argv[1] en y rajoutant ensuite "sorted.txt". A mon avis, tout ça ça fait beaucoup plus que 10
    Je me permet de rajouter une petite remarque concernant ce point, quel est l'intérêt d'allouer dynamiquement (malloc) un tableau dont la taille est fixe, connue à la compilation et petite ?

  7. #7
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 689
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 689
    Points : 30 983
    Points
    30 983
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par mikhailo Voir le message
    Pour sort, je viens de refaire le test, et voilà le résultat:
    123
    abba
    afterchezlulu
    dix-huit
    ôter
    raton-laveur
    term_signal
    tèrm_signal
    vingt-quatre
    zorro
    Amusant. J'ai passé ton fichier au travers de sort et le résultat est identique. Ensuite je l'ai passé via mon programme et "ôter" a été placé en dernier. J'ai ensuite remplacé "term_signal" par "tzrm_signal" ce qui n'a pas empêché d'être placé avant "tèrm_signal" (ce qui n'arrive pas avec sort)

    J'en conclus que le programme "sort" a été un peu amélioré pour prendre en charge les caractères accentués.

    Citation Envoyé par mikhailo Voir le message
    Ce qui n'est pas l'ordre ascii... Car en ascii, "ôter" avec son caractère accentué sera classé tout à la fin du fichier, après le "z", ce qui est le cas pour strcmp().
    Ce qui se passe effectivement avec mon programme basé sur strcmp()

    Citation Envoyé par mikhailo Voir le message
    De plus, sort a l'air de considérer que le caractère vide est "supérieur" aux autres, car par ex il classe "ote" après "otes"
    Arf pas normal ça. C'est pas ce que ça fait chez-moi. Si j'osais, je te dirais que pour ce genre de fichier test, vaut mieux se passer de gedit et de s'en tenir au bon vieux "vi" (sans présumer de la valeur de gedit bien sûr mais "vi" indique bien visiblement la fin d'une ligne ou d'un fichier et pour insérer du texte faut vraiment le vouloir alors qu'avec gedit, taper un truc en plus est si vite arrivé )

    Citation Envoyé par mikhailo Voir le message
    Je vais utiliser ta fonction avec qsort, je pense, ce sera le mieux
    Ca dépend de ton besoin. Ptet que sort a une option pour ne pas gérer les accents.
    Mais effectivement c'est pas un truc facile à gérer (et c'est pire si on travaille en utf8 car là, les caractères accentués prennent la place de 2 octets )

    Citation Envoyé par gl Voir le message
    Je me permet de rajouter une petite remarque concernant ce point, quel est l'intérêt d'allouer dynamiquement (malloc) un tableau dont la taille est fixe, connue à la compilation et petite ?
    Ben non !!! On ne connait pas la taille de argv[1] lors de la compilation puisqu'il s'agit d'un argument passé au programme lors de son appel...

    Toutefois, je vois ce que tu veux dire. On peut effectivement récupérer la limite MAXPATHLEN définissant la taille maximale d'un nom unix et donc calculer la taille de la zone à partir de cette constante. Mais bon, je pense que mikhailo ne connaissant pas cette constante est parti au plus simple (tout en essayant d'être propre ce qui est tout à son honneur même s'il n'y est pas arrivé )
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  8. #8
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Points : 4 637
    Points
    4 637
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    Ben non !!! On ne connait pas la taille de argv[1] lors de la compilation puisqu'il s'agit d'un argument passé au programme lors de son appel...
    Euh! dans le code initial :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    char* resultat = (char*)malloc(10*sizeof(*resultat));
    Il n'y a aucun lien avec argv[1] ni avec sa taille, et ici, je ne vois vraiment pas l'intérêt du malloc().

    Après que ce soit utile dans le correctif que tu sous-entends, je suis bien d'accord. Mais je rebondissait par rapport au code original (désolé je n'ai pas été très clair à ce sujet).

  9. #9
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 689
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 689
    Points : 30 983
    Points
    30 983
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par gl Voir le message
    Euh! dans le code initial :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    char* resultat = (char*)malloc(10*sizeof(*resultat));
    Il n'y a aucun lien avec argv[1] ni avec sa taille, et ici, je ne vois vraiment pas l'intérêt du malloc().
    Exact. J'ai répondu à ton post en fonction de l'algo que j'avais compris dans le code de mikhailo (il va avoir besoin de stocker argv[1]+"sorted.txt") et non du code tapé (c'est en effet dommage de faire un malloc(10) alors qu'on peut définir directement un char resultat[10])

    Citation Envoyé par gl Voir le message
    Après que ce soit utile dans le correctif que tu sous-entends, je suis bien d'accord. Mais je rebondissait par rapport au code original (désolé je n'ai pas été très clair à ce sujet).
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  10. #10
    Membre régulier Avatar de mikhailo
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    78
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Mars 2010
    Messages : 78
    Points : 75
    Points
    75
    Par défaut
    Alors, voici une version fonctionnelle du tri utilisant le qsort, comme tu m'as dit:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    #define _GNU_SOURCE
    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/stat.h>
     
     
     
     
     
     
    int compare(char* mot1, char* mot2)
    {
    	return strcmp(mot1, mot2);
    }
     
     
     
    int main(int argc, char** argv)
    {	
    	if (argc != 2)
    	{
    		printf("ERREUR: argument doit etre du type \"fichier en entree\".\n");
    		return 0;
    	}
     
    	int i = 0;
    	long int nombre_lignes = 1;
    	char ligne_lue[200];
    	char c[200];
     
    	char* resultat = (char*)malloc(strlen(argv[1]) + strlen("sorted.txt") +1);
    	strcpy(resultat, argv[1]);
    	strcat(resultat, "sorted.txt");
     
    	FILE* fichier = NULL;
    	fichier = fopen(argv[1], "r");
     
    	while (fgets(c, 200, fichier) != NULL)
    	{
    		nombre_lignes++;
    	}
     
    	fseek(fichier, 0, SEEK_SET);
    	printf("le fichier %s contient %ld lignes! c'est cool\n", argv[1], nombre_lignes);
     
    	char** tableau = (char**)malloc(nombre_lignes * sizeof(char*));
     
    	while (fgets(ligne_lue, 200, fichier) != NULL)
    	{
    		ligne_lue[strlen(ligne_lue)-1] = '\0';
    		asprintf(&tableau[i], "%s", ligne_lue);
    		i++;
    	}
     
    	printf("le fichier contient %ld lignes, c'est cool :'-)\n", nombre_lignes);
     
    	qsort(tableau, nombre_lignes+1, sizeof(char *), compare);
     
    	FILE* output_fichier = NULL;
    	output_fichier = fopen(resultat, "w");
     
    	for (i = 0; i < nombre_lignes-1; i++)
    	{
    		printf("processing line... %s\n", tableau[i]);
    		fprintf(output_fichier, "%s\n", tableau[i]);
    	}
     
    	printf("tri terminé! :'-)\n");	
     
    	free(tableau);
    	free(resultat);
    	fclose(fichier);
    	fclose(output_fichier);
    	return 0;
    }

    Elle marche nickel, il y a juste un petit warning à la compilation que je ne comprends pas vraiment...

    [midiakonov@n5 projet s6]$ gcc -Wall -ansi -ggdb3 -o sortFileFusion.o sortFileFusion.c
    sortFileFusion.c: In function main:
    sortFileFusion.c:60: attention : passing argument 4 of qsort from incompatible pointer type

    Je réglerai aussi l'histoire de l'initialisation du nombre de lignes à 1; pas le temps de regarder ça maintenant =)
    "Les hommes et les femmes qui, sans bouger de leur bureau ou de leur bibliotheque, sans développer leur puissance corporelle et leurs infinies dimensions, parviennent, par une opération de la conscience, à une tristesse pessimiste qui se pretend lucide ne font que constater, sans le savoir, que toute identification du multiple de la vie à la vacuite de la conscience mène inévitablement à ce pessimisme et cette impuissance."

    extrait de "La fragilité" de Benasayag

  11. #11
    Membre expert

    Homme Profil pro
    Spécialiste progiciel
    Inscrit en
    Février 2010
    Messages
    1 747
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Haute Loire (Auvergne)

    Informations professionnelles :
    Activité : Spécialiste progiciel
    Secteur : Service public

    Informations forums :
    Inscription : Février 2010
    Messages : 1 747
    Points : 3 016
    Points
    3 016
    Par défaut
    BOnjour,

    Essaye de définir ta fonction compare comme cela
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    int compare (void const *mot1, void const *mot2)
     
    {
    	return strcmp((char *)mot1,(char*) mot2);
    }
    Comme cela, tu passes bien à la fonction qsort le prototype demandé pour la fonction de comparaison.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void qsort( void *base, size_t num, size_t width, int (__cdecl *compare )(const void *elem1, const void *elem2 ) );
    Cordialement,
    Christophe
    Cordialement,
    Christophe

    Merci de ne pas oublier de mettre résolu quand le sujet l'est. Cela aide tous les DVPnautes dans leur recherche

  12. #12
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 689
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 689
    Points : 30 983
    Points
    30 983
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par mikhailo Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    int compare(char* mot1, char* mot2)
    {
    	return strcmp(mot1, mot2);
    }
    T'as pas bien vu mon code. Je ne trie pas des chaines mais des pointeurs (des char *) !!! C'est en effet beaucoup plus rapide de déplacer 4 octets que 200
    Et comme la fonction doit recevoir un pointeur sur l'élément à trier, elle reçoit donc un char **

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    int compare(char** mot1, char** mot2)
    {
    	return strcmp(*mot1, *mot2);
    }
    Citation Envoyé par mikhailo Voir le message
    Elle marche nickel...
    Bienvenue dans le C et ses comportements indéterminés.
    Le plus gros danger du C c'est qu'il ne vérifie pas la cohérence du code par rapport à ce qu'on est sensé en faire (style un tableau prévu pour 10 rmais rempli avec 11 éléments). C'est fait exprès pour aller vite (philosophie qui sous-tend ce comportement: le programmeur sait ce qu'il fait) mais malheureusement, quand le programmeur ne sait pas ou voit mal, on arrive dans le comportement indéterminé. Et ça, c'est le plus grave.

    Un comportement indéterminé c'est un comportement imprévisible. Et le terme "imprévisible" recouvre vraiment toute la gamme. c.a.d. que ton programme peut fonctionner quand-même (parce que la zone qui dépasse n'est pas demandée ou autre raison).
    Puis un jour, 6 mois après, tu rajoutes un printf() à la con et là crash. Et là, tu t'arraches les cheveux à essayer de comprendre pourquoi ton printf() fait crasher le truc.

    Et là, t'es en plein dedans. Ta fonction compare() ne reçoit pas un char * mais un char **. Désolé mais le fait que ton programme fonctionne n'est absolument pas une garantie...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  13. #13
    Membre régulier Avatar de mikhailo
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    78
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Mars 2010
    Messages : 78
    Points : 75
    Points
    75
    Par défaut
    Re =)

    Voilà, j'ai corrigé presque tous les problèmes:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    #define _GNU_SOURCE
    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/stat.h>
     
     
     
     
     
     
    int cmp(char** mot1, char** mot2)
    {
    	return strcmp(*mot1, *mot2);
    }
     
     
     
    int main(int argc, char** argv)
    {	
    	int i = 0;
    	long int nombre_lignes = 0;
    	char ligne_lue[200];
    	char c[200];
    	char* resultat = (char*)malloc(strlen(argv[1]) + strlen("sorted.txt") +1);
    	FILE* fichier = NULL;
    	FILE* output_fichier = NULL;
    	char** tableau;
     
     
    	if (argc != 2)
    	{
    		printf("ERREUR: argument doit etre du type \"fichier en entree\".\n");
    		return 0;
    	}
     
    	strcpy(resultat, argv[1]);
    	strcat(resultat, "sorted.txt");
     
     
    	fichier = fopen(argv[1], "r");
     
    	while (fgets(c, 200, fichier) != NULL)
    	{
    		nombre_lignes++;
    	}
     
    	fseek(fichier, 0, SEEK_SET);
    	printf("le fichier %s contient %ld lignes! c'est cool\n", argv[1], nombre_lignes);
     
    	tableau = (char**)malloc(nombre_lignes * sizeof(char*));
     
    	while (fgets(ligne_lue, 200, fichier) != NULL)
    	{
    		ligne_lue[strlen(ligne_lue)-1] = '\0';
    		asprintf(&tableau[i], "%s", ligne_lue);
    		i++;
    	}
     
    	printf("le fichier contient %ld lignes, c'est cool :'-)\n", nombre_lignes);
     
    	qsort(tableau, nombre_lignes, sizeof(char *), cmp);
     
    	output_fichier = fopen(resultat, "w");
     
    	for (i = 0; i < nombre_lignes-1; i++)
    	{
    		printf("processing line... %s\n", tableau[i]);
    		fprintf(output_fichier, "%s\n", tableau[i]);
    	}
     
    	printf("tri terminé! :'-)\n");	
     
    	free(tableau);
    	free(resultat);
    	fclose(fichier);
    	fclose(output_fichier);
    	return 0;
    }

    J'ai essayé ta suggestion, carden, mais elle ne supprime pas l'erreur, et en revanche, la fonction ne fonctionne plus comme il faut. Le seul problème donc, je crois, est maintenant le:

    mikhail@mikhail-laptop:~/info/projet s6$ gcc -Wall -ansi -pedantic -o sortFileFusion.o sortFileFusion.c
    sortFileFusion.c: In function ‘main’:
    sortFileFusion.c:64: warning: passing argument 4 of ‘qsort’ from incompatible pointer type
    /usr/include/stdlib.h:710: note: expected ‘__compar_fn_t’ but argument is of type ‘int (*)(char **, char **)’
    mikhail@mikhail-laptop:~/info/projet s6$

    Et en fait, Sve@r, ce qui était drôle, c'est qu'une fois tous les problèmes corrigés, l'initialisation du nombre_lignes à 1 est parti de lui-même car il causait un segfault... Comme quoi ^^
    "Les hommes et les femmes qui, sans bouger de leur bureau ou de leur bibliotheque, sans développer leur puissance corporelle et leurs infinies dimensions, parviennent, par une opération de la conscience, à une tristesse pessimiste qui se pretend lucide ne font que constater, sans le savoir, que toute identification du multiple de la vie à la vacuite de la conscience mène inévitablement à ce pessimisme et cette impuissance."

    extrait de "La fragilité" de Benasayag

  14. #14
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Points : 4 637
    Points
    4 637
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    Et comme la fonction doit recevoir un pointeur sur l'élément à trier, elle reçoit donc un char **

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    int compare(char** mot1, char** mot2)
    {
    	return strcmp(*mot1, *mot2);
    }
    Attention, effectivement la fonction va recevoir un const char**, mais le prototype de la fonction attendue par qsort() est :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    int (*compar)(const void*, const void *)
    La fonction à utiliser est donc plutôt :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    int compare(const void* mot1, const void* mot2)
    {
    	return strcmp(*(const char**)mot1, *(const char**)mot2);
    }

  15. #15
    Membre régulier Avatar de mikhailo
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    78
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Mars 2010
    Messages : 78
    Points : 75
    Points
    75
    Par défaut
    Merci, c'est impec' comme ça! Plus aucun warning ni problème technique... Grâce à vous, je peux avancer maintenant la conscience tranquille sur la partie algorithmique de mon projet
    "Les hommes et les femmes qui, sans bouger de leur bureau ou de leur bibliotheque, sans développer leur puissance corporelle et leurs infinies dimensions, parviennent, par une opération de la conscience, à une tristesse pessimiste qui se pretend lucide ne font que constater, sans le savoir, que toute identification du multiple de la vie à la vacuite de la conscience mène inévitablement à ce pessimisme et cette impuissance."

    extrait de "La fragilité" de Benasayag

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Probleme de tri alphabétique d'un fichier texte
    Par Oli_Ifre dans le forum Langage
    Réponses: 6
    Dernier message: 27/03/2007, 16h01
  2. lire/écrire sur un fichier texte sur un serveur distant
    Par nabmoah dans le forum Visual C++
    Réponses: 6
    Dernier message: 12/02/2007, 10h27
  3. Réponses: 8
    Dernier message: 14/09/2006, 16h43
  4. Stats sur un fichier texte
    Par fermat dans le forum Delphi
    Réponses: 3
    Dernier message: 17/08/2006, 00h50
  5. Réponses: 7
    Dernier message: 23/03/2005, 22h23

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo