Comparer deux fichiers

Signaler
Messages postés
393
Date d'inscription
lundi 22 juin 2009
Statut
Membre
Dernière intervention
23 décembre 2011
-
Messages postés
393
Date d'inscription
lundi 22 juin 2009
Statut
Membre
Dernière intervention
23 décembre 2011
-
Bonjour,

J'ai deux fichiers "exemple.txt" et "essai.txt"
J'aime afficher les lignes qui existent dans "exemple.txt" et qui n'existent pas dans "essai.txt"
c'est comme une sorte de la différence.

Chaque ligne de fichier contient une chaine de caractère.
Mon idée :
pour chaque ligne de "exemple.txt" je teste si elle existe dans "essai.txt".
Si oui je l'affiche.

Le problème que on peut trouver la même chaine de caractère de "exemple.txt" mais dont l'ordre des mots formant cette chaine est différent de celui dans "essai.txt"

on affiche la chaine autant qui se compose de mêmes mots.

Soit le fichier "exemple.txt"

nom prenom
nom age
nom prenom age
nom emploi
age emploi
prenom age empoi
nom age emploi
nom prenom emploi
nom prenom age emploi


Soit le fichier "essai.txt"

nom
prenom
age
emploi
age nom
nom age prenom
nom emploi
age emploi
prenom age empoi
nom prenom emploi
nom prenom age emploi


le résultat souhaité est:

nom prenom
nom age
nom age emploi


Comment on obtient ce résultat ?

Merci.

108 réponses

Messages postés
3834
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
20 octobre 2021
124
Il possède un bon compilateur à mon avis sous windows. De plus, je ne peux pas le changer maintenant.

Je n'ai jamais dit que c'était un mauvais compilateur. J'essaie juste de faire en sorte qu'on soit dans les mêmes conditions, afin de déceler ce qui ne vas pas dans ce code. (Tout fonctionne chez moi sur deux OS différents).

Je crois que dans la fonction strndup que vous écrivez plus de donnés qu'il n'y a de place dans ton tableau, en l'occurrence, vous écrivez un byte de trop, donc comportement indéterminé.

Non, je t'invite à relire le code. La taille du tableau est de n + 1 et je met un 0 terminal à la case n. Donc il n'y a pas débordement.
De plus, j'ai passé mon exécutable sous valgrind (outil de détection des fuites mémoires) qui me répond : "0 errors. No memory leak are possible."

Vous dites que :
[...]
Je ne trouve pas dans le code la partie qui permet d'afficher:
[...]


C'est normal, j'ai dit que le code fonctionnait, pas qu'il résolvait ton problème.

C'est possible de me donner la version finale et complète de code qui me répond à mon problème pour le tester une fois pour toute ?

Non, c'est à toi de réaliser ce code. Je peux t'aider, te corriger ou t'aiguiller, mais je ne ferais pas ton travail à ta place. Encore un petit effort, tu n'es plus très loin.
Messages postés
393
Date d'inscription
lundi 22 juin 2009
Statut
Membre
Dernière intervention
23 décembre 2011
5
Bonjour,

Voici mon essai qui contient aussi la partie concernant l'intersection entre les trois résultats de comparaison.
#include <stdio.h>

#include <stdlib.h>

#include <string.h>



#define MAX_SIZE 1024



char* strndup(const char *str, size_t n)

{

  char *ret = malloc((n+1) * sizeof (char));



  if (!ret)

    exit(0);  strncpy(ret, str, n);

  ret[n] = 0;



  return ret;

}



void free_tab(char** t)

{

  char** head = t;



  while (t && *t)

  {

    free(*t);

    t++;



  }

  free(head);

}



char** get_word(const char* str)

{

  char* pos = NULL;

  char** res = NULL;

  int nb = 0;



  do

  {

    int size = 0;



    pos = strchr(str, ' ');

    if (pos)

      size = pos - str;    else

      size = strlen(str) - 1; /* - 1 to get rid of \n */

    nb++;

    res = realloc(res, (nb + 1) * sizeof (char*));

    res[nb -1] = strndup(str,  size);

    str = pos + 1;

  }

  while (pos);



  res[nb] = 0;



  return res;

}



int is_same(const char* const s1, const char* const s2)

{

  char **t1, **t2;

  int ret = 0;



  t1 = get_word(s1);

  t2 = get_word(s2);



  if (t1 && t2)

  {

    char** tab1 = t1;

    char** tab2 = t2;

    int nb = 0;

    int size = 0;



    while (tab1 && *tab1)

    {

      tab2 = t2;

      while (tab2 && *tab2)

      {

if (!strcmp(*tab1, *tab2))

  nb++;

tab2++;

      }      tab1++;

      size++;

    }



    ret = (nb >= size);

    free_tab(t1);

    free_tab(t2);

  }



  return ret;

}



char** compare_file(const char* filename1, const char* filename2)

