Programme en C

Résolu
jamsss Messages postés 36 Statut Membre -  
jamsss Messages postés 36 Statut Membre -
Bonjour,

J'ai écrit le code suivant en C, c'est un correcteur orthographique (comparaison entre les mots d'un fichier texte et ceux d'un fichier dico)

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

short dichotomie(char **dico,char *mot_texte,int nbmots);
void ajout(char **dico, char *mot_texte, int findico);
char *sup_ponc(char *mot_texte);
char *sup_maj(char *mot_texte);
int compare_mots(const void *a, const void *b);

#define MAXMOTS 100
#define LONGMOT 20

int main(int argc,char *argv[])
{
 /*Déclarations des fichiers*/
 FILE *fichiertexte;
 FILE *fichierdico;

 /*Déclarations des variables*/
 int i,findico,nbmots;
 char reponse[1];

 /*Déclarations des pointeurs*/
 char **dico;
 char *mot_texte;

 /*Allocation des pointeurs*/
 mot_texte=malloc(MAXMOTS*sizeof(char *));
 dico=malloc(MAXMOTS*LONGMOT*sizeof(char **));

 /*Vérification du nombre d'arguments corrects à l'appel*/
 if (argc!=2)
  {
   printf("Erreur dans le nombre d'arguments\n");
   exit(EXIT_FAILURE);
  }

 /*Ouverture des fichiers en lecture*/
 fichiertexte=fopen(argv[1],"r");
 if (fichiertexte==NULL)
  {
   printf("Impossible d'ouvrir %s.\n", argv[1]);
   exit(EXIT_FAILURE);
  }
 fichierdico=fopen("dico.dat","r");

 /*Lecture du fichier dico et stockage en mémoire dans le tabeau dico*/
 for(findico=0;!feof(fichierdico);findico++) fscanf((fichierdico),"%s",dico[findico]);

 /*Fermeture du fichier dico.dat*/
 fclose(fichierdico);

 /*Tri du tableau dico*/
 qsort((char**)dico,MAXMOTS,LONGMOT,compare_mots);

 /*Lecture et traitement du fichier texte*/
 nbmots=0;
 while(!feof(fichiertexte))
 {
  fscanf(fichiertexte,"%s",mot_texte);
  mot_texte=sup_ponc(mot_texte);
  mot_texte=sup_maj(mot_texte);
  nbmots++;
  if (dichotomie(dico,mot_texte,nbmots)==0) 
   {
    printf("Le mot n'est pas dans le dictionnaire, voulez vous le rajouter (o/n) ?\n");
    scanf("%s",reponse);
    while((reponse[0]!='o') && (reponse[0]!='n'))
     {
      printf("Réponse invalide, recommencez\n");
      scanf("%s",reponse);
     }
    if(reponse[0]=='o') ajout(dico,mot_texte,findico);
   }
 }

 /*Fermeture du fichier texte*/
 fclose(fichiertexte);

 /*Ouverture du fichier dico, écriture des éléments du tableau et fermeture*/
 fichierdico=fopen("dico.dat","w");
 for(i=0;i<=findico;i++) fprintf(fichierdico,"%s",dico[i]);
 fclose(fichierdico);

 /*Libération des pointeurs en mémoire*/
 free(mot_texte);
 free(dico);

 return 0;
}

char *sup_ponc(char *mot)
 {
  int lettre, lettresuiv;
  for(lettre=0,lettresuiv=0;mot[lettresuiv];lettresuiv++)
   {
    mot[lettre]=mot[lettresuiv];
    /* Si le caractère est une ponctuation, on l'ignore*/
    if (ispunct(mot[lettresuiv])!=1) lettre++;
   }
  /*Pour terminer la chaîne:*/
  mot[lettre]='\0';
  return mot;
 }

char *sup_maj(char *mot)
 {
  int lettre;
  for (lettre=0;mot[lettre];lettre++)
   {
    if (isupper(mot[lettre])) mot[lettre]=tolower(mot[lettre]);
   }
  return mot;
 }