{

  FILE *f, *f1;

  char s[MAX_SIZE], s1[MAX_SIZE];

  int a;

  char** res = NULL;

  int nb = 0;



  f = fopen(filename1, "r");

  f1 = fopen(filename2, "r");

  if (f && f1)

  {

    while (fgets(s, MAX_SIZE, f))

    {

      a = 0;

      rewind(f1);

      while (fgets(s1, MAX_SIZE, f1))

      {

if (is_same(s, s1))

{

  a = 1;

  break;

}

      }

      if (!a)

      {

nb++;

res = realloc(res, (nb + 1) * sizeof (char*));

res[nb - 1] = strndup(s, strlen(s) - 1); /* Get rid of the \n */

res[nb] = 0;

      }

    }

    fclose(f);

    fclose(f1);

  }



  return res;

}



char** copy_tab(char** tab)

{

  char** res = NULL;

  int nb = 0;



  while (tab && *tab)

  {

    nb++;

    res = realloc(res, (nb + 1) * sizeof (char*));

    res[nb - 1] = strndup(*tab, strlen(*tab));

    res[nb] = 0;

    tab++;

  }



  return res;

}



char** compute_intersect(char** tab1, char** tab2)

{

char** inter = NULL;

  if (!tab2)

    return NULL;

  else if (!tab1)

    return copy_tab(tab2);

  // Ici finir de coder l'intersection 
  else
  {
          //inter: tableau contient les  éléments communs entre tab1 et tab2  
  inter = realloc(inter,sizeof (char*));


  while (tab1 && *tab1)

  {

  while (tab2 && *tab2)

  {

  if(!strcmp(*tab1,*tab2))

  *inter = strndup(*tab1, strlen(*tab1));
     
  tab2++;


  }

  tab1++;

  }

  return inter;


  }

}


void display_tab(char** tab)

{

  while (tab && *tab)

  {

    printf("%s\n", *tab);

    tab++;

  }

}



int main()

{

  char** res = NULL;

 char** intersect = NULL;

  char input[32];

  int i;



  for (i = 1; i <= 3; i++)

  {

    sprintf(input,"f%d.txt",i);

    res = compare_file("f.txt",input);

    /* temp */

    printf("Comparing f.txt and %s:\n", input);

    display_tab(res);

    /* ! temp */

    intersect = compute_intersect(intersect, res);

    free_tab(res);

  }



  printf("Final result:\n");

  display_tab(intersect);

  free_tab(intersect);
 


  return 0;

}


La compilation se passe bien mais lorsque je lance l'exécution il y a un affichage des résultats de comparaison mais le programme ne termine pas l'exécution correctement lorsque il exécute la fonction " compute_intersect"

je crois que le problème est dans la fonction "compute_intersect" .

Que proposez vous ?

Merci.
Messages postés
3834
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
20 octobre 2021
124
Plusieurs corrections sont à apporter.