short dichotomie(char **dico,char *mot,int nbmots)
{
 int i,j,k;
 i=0;
 j=nbmots;
 while ((j-i)>1)
  {
   k=i+((j-i)/2);
   if (((j-i)%2)==0) k++;
   if (strcmp(mot,dico[k-1])==0) return 1;
   if (strcmp(mot,dico[k-1])<0) j=(k-1);
   else i=(k-1);
  }
 if ((strcmp(dico[i],mot)==0) || (strcmp(dico[j],mot)==0)) return 1;
  else return 0;
}

void ajout(char **dico,char *mot_texte,int findico)
 {
  /*Si le le nombre de mots est supérieur à MAXMOTS, on affiche une erreur sinon on ajoute le mot a la fin du tableau*/
  if(findico!=MAXMOTS)
   {
    dico[findico+1]=mot_texte;
    findico++;
   }
  else
   {
    printf("Vous avez dépassé le nombre de mots maximal du dictionnaire");
    exit(EXIT_FAILURE);
   }
   /*On retri le tableau*/
   qsort((char**)dico, MAXMOTS,LONGMOT,compare_mots);
 }

int compare_mots(const void *chaine1, const void *chaine2)
 {
 return strcmp(chaine1,chaine2);
 }


Le problème est que GCC me donne une erreur de segmentation dès le début de l'exécution du programme mais ne me donne aucune erreur, aucun warning même avec -wall, je ne comprends pas quel est le problème

Merci d'avance de votre aide

Jamsss

11 réponses

jamsss Messages postés 36 Statut Membre
 
Problème d'allocation de double pointeur... quel gland je fais ;-p
0
Giorgiolino Messages postés 270 Statut Contributeur 52
 
Bonjour,

pour faire encore moins gland, un petit "résolu" peut être utile aussi.

Cordialement.
0
jamsss Messages postés 36 Statut Membre
 
Sauf que je n'ai pas mis résolu parce que le problème ne l'est pas... J'ai mis ceci

for(findico=0;!feof(fichierdico);findico++)
{
dico[findico]=malloc(LONGMOT*sizeof(char*));
fscanf(fichierdico,"%s",dico[findico]);
}

pour allouer mon pointeur de tableau de char mais gdb me dit ça :

(gdb) run texte.txt
Starting program: /home/christophe/Test_C/D8.2 texte.txt

Program received signal SIGSEGV, Segmentation fault.
0x000000000040095e in main (argc=2, argv=0x7fff3a234db8) at D8.2.c:51
51 dico[findico]=malloc(LONGMOT*sizeof(char*));
Missing debug package(s), you should install: glibc-debug-2.9-0.20081113.5mnb2.x86_64
(gdb) bt full
#0 0x000000000040095e in main (argc=2, argv=0x7fff3a234db8) at D8.2.c:51
fichiertexte = (FILE *) 0x7c80c0
fichierdico = (FILE *) 0x7c8300
i = 0
findico = 0
reponse = ""
dico = (char **) 0x4007c0
mot_texte = 0x7c8010 ""
(gdb)

Merci d'avance
0
fiddy Messages postés 11653 Statut Contributeur 1 847
 
Salut,
J'ai pas tout lu, mais je vois des erreurs.
Notamment, l'erreur d'allocation sur le double pointeur.
Tu alloues le double pointeur dico. Ce qui t'assure que dico pointera bien vers une zone du heap. Mais, l'allocation de dico[i] n'est pas fait. Il faut donc réaliser l'allocation sur dico[i] avec une simple boucle for.

De plus, char reponse[1] ne sert à rien. Autant mettre : char reponse et utiliser getchar(); pour récupérer un caractère. Soit si tu veux impérativement passer par scanf %s et un tableau de char, tu devras utiliser char reponse[2]; le second caractère étant le '\0'. Mais tu devras bien penser à vider le buffer clavier après pour éliminer le '\n'. Par ailleurs attention au cas où l'utilisateur entre une chaîne bien plus grande qu'un simple caractère. Cela te provoquerait bien des surprises dans ton programme.

De plus, en C, tu dois toujours vérifier que l'allocation s'est bien déroulée en testant la valeur de retour, de même pour les fopen etc.

Cdlt
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
jamsss Messages postés 36 Statut Membre
 
Salut,

pour l'allocation du double pointeur c'est ce que j'ai dit plus haut j'ai remplacé le:

dico=malloc(MAXMOTS*LONGMOT*sizeof(char **));

par

for(findico=0;!feof(fichierdico);findico++)
{
dico[findico]=malloc(LONGMOT*sizeof(char*));
fscanf(fichierdico,"%s",dico[findico]);
}


mais j'ai toujours cette erreur de segmentation

Pour le réponse[1] ça fonctionne très bien (testé sur un autre programme), on ne peut pas rentrer d'autres valeurs que 'o' ou 'n' grace à :

while((reponse[0]!='o') && (reponse[0]!='n'))
{
printf("Réponse invalide, recommencez\n");
scanf("%s",reponse);
purger();
}

;)
0
fiddy Messages postés 11653 Statut Contributeur 1 847
 
dico=malloc(MAXMOTS*LONGMOT*sizeof(char **));
Il faut faire sizeof(char*);

dico[findico]=malloc(LONGMOT*sizeof(char*));
il faut mettre sizeof(char).

Pour le réponse[1] ça fonctionne très bien (testé sur un autre programme), on ne peut pas rentrer d'autres valeurs que 'o' ou 'n' grace à :
Il est possible que ça marche. Mais il n'empêche que c'est faux. Tu utilises %s dans ton scanf, il va donc mettre un \0 à la fin. Et donc il y aura un débordement d'un byte. Il suffit qu'il y ait une variable juste à côté dans la pile et tu changeras un byte au passage, ce qui est très gênant.
0
jamsss Messages postés 36 Statut Membre
 
Je remet le code à jour avec les corrections citées précédement:


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

short dichotomie(char **dico,char *mot_texte,int nbmots);
void ajout(char **dico, char *mot_texte, int findico);
char *sup_ponc(char *mot_texte);
char *sup_maj(char *mot_texte);
int compare_mots(const void *a, const void *b);
void purger();

#define MAXMOTS 100
#define LONGMOT 20

int main(int argc,char *argv[])
{
 /*Déclarations des fichiers*/
 FILE *fichiertexte;
 FILE *fichierdico;

 /*Déclarations des variables*/
 int i,findico;
 char reponse[1];

 /*Déclarations des pointeurs*/
 char **dico;
 char *mot_texte;

 /*Allocation du pointeur *mot_texte*/
 mot_texte=malloc(LONGMOT*sizeof(char*));
if (mot_texte==NULL)
 {
  fprintf(stderr,"Allocation impossible \n");
  exit(EXIT_FAILURE);
 }

 /*Vérification du nombre d'arguments corrects à l'appel*/
 if (argc!=2)
  {
   printf("Erreur dans le nombre d'arguments\n");
   exit(EXIT_FAILURE);
  }

 /*Ouverture des fichiers en lecture*/
 fichiertexte=fopen(argv[1],"r");
 if (fichiertexte==NULL)
  {
   printf("Impossible d'ouvrir %s.\n", argv[1]);
   exit(EXIT_FAILURE);
  }
 fichierdico=fopen("dico.dat","r");

 /*Lecture du fichier dico et stockage en mémoire dans le tabeau dico*/
 for(findico=0;!feof(fichierdico);findico++) 
  {
   dico[findico]=malloc(LONGMOT*sizeof(char*));
   fscanf(fichierdico,"%s",dico[findico]);
   if (dico[findico]==NULL)
    {
     fprintf(stderr,"Allocation impossible \n");
     exit(EXIT_FAILURE);
    }
  }

 /*Fermeture du fichier dico.dat*/
 fclose(fichierdico);

 /*Tri du tableau dico*/
 qsort((char**)dico,MAXMOTS,LONGMOT,compare_mots);

 /*Lecture et traitement du fichier texte*/
 while(!feof(fichiertexte))
 {
  fscanf(fichiertexte,"%s",mot_texte);
  mot_texte=sup_ponc(mot_texte);
  mot_texte=sup_maj(mot_texte);
  if (dichotomie(dico,mot_texte,findico-1)==0) 
   {
    printf("Le mot '%s' n'est pas dans le dictionnaire, voulez vous le rajouter (o/n) ?\n", mot_texte);
    scanf("%s",reponse);
    while((reponse[0]!='o') && (reponse[0]!='n'))
     {
      printf("Réponse invalide, recommencez\n");
      scanf("%s",reponse);
      purger();
     }
    if(reponse[0]=='o') ajout(dico,mot_texte,findico);
   }
 }

 /*Fermeture du fichier texte*/
 fclose(fichiertexte);

 /*Ouverture du fichier dico, écriture des éléments du tableau et fermeture*/
 fichierdico=fopen("dico.dat","w");
 for(i=0;i<=findico;i++) fprintf(fichierdico,"%s",dico[i]);
 fclose(fichierdico);

 /*Libération des pointeurs en mémoire*/
 free(mot_texte);
 free(dico);

 return 0;
}