Tout d'abord inutile de mettre un "else" après un "return", le "return" est débranchant, c'est à dire qu'il fait immédiatement quitter une fonction.

  if (!tab2)
    return NULL;
  else if (!tab1)
    return copy_tab(tab2);
  // Ici finir de coder l'intersection 
  else
  {
         //inter: tableau contient les  éléments communs entre tab1 et tab2  


peut facilement être remplacé par:

  if (!tab2)
    return NULL;
  if (!tab1)
    return copy_tab(tab2);
  // Ici finir de coder l'intersection 

  //inter: tableau contient les  éléments communs entre tab1 et tab2  


De plus tu fais :

 inter = realloc(inter,sizeof (char*));


Donc ta tableau aura toujours une taille de 1. Vu que tu ne réalloues jamais après, ton programme planteras forcément.

Afin de simplifier cette fonction je te conseille de coder la fonction "int is_in_tab(char* str, char** tab)" qui retourne si la chaîné donnée est présente dans le tableau.
Mis à part l'oublie de réallocation, le principe à l'air d'être correct.
Messages postés
393
Date d'inscription
lundi 22 juin 2009
Statut
Membre
Dernière intervention
23 décembre 2011
5
Bonjour,

J'ai modifié un peu le code de la fonction
"compute_intersect"

char** compute_intersect(char** tab1, char** tab2)

{

char** inter = NULL;
int i,j;

  if (!tab2)

    return NULL;

  if (!tab1)

    return copy_tab(tab2);

  // Ici finir de coder l'intersection 
   inter = realloc(inter,strlen(tab1)*sizeof (char*));

  for(i=0;i<strlen(tab1);i++)
  
  for(j=0;j<strlen(tab2);j++)
  {
       if(!strcmp(tab1[i], tab2[j]))
   
   strcpy(inter[i],tab1[i]);

   j++;
  }
 
   return inter;

 }



la compilation se passe bien.
Mais,l'exécution ne se termine pas correctement.
J'ai beaucoup des warning (13 warning):

1>------ Début de la génération : Projet : inters, Configuration : Debug Win32 ------
1>Compilation en cours...
1>main.c
1>c:\inters\inters\main.c(23) : warning C4996: 'strncpy': This function or variable may be unsafe. Consider using strncpy_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
1> c:\program files\microsoft visual studio 9.0\vc\include\string.h(157) : voir la déclaration de 'strncpy'
1>c:\inters\inters\main.c(199) : warning C4996: 'fopen': This function or variable may be unsafe. Consider using fopen_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
1> c:\program files\microsoft visual studio 9.0\vc\include\stdio.h(237) : voir la déclaration de 'fopen'
1>c:\inters\inters\main.c(201) : warning C4996: 'fopen': This function or variable may be unsafe. Consider using fopen_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
1> c:\program files\microsoft visual studio 9.0\vc\include\stdio.h(237) : voir la déclaration de 'fopen'
1>c:\inters\inters\main.c(311) : warning C4047: 'fonction' : 'const char *' diffère de 'char **' dans les niveaux d'indirection
1>c:\inters\inters\main.c(311) : warning C4024: 'strlen' : types différents pour le paramètre formel et réel 1
1>c:\inters\inters\main.c(313) : warning C4047: 'fonction' : 'const char *' diffère de 'char **' dans les niveaux d'indirection
1>c:\inters\inters\main.c(313) : warning C4024: 'strlen' : types différents pour le paramètre formel et réel 1
1>c:\inters\inters\main.c(313) : warning C4018: '<' : incompatibilité signed/unsigned
1>c:\inters\inters\main.c(315) : warning C4047: 'fonction' : 'const char *' diffère de 'char **' dans les niveaux d'indirection
1>c:\inters\inters\main.c(315) : warning C4024: 'strlen' : types différents pour le paramètre formel et réel 1
1>c:\inters\inters\main.c(315) : warning C4018: '<' : incompatibilité signed/unsigned
1>c:\inters\inters\main.c(319) : warning C4996: 'strcpy': This function or variable may be unsafe. Consider using strcpy_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
1> c:\program files\microsoft visual studio 9.0\vc\include\string.h(74) : voir la déclaration de 'strcpy'
1>c:\inters\inters\main.c(365) : warning C4996: 'sprintf': This function or variable may be unsafe. Consider using sprintf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
1> c:\program files\microsoft visual studio 9.0\vc\include\stdio.h(366) : voir la déclaration de 'sprintf'
1>Édition des liens en cours...
1>Incorporation du manifeste en cours...
1>Le journal de génération a été enregistré à l'emplacement "file://c:\inters\inters\Debug\BuildLog.htm"
1>inters - 0 erreur(s), 13 avertissement(s)
======== Génération : 1 a réussi, 0 a échoué, 0 mis à jour, 0 a été ignoré ==========

Avez-vous une autre propoistion ?

Merci.
Messages postés
3834
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
20 octobre 2021
124
for(i=0;i<strlen(tab1);i++)


Il ne faut pas faire cela. D'une part tab1 est un tableau de chaîne de caractères et non pas une chaîne de caractère.
De plus, on ne met pas de fonction dans un "for" sinon celle-ci est appelé autant de fois qu'il y a de tour de boucle... Autant dire que niveau performance ce n'est pas terrible !

Commence par coder la fonction "is_in_tab" décrite précédemment.

Pour parcourir le tableau il suffit de faire comme dans les autre fonction, de vérifier s'il n'est pas nul (tab) et de vérifier que l'élément en cours n'est pas nul (*tab), et d'avancer (tab++).
Soit:

if (tab && *tab)
{
  // Opérations
  tab++;
}
Messages postés
393
Date d'inscription
lundi 22 juin 2009
Statut
Membre
Dernière intervention
23 décembre 2011
5
Bonjour,

Voici une version de la fonction "compute_intersect" :
int is_in_tab(char *str, char **tab2))
{
 if(tab2 &&*tab2)
  {
   if(strcmp(str,*tab2))
   return 1;
  tab2++	  
  }
 return 0;
}


char** compute_intersect(char** tab1, char** tab2)

{

char** inter = NULL;
int i,j;

  if (!tab2)

    return NULL;

  if (!tab1)

    return copy_tab(tab2);

  // Ici finir de coder l'intersection 
   

  if(tab1 &&*tab1)
  {
   if(is_in_tab(*tab1,tab2))

  tab1++	  
  }
 // ? comment on va allouer le tab inter
  // ? comment on va sauvegarder la chaine trouvée dans inter
   return inter; 

 }



Pouvez vous proposez la solution ?

Merci.
Messages postés
3834
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
20 octobre 2021
124
As-tu tester la fonction is_in_tab ? En l'état elle ne compilera pas, et ne te donnera pas le bon résultat.

Pouvez vous proposez la solution ?

Non, je veux bien te corriger, mais pas te donner la solution.

Tu n'es plus très loin de réussir.
Messages postés
393
Date d'inscription
lundi 22 juin 2009
Statut
Membre
Dernière intervention
23 décembre 2011
5
Bonsoir,
J'ai modifié un peu le code.
La compilation de passe bien mais l'exécution ne se termine pas de manière correcte. Je crois que le probème est dans la fonction "compute_intersect".
J'ai le message suivant:

Debug Assertion Failed!
Program: c:\inters\Debug\inters.exe
File: f:\dd\vctools\crt_bld\self_x86\crt\src\dbgheap.c
Line : 1317

Expression: _crtIsValidHeaPointer(pUserData)


Voici le code de la fonction "compute_intersect"

int is_in_tab(char *str, char **tab2)
{

 if(tab2 &&*tab2)
  {

   if(strcmp(str,*tab2))

   return 1;

  tab2++;	  

  }

 return 0;

}


char** compute_intersect(char** tab1, char** tab2)
{

char** inter = NULL;


  if (!tab2
    return NULL;

  if (!tab1)
    return copy_tab(tab2);



  // Ici finir de coder l'intersection 

   



  if(tab1 &&*tab1)

  {

   if(is_in_tab(*tab1,tab2))



  tab1++	  

  }

 // ? comment on va allouer le tab inter

  // ? comment on va sauvegarder la chaine trouvée dans inter

   return inter; 

 }



- comment on va allouer le tab inter

- comment on va sauvegarder la chaine trouvée dans inter

- Quelle est la modification à faire pour obtenir le résultat souhaité ? 



Merci.
Messages postés
393
Date d'inscription
lundi 22 juin 2009
Statut
Membre
Dernière intervention
23 décembre 2011
5
une petite modification à la fonction
C'est !strcmp(str,*tab2)) ou lieu de strcmp(str,*tab2))
int is_in_tab(char *str, char **tab2)

{



 if(tab2 &&*tab2)

  {



   if(!strcmp(str,*tab2))



   return 1;



  tab2++;	  



  }



 return 0;



}



je serais très contente pour votre aide.
Messages postés
3834
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
20 octobre 2021
124
La fonction is_in_tab est maintenant correcte.

Pour la fonction compute_intersect, je vais te mettre quoi faire:
Il te faut déclarer une nouvelle variable qui contiendra le résultat de l'intersection (tu l'as appelé "inter").
Ensuite, ton raisonnement semble correcte, il ne te manque que le remplissage de ce tableau. Pour cela il suffit de dire que le tableau est augmenté d'une case (à l'aide realloc) et que dans cette case tu mets une copie (strndup) de la chaîne trouvée. N'oublie pas de mettre une case en plus pour mettre un 0 terminal (on s'en sert pour marquer la fin du tableau).