char *sup_ponc(char *mot)
 {
  int lettre, lettresuiv;
  for(lettre=0,lettresuiv=0;mot[lettresuiv];lettresuiv++)
   {
    mot[lettre]=mot[lettresuiv];
    /* Si le caractère est une ponctuation, on l'ignore*/
    if (ispunct(mot[lettresuiv])!=1) lettre++;
   }
  /*Pour terminer la chaîne:*/
  mot[lettre]='\0';
  return mot;
 }

char *sup_maj(char *mot)
 {
  int lettre;
  for (lettre=0;mot[lettre];lettre++)
   {
    if (isupper(mot[lettre])) mot[lettre]=tolower(mot[lettre]);
   }
  return mot;
 }

short dichotomie(char **dico,char *mot,int nbmots)
{
 int i,j,k,x;
 i=0;
 j=nbmots;

  /*Allocation du pointeur **dico*/
 for(x=0;x<=(nbmots+1);x++) 
  {
   dico[x]=malloc(LONGMOT*sizeof(char));
   if (dico[x]==NULL)
    {
     fprintf(stderr,"Allocation impossible \n");
     exit(EXIT_FAILURE);
    }
  }

 while ((j-i)>1)
  {
   k=i+((j-i)/2);
   if (((j-i)%2)==0) k++;
   if (strcmp(mot,dico[k-1])==0) return 1;
   if (strcmp(mot,dico[k-1])<0) j=(k-1);
   else i=(k-1);
  }
 if ((strcmp(dico[i],mot)==0) || (strcmp(dico[j],mot)==0)) return 1;
  else return 0;
}

void ajout(char **dico,char *mot_texte,int findico)
 {
  /*Si le le nombre de mots est supérieur à MAXMOTS, on affiche une erreur sinon on ajoute le mot a la fin du tableau*/
  if(findico!=MAXMOTS)
   {
    dico[findico+1]=mot_texte;
    findico++;
   }
  else
   {
    printf("Vous avez dépassé le nombre de mots maximal du dictionnaire");
    exit(EXIT_FAILURE);
   }
   /*On retri le tableau*/
   qsort((char**)dico, MAXMOTS,LONGMOT,compare_mots);
 }

int compare_mots(const void *chaine1, const void *chaine2)
 {
 return strcmp(chaine1,chaine2);
 }

void purger(void)
 {
  int c;
  while ((c=getchar()) != '\n' && c != EOF)
  {}
 }



Et toujours cette erreur de segmentation détectée par gdb à cette ligne:

dico[findico]=malloc(LONGMOT*sizeof(char*));
0
heyquem Messages postés 808 Statut Membre 131
 