char** compute_intersect(char** tab1, char** tab2)
{
   char** inter = NULL;
   int nb = 0; // Nombre d'élément trouvé

  if (!tab2
    return NULL;

  if (!tab1)
    return copy_tab(tab2);

  // Ici finir de coder l'intersection

  // Pourquoi un if ? Si tu veux boucler il te faut un while
  if(tab1 &&*tab1)
  {
   if(is_in_tab(*tab1,tab2))
   {
     // Ici dire que le nb d'élément trouvé est incrémenté de 1
     // On augmente la taille de inter, de 1
     // On copie la chaîne trouvé dans inter
     // On met un 0 terminal
   }
   tab1++;
  }
  // On pense ensuite à libérer l'ancien tableau de résultat.

 return inter; // Enfin on retourne le résultat final.
}
Messages postés
393
Date d'inscription
lundi 22 juin 2009
Statut
Membre
Dernière intervention
23 décembre 2011
5
Bonjour,
Voici une autre version de code de la fonction "compute_intersect" :

int is_in_tab(char *str, char **tab2)
{
 while(tab2 &&*tab2)
  {
   if(!strcmp(str,*tab2))
   return 1;
  tab2++;	  
  }
 return 0;
}


char** compute_intersect(char** tab1, char** tab2)

{

   char** inter = NULL;

   int nb = 0; // Nombre d'élément trouvé



  if (!tab2)

    return NULL;



  if (!tab1)

    return copy_tab(tab2);



  // Ici finir de coder l'intersection



  // Pourquoi un if ? Si tu veux boucler il te faut un while

  while(tab1 &&*tab1)

  {

   if(is_in_tab(*tab1,tab2))

   {

     nb++;// Ici dire que le nb d'élément trouvé est incrémenté de 1

     inter = realloc(inter, (nb + 1) * sizeof (char*));// On augmente la taille de inter, de 1

     	inter[nb - 1] = strndup(*tab1, strlen(*tab1) - 1);// On copie la chaîne trouvé dans inter

    inter[nb] = 0; // On met un 0 terminal
  
   }

   tab1++;

  }

  // On pense ensuite à libérer l'ancien tableau de résultat.



 return inter; // Enfin on retourne le résultat final.

}

Messages postés
393
Date d'inscription
lundi 22 juin 2009
Statut
Membre
Dernière intervention
23 décembre 2011
5
Bonjour,

Après la compilation et l'exécution,
J'obtiens:

Comparing f.txt and f1.txt:
a b
b d
c d
a b c
a b d
b c d
a c d
a b c d
Comparing f.txt and f2.txt:
a c
b d
a b c
a b d
b c d
a c d
a b c d

Comparing f.txt and f3.txt:
b d
c d
a b c
a b d
b c d
a c d
a b c d
Final result:


Je ne sais pas pourquoi il n' y pas affichage de la partie "Final result" ?
Cette affichage se fait par la fonction
"display_tab(intersect)"

et voici le code de programme complet:
[code=cpp]
#include <stdio.h>

#include <stdlib.h>

#include <string.h>



#define MAX_SIZE 1024



char* strndup(const char *str, size_t n)

{

char *ret = malloc((n+1) * sizeof (char));



if (!ret)
exit(0);
strncpy(ret, str, n);

ret[n] = 0;



return ret;

}



void free_tab(char** t)

{

char** head = t;



while (t && *t)

{

free(*t);

t++;



}

free(head);

}



char** get_word(const char* str)

{

char* pos = NULL;

char** res = NULL;

int nb = 0;



do

{

int size = 0;



pos = strchr(str, ' ');

if (pos)

size = pos - str; else

size = strlen(str) - 1; /* - 1 to get rid of \n */

nb++;

res = realloc(res, (nb + 1) * sizeof (char*));

res[nb -1] = strndup(str, size);

str = pos + 1;

}

while (pos);



res[nb] = 0;



return res;

}



int is_same(const char* const s1, const char* const s2)

{

char **t1, **t2;

int ret = 0;



t1 = get_word(s1);

t2 = get_word(s2);



if (t1 && t2)

{

char** tab1 = t1;

char** tab2 = t2;

int nb = 0;

int size = 0;



while (tab1 && *tab1)

{

tab2 = t2;

while (tab2 && *tab2)

{

if (!strcmp(*tab1, *tab2))

nb++;

tab2++;

} tab1++;

size++;

}



ret = (nb >= size);

free_tab(t1);

free_tab(t2);

}



return ret;

}



char** compare_file(const char* filename1, const char* filename2)

{

FILE *f, *f1;

char s[MAX_SIZE], s1[MAX_SIZE];

int a;

char** res = NULL;

int nb = 0;



f = fopen(filename1, "r");

f1 = fopen(filename2, "r");

if (f && f1)

{

while (fgets(s, MAX_SIZE, f))

{

a = 0;

rewind(f1);

while (fgets(s1, MAX_SIZE, f1))

{

if (is_same(s, s1))

{

a = 1;

break;

}

}

if (!a)

{

nb++;

res = realloc(res, (nb + 1) * sizeof (char*));

res[nb - 1] = strndup(s, strlen(s) - 1); /* Get rid of the \n */

res[nb] = 0;

}

}

fclose(f);

fclose(f1);

}



return res;

}



char** copy_tab(char** tab)

{

char** res = NULL;

int nb = 0;



while (tab && *tab)

{

nb++;

res = realloc(res, (nb + 1) * sizeof (char*));

res[nb - 1] = strndup(*tab, strlen(*tab));

res[nb] = 0;

tab++;

}



return res;

}

int is_in_tab(char *str, char **tab2)
{
while(tab2 &&*tab2)
{
if(!strcmp(str,*tab2))
return 1;
tab2++;
}
return 0;
}


char** compute_intersect(char** tab1, char** tab2)

{

char** inter = NULL;

int nb = 0; // Nombre d'élément trouvé



if (!tab2)

return NULL;



if (!tab1)

return copy_tab(tab2);



// Ici finir de coder l'intersection



// Pourquoi un if ? Si tu veux boucler il te faut un while

while(tab1 &&*tab1)

{

if(is_in_tab(*tab1,tab2))

{

nb++;// Ici dire que le nb d'élément trouvé est incrémenté de 1

inter = realloc(inter, (nb + 1) * sizeof (char*));// On augmente la taille de inter, de 1

inter[nb - 1] = strndup(*tab1, strlen(*tab1) - 1);// On copie la chaîne trouvé dans inter

inter[nb] = 0; // On met un 0 terminal

}

tab1++;

}

// On pense ensuite à libérer l'ancien tableau de résultat.



return inter; // Enfin on retourne le résultat final.

}


void display_tab(char** tab)
{
while (tab && *tab)
{

printf("%s\n", *tab);

tab++;

}
}


int main()

{

char** res = NULL;

char** intersect = NULL;

char input[32];

int i;



for (i = 1; i <= 3; i++)

{

sprintf(input,"f%d.txt",i);

res = compare_file("f.txt",input);

/* temp */

printf("Comparing f.txt and %s:\n", input);

display_tab(res);

/* ! temp */

intersect = compute_intersect(intersect, res);

free_tab(res);

}

printf("Final result:\n");

display_tab(intersect);

free_tab(intersect);

return 0;

}

[code=cpp]
Messages postés
3834
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
20 octobre 2021
124
Le code de la fonction compute_intersect est maintenant presque correcte, félicitations.

2 petites choses:
inter[nb - 1] = strndup(*tab1, strlen(*tab1) - 1);

Inutile de mettre un "- 1", "strlen(*tab1)" suffira. En effet, ici il n'y a déjà plus de \n, donc si tu refais un "- 1", tu risques de couper un morceau de mots que tu voudrais garder.

Ensuite, il te faut penser à libérer l'ancien "intersect", qui est normalement ton "tab1".

Si tu n'as pas d'affichage du résultat final, vérifie la valeur de "inter" juste avant l'appel à "display_tab".
Messages postés
393
Date d'inscription
lundi 22 juin 2009
Statut
Membre
Dernière intervention
23 décembre 2011
5
Bonjour,
Voici une version de la fonction "compute_intersect"

int is_in_tab(char *str, char **tab2)
{
 while(tab2 &&*tab2)
  {
   if(!strcmp(str,*tab2))
   return 1;
  tab2++;	  
  }
 return 0;
}


char** compute_intersect(char** tab1, char** tab2)

{

   char** inter = NULL;

   int nb = 0; // Nombre d'élément trouvé



  if (!tab2)

    return NULL;



  if (!tab1)

    return copy_tab(tab2);



  // Ici finir de coder l'intersection

  while(tab1 &&*tab1)

  {

   if(is_in_tab(*tab1,tab2))

   {

     nb++;// Ici dire que le nb d'élément trouvé est incrémenté de 1

     inter = realloc(inter, (nb + 1) * sizeof (char*));// On augmente la taille de inter, de 1

     	inter[nb - 1] = strndup(*tab1, strlen(*tab1));// On copie la chaîne trouvé dans inter

    inter[nb] = 0; // On met un 0 terminal
  
   }

   tab1++;

  }

  // On pense ensuite à libérer l'ancien tableau de résultat.

 free_tab(tab1);

 return inter; // Enfin on retourne le résultat final.

}


void display_tab(char** tab)
{
  while (tab && *tab)
  {

   printf("%s\n", *tab);

   tab++;

  } 
}


et voici le programme complet:
#include <stdio.h>

#include <stdlib.h>

#include <string.h>



#define MAX_SIZE 1024



char* strndup(const char *str, size_t n)

{

  char *ret = malloc((n+1) * sizeof (char));



  if (!ret)
    exit(0);  
  strncpy(ret, str, n);

  ret[n] = 0;



  return ret;

}



void free_tab(char** t)

{

  char** head = t;



  while (t && *t)

  {

    free(*t);

    t++;



  }

  free(head);

}



char** get_word(const char* str)

{

  char* pos = NULL;

  char** res = NULL;

  int nb = 0;



  do

  {

    int size = 0;



    pos = strchr(str, ' ');

    if (pos)

      size = pos - str;    else

      size = strlen(str) - 1; /* - 1 to get rid of \n */

    nb++;

    res = realloc(res, (nb + 1) * sizeof (char*));

    res[nb -1] = strndup(str,  size);

    str = pos + 1;

  }

  while (pos);



  res[nb] = 0;



  return res;

}



int is_same(const char* const s1, const char* const s2)

{

  char **t1, **t2;

  int ret = 0;



  t1 = get_word(s1);

  t2 = get_word(s2);



  if (t1 && t2)

  {

    char** tab1 = t1;

    char** tab2 = t2;

    int nb = 0;

    int size = 0;



    while (tab1 && *tab1)

    {

      tab2 = t2;

      while (tab2 && *tab2)

      {

if (!strcmp(*tab1, *tab2))

  nb++;

tab2++;

      }      tab1++;

      size++;

    }



    ret = (nb >= size);

    free_tab(t1);

    free_tab(t2);

  }



  return ret;

}



char** compare_file(const char* filename1, const char* filename2)

{

  FILE *f, *f1;

  char s[MAX_SIZE], s1[MAX_SIZE];

  int a;

  char** res = NULL;

  int nb = 0;



  f = fopen(filename1, "r");

  f1 = fopen(filename2, "r");

  if (f && f1)

  {

    while (fgets(s, MAX_SIZE, f))

    {

      a = 0;

      rewind(f1);

      while (fgets(s1, MAX_SIZE, f1))

      {

if (is_same(s, s1))

{

  a = 1;

  break;

}

      }

      if (!a)

      {

nb++;

res = realloc(res, (nb + 1) * sizeof (char*));

res[nb - 1] = strndup(s, strlen(s) - 1); /* Get rid of the \n */

res[nb] = 0;

      }

    }

    fclose(f);

    fclose(f1);

  }



  return res;

}



char** copy_tab(char** tab)

{

  char** res = NULL;

  int nb = 0;



  while (tab && *tab)

  {

    nb++;

    res = realloc(res, (nb + 1) * sizeof (char*));

    res[nb - 1] = strndup(*tab, strlen(*tab));

    res[nb] = 0;

    tab++;

  }



  return res;

}

int is_in_tab(char *str, char **tab2)
{
 while(tab2 &&*tab2)
  {
   if(!strcmp(str,*tab2))
   return 1;
  tab2++;	  
  }
 return 0;
}


char** compute_intersect(char** tab1, char** tab2)

{

   char** inter = NULL;

   int nb = 0; // Nombre d'élément trouvé



  if (!tab2)

    return NULL;



  if (!tab1)

    return copy_tab(tab2);



  // Ici finir de coder l'intersection

  while(tab1 &&*tab1)

  {

   if(is_in_tab(*tab1,tab2))

   {

     nb++;// Ici dire que le nb d'élément trouvé est incrémenté de 1

     inter = realloc(inter, (nb + 1) * sizeof (char*));// On augmente la taille de inter, de 1

     	inter[nb - 1] = strndup(*tab1, strlen(*tab1));// On copie la chaîne trouvé dans inter

    inter[nb] = 0; // On met un 0 terminal
  
   }

   tab1++;

  }

  // On pense ensuite à libérer l'ancien tableau de résultat.

 free_tab(tab1);

 return inter; // Enfin on retourne le résultat final.

}


void display_tab(char** tab)
{
  while (tab && *tab)
  {

   printf("%s\n", *tab);

   tab++;

  } 
}


int main()

{

  char** res = NULL;

 char** intersect = NULL;

  char input[32];

  int i;

  for (i = 1; i <= 3; i++)
  {
    sprintf(input,"f%d.txt",i);

    res = compare_file("f.txt",input);

    /* temp */

    printf("Comparing f.txt and %s:\n", input);

    display_tab(res);

    /* ! temp */

    intersect = compute_intersect(intersect, res);

    free_tab(res);
 
  }

  printf("Final result:\n");
  if (intersect == NULL)
  printf("erreur\n");

  display_tab(intersect);

  free_tab(intersect);
 
  return 0;

}
Messages postés
393
Date d'inscription
lundi 22 juin 2009
Statut
Membre
Dernière intervention
23 décembre 2011
5
La compilation se passe bien. Mais, l'exécution ne se termine pas correctement.

J'ai l'affichage suivant:
Comparing f.txt and f1.txt:
a b
b d
c d
a b c
a b d
b c d
a c d
a b c d
Comparing f.txt and f2.txt:
a c
b d
a b c
a b d
b c d
a c d
a b c d


et apparaition d'une fenetre qui affiche:
Debug assertion Failed!
Program :
File :f:\dd\vctools\crt_bld\self_x86\crt\src\dbgheap.c
Expression : _CrtIsValidHeapPointer(pUserData)
Line : 1317


A mon avis, je vois que realloc()peut conduire dans certains cas à une fuite mémoire.
Quand on utilise malloc() et realloc() ?

Peut être chez vous il y a pas problème de mémoire. Alors peut être chez moi, il a problème de l'espace mémoire.
Quels sont les tests à ajouter au programme pour assurer que nous avons bien alloués de la mémoire, que nous avons bien libérer les espaces mémoires utilisées, que les fichiers utilisés sont bien ouverts et fermants, que les chaines e caractères passées comme paramètres sont valides etc... ?

Je suis bloquée et j'ai besoin de votre aide.

Merci.
Messages postés
393
Date d'inscription
lundi 22 juin 2009
Statut
Membre
Dernière intervention
23 décembre 2011
5
Bonsoir,

Pouvez vous poster votre dernière solution qui marche bien chez vous ?
Messages postés
3834
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
20 octobre 2021
124
Voici la version qui fonctionne chez moi. Elle n'est pas vraiment différente de la tienne.

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

#define MAX_SIZE 1024

char* strndup(const char *str, size_t n)
{
  char *ret = malloc((n+1) * sizeof (char));

  if (!ret)
    exit(0);  strncpy(ret, str, n);
  ret[n] = 0;

  return ret;
}

void free_tab(char** t)
{
  char** head = t;

  while (t && *t)
  {
    free(*t);
    t++;
  }
  free(head);
}

char** get_word(const char* str)
{
  char* pos = NULL;
  char** res = NULL;
  int nb = 0;

  do
  {
    int size = 0;

    pos = strchr(str, ' ');
    if (pos)
      size = pos - str;
    else
      size = strlen(str) - 1; /* - 1 to get rid of \n */
    nb++;
    res = realloc(res, (nb + 1) * sizeof (char*));
    res[nb -1] = strndup(str,  size);
    str = pos + 1;
  }
  while (pos);

  res[nb] = 0;

  return res;
}

int is_same(const char* const s1, const char* const s2)
{
  char **t1, **t2;
  int ret = 0;

  t1 = get_word(s1);
  t2 = get_word(s2);

  if (t1 && t2)
  {
    char** tab1 = t1;
    char** tab2 = t2;
    int nb = 0;
    int size = 0;

    while (tab1 && *tab1)
    {
      tab2 = t2;
      while (tab2 && *tab2)
      {
if (!strcmp(*tab1, *tab2))
  nb++;
tab2++;
      }
      tab1++;
      size++;
    }

    ret = (nb >= size);
    free_tab(t1);
    free_tab(t2);
  }

  return ret;
}

char** compare_file(const char* filename1, const char* filename2)
{
  FILE *f, *f1;
  char s[MAX_SIZE], s1[MAX_SIZE];
  int a;
  char** res = NULL;
  int nb = 0;

  f = fopen(filename1, "r");
  f1 = fopen(filename2, "r");
  if (f && f1)
  {
    while (fgets(s, MAX_SIZE, f))
    {
      a = 0;
      rewind(f1);
      while (fgets(s1, MAX_SIZE, f1))
      {
if (is_same(s, s1))
{
  a = 1;
  break;
}
      }

      if (!a)
      {
nb++;
res = realloc(res, (nb + 1) * sizeof (char*));
res[nb - 1] = strndup(s, strlen(s) - 1); /* Get rid of the \n */
res[nb] = 0;
      }
    }
    fclose(f);
    fclose(f1);
  }

  return res;
}

char** copy_tab(char** tab)
{
  char** res = NULL;
  int nb = 0;

  while (tab && *tab)
  {
    nb++;
    res = realloc(res, (nb + 1) * sizeof (char*));
    res[nb - 1] = strndup(*tab, strlen(*tab));
    res[nb] = 0;
    tab++;
  }

  return res;
}

int is_in_tab(char* str, char** tab)
{
  while (tab && *tab)
  {
    if (!strcmp(str, *tab))
      return 1;
    tab++;
  }

  return 0;
}

char** compute_intersect(char** tab1, char** tab2)
{
  char** head = tab1;
  char** res = NULL;
  int nb = 0;

  if (!tab2)
    return NULL;

  if (!tab1)
    return copy_tab(tab2);

  while (tab1 && *tab1)
  {
    if (is_in_tab(*tab1, tab2))
    {
      nb++;
      res = realloc(res, (nb + 1) * sizeof (char*));
      res[nb - 1] = strndup(*tab1, strlen(*tab1));
      res[nb] = 0;
    }
    tab1++;
  }
  free_tab(head);

  return res;
}

void display_tab(char** tab)
{
  while (tab && *tab)
  {
    printf("%s\n", *tab);
    tab++;
  }
}

int main()
{
  char** res = NULL;
  char** intersect = NULL;
  char input[32];
  int i;

  for (i = 1; i <= 3; i++)
  {
    sprintf(input,"f%d.txt", i);
    res = compare_file("f.txt", input);
    /* temp */
    printf("Comparing f.txt and %s:\n", input);
    display_tab(res);
    /* ! temp */
    intersect = compute_intersect(intersect, res);
    free_tab(res);
  }

  printf("Final result:\n");
  display_tab(intersect);
  free_tab(intersect);

  return 0;
}
Messages postés
3834
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
20 octobre 2021
124
Pour information ce qui n'allait pas dans ton code était:

Tu libère "tab1" dans la fonction "compute_intersect". Or "tab1" n'est pas au début mais à été avancé. Pour libérer une ressource tu dois donner le début de la ressource. Ainsi, quand tu faisais appel à "free_tab(tab1)", le programme plantait.
Il faut se souvenir de la tête, et libérer celle-ci une fois le travail réaliser.
char* head = tab1;
/* Traitement contenant de tab1++ */
free_tab(head); /* et non free_tab(tab1)*/
Messages postés
393
Date d'inscription
lundi 22 juin 2009
Statut
Membre
Dernière intervention
23 décembre 2011
5
Bonsoir,


Voici la version qui fonctionne chez moi. Elle n'est pas vraiment différente de la tienne.

J'ai pris le même code que vous et qui est daté le dimanche 6 septembre 2009 à 22:39:05.
Après la compilation et l'exécution, j'obtiens:

Comparing f.txt and f1.txt:
Comparing f.txt and f2.txt:
Comparing f.txt and f3.txt:
Final result:
Appuyez sur une touche pour continuer...


Mais, je ne vois aucun affichage.
Messages postés
393
Date d'inscription
lundi 22 juin 2009
Statut
Membre
Dernière intervention
23 décembre 2011
5
Bonsoir,

Pardon, j'obtiens cet affichage:
Comparing f.txt and f1.txt:
b d
c d
a b d
b c d
a c d
a b c d
Comparing f.txt and f2.txt:
b d
a b d
b c d
a c d
a b c d
Comparing f.txt and f3.txt:
b d
c d
a b d
b c d
a c d
a b c d
Final result:
b d
a b d
b c d
a c d
a b c d


Dans ce problème, il reste un petit truc qui consiste à laisser de résultat final que les chaines de caractères qui ne sont pas incluses dans les autres chaines de caractères.
on a :
"a b d" contient "b d" donc on ne la garde pas.
"b c d" contient "b d" donc on ne la garde pas.
"a b c d" contient "b d" donc on ne la garde pas.

et donc on obtient comme résultat final qui est le but de ce problème:
b d
a c d

Quelles sont les modifications à faire dans le code au dessus ?

Merci.