Cas typique d'un beau travail dans le principe qui est gaché dans sa concrétisation par l'obligation de se coltiner des préoccupations de niveau hardware dont le niveau de détail m'effraie:
Tu utilises %s dans ton scanf, il va donc mettre un \0 à la fin. Et donc il y aura 
un débordement d'un byte. Il suffit qu'il y ait une variable juste à côté dans la pile 
et tu changeras un byte au passage, ce qui est très gênant. 


Tout sujet portant sur une langue me semble pourtant relever d'un langage de plus haut niveau, pour pouvoir se concentrer sur les vraies questions intéressantes. Pourquoi avoir choisi de faire ce code en langage C ?? Je vois mal que la vitesse d'exécution soit un impératif.


Félicitations quand même , jamsss
0
jamsss Messages postés 36 Statut Membre
 
Bonjour,

pour répondre à ta question heyquem la raison pour laquelle j'ai écrit ce code en C est que c'est un devoir dans le cadre de de ma formation tout simplement je n'ai pas le choix du langage

;)
0
heyquem Messages postés 808 Statut Membre 131
 
Merci pour la réponse.

Un tel programme me semble demander un certain niveau de connaissance, et donc demandé par un prof qui doit quand même être bien expérimenté en informatique. J'espère donc que ce devoir n'est imposé en C que pour fournir un sujet sur lequel s'exercer en C. Il faut bien faire des programmes sur quelque chose. Le but étant le C, pas la correction orthographique.
0
jamsss Messages postés 36 Statut Membre
 
Bonjour,

Suite à vos remarques j'ai pu régler (je pense) les erreurs de segmentation par contre maintenant j'ai un autre soucis c'est que mon tableau dico[] ne contient pas vraiment les mots du texte mais après un test avec un printf il contient plutôt des choses de ce style : 0+��j ou P+��j ... Inutile de vous dire que pour la comparaison avec les mots du texte c'est pas génial... Voici le code:

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

short dichotomie(char **dico,char *mot_texte,short nbmots);
void ajout(char **dico, char *mot_texte, int findico);
char *sup_ponc(char *mot_texte);
char *sup_maj(char *mot_texte);
int compare_mots(const void *a, const void *b);
void purger();

#define MAXMOTS 100
#define LONGMOT 20

int main(int argc,char *argv[])
{
 /*Déclarations des fichiers*/
 FILE *fichiertexte;
 FILE *fichierdico;

 /*Déclarations des variables*/
 int i,findico;
 char reponse;

 /*Déclarations des pointeurs*/
 char **dico;
 char *mot_texte;

 /*Allocation des pointeurs */
 mot_texte=malloc(MAXMOTS*sizeof(char *));
 dico=malloc(MAXMOTS*LONGMOT*sizeof(char *));
 if (mot_texte==NULL)
  {
   fprintf(stderr,"Allocation impossible \n");
   exit(EXIT_FAILURE);
  }

 /*Vérification du nombre d'arguments corrects à l'appel*/
 if (argc!=2)
  {
   printf("Erreur dans le nombre d'arguments\n");
   exit(EXIT_FAILURE);
  }

 /*Ouverture des fichiers en lecture*/
 fichiertexte=fopen(argv[1],"r");
 if (fichiertexte==NULL)
  {
   printf("Impossible d'ouvrir %s.\n", argv[1]);
   exit(EXIT_FAILURE);
  }
 fichierdico=fopen("dico.dat","r");

 /*Lecture du fichier dico et stockage en mémoire dans le tabeau dico*/
 for(findico=0;!feof(fichierdico);findico++) 
  {
   dico[findico]=malloc(LONGMOT*sizeof(char));
    if (dico[findico]==NULL)
    {
     fprintf(stderr,"Allocation impossible \n");
     exit(EXIT_FAILURE);
    }
   else fscanf(fichierdico,"%s",dico[findico]);
   printf("%s\n",dico[findico]);
  }

 /*Fermeture du fichier dico.dat*/
 fclose(fichierdico);

 /*Tri du tableau dico*/
 qsort((char**)dico,MAXMOTS,LONGMOT,compare_mots);

 /*Lecture et traitement du fichier texte*/
 while(!feof(fichiertexte))
 {
  fscanf(fichiertexte,"%s",mot_texte);
  mot_texte=sup_ponc(mot_texte);
  mot_texte=sup_maj(mot_texte);
  if (dichotomie(dico,mot_texte,findico-1)!=1) 
   {
    printf("Le mot '%s' n'est pas dans le dictionnaire, voulez vous le rajouter (o/n) ?\n", mot_texte);
    reponse=getchar();
    purger();
    while((reponse!='o') && (reponse!='n'))
     {
      printf("Réponse invalide, recommencez\n");
      reponse=getchar();
      purger();
     }
    if(reponse=='o') ajout(dico,mot_texte,findico);
   }
 }

 /*Fermeture du fichier texte*/
 fclose(fichiertexte);

 /*Ouverture du fichier dico, écriture des éléments du tableau et fermeture*/
 fichierdico=fopen("dico.dat","w");
 for(i=0;i<=findico;i++) fprintf(fichierdico,"%s",dico[i]);
 fclose(fichierdico);

 /*Libération des pointeurs en mémoire*/
 free(mot_texte);
 for (i=0;i<findico;i++) free(dico[i]);

 return 0;
}

char *sup_ponc(char *mot)
 {
  int lettre, lettresuiv;
  for(lettre=0;mot[lettresuiv];lettre++)
   {
    lettresuiv=lettre+1;
    /* Si le caractère est une ponctuation, on l'ignore*/
    if (ispunct(mot[lettre])!=0) strcpy(&mot[lettre],&mot[lettresuiv]);
   }
  /*Pour terminer la chaîne:*/
  mot[lettre]='\0';
  return mot;
 }

char *sup_maj(char *mot)
 {
  int lettre;
  for (lettre=0;mot[lettre];lettre++)
   {
    if (isupper(mot[lettre])) mot[lettre]=tolower(mot[lettre]);
   }
  return mot;
 }

short dichotomie(char **dico,char *mot,short nbmots)
{
 int i,j,k,x;
 j=nbmots;
 i=0;

  /*Allocation du pointeur **dico*/
 for(x=0;x<=nbmots;x++)
  {
   dico[x]=malloc(LONGMOT*sizeof(char));
   if (dico[x]==NULL)
    {
     fprintf(stderr,"Allocation impossible \n");
     exit(EXIT_FAILURE);
    }
  }

 while ((j-i)>1)
  {
   k=i+((j-i)/2);
   if (((j-i)%2)==0) k++;
   if (strcmp(mot,dico[k-1])==0) return 1;
   if (strcmp(mot,dico[k-1])<0) j=(k-1);
   else i=(k-1);
  }
printf("%s\n",dico[i]);
printf("%s\n",mot);
 if ((strcmp(dico[i],mot)==0) || (strcmp(dico[j],mot)==0)) return 1;
  else return 0;
}

void ajout(char **dico,char *mot_texte,int findico)
 {
  /*Si le le nombre de mots est supérieur à MAXMOTS, on affiche une erreur sinon on ajoute le mot a la fin du tableau*/
  if(findico!=MAXMOTS)
   {
    dico[findico+1]=mot_texte;
    findico++;
   }
  else
   {
    printf("Vous avez dépassé le nombre de mots maximal du dictionnaire");
    exit(EXIT_FAILURE);
   }
   /*On retri le tableau*/
   qsort((char**)dico, MAXMOTS,LONGMOT,compare_mots);
 }

int compare_mots(const void *chaine1, const void *chaine2)
 {
 return strcmp(chaine1,chaine2);
 }

void purger(void)
 {
  int c;
  while ((c=getchar()) != '\n' && c != EOF)
  {}
 }


Merci de votre aide
0
jamsss Messages postés 36 Statut Membre
 
Le remplissage du tableau dico semble bon, le problème viendrai plutôt du qsort, quelqu'un à une idée ?
0