Erreur de segmentation

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

j'obtiens une erreur de segmentation quand j'exécute le programme suivant:
L'erreur se situe au niveau de l'entrée d'un nom, pourtant j'ai bien alloué la mémoire à mon pointeur, je ne comprends pas....

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void creation();
void recherche();
char *lecture();
struct enreg
{
char nom[30];
char tel[11];
};
FILE *fd;

main()
{
char choix[100];
fd=fopen("/home/christophe/Test_C/test","a+");
printf("1-Création d'une nouvelle fiche\n");
printf("2-Recherche d'une fiche\n");
printf("3-Fin du programme\n");
scanf("%s",&choix);
while ((choix[0]!='1') && (choix[0]!='2') && (choix[0]!='3'))
{
printf("Réponse invalide, recommencez\n");
scanf("%s",&choix);
}
if (choix[0]=='1') creation();
if (choix[0]=='2') recherche();
if (choix[0]=='3') exit(1);
}

void creation()
{
char reponse[100],*chaine1;
struct enreg *fiche;
fiche=malloc(sizeof(struct enreg));
chaine1=(char *)malloc(31*sizeof(char)); */L'erreur se situe par ici*/
printf("Entrez le nom\n");
gets(chaine1);
strcpy(fiche->nom,lecture(&chaine1));
printf("Entrez le numéro de téléphone\n");
scanf("%s",&(fiche->tel));
printf("Voulez vous sauver cette fiche (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')
{
fseek(fd,0,SEEK_END);
fprintf(fd,"%s\n",(fiche->nom));
fprintf(fd,"%s\n",(fiche->tel));
free(chaine1);
free(fiche);
fclose(fd);
main();
}
else if (reponse[0]=='n') main();
}

void recherche()
{
char chaine[30],nom2[30],tel2[11],reponse[100];
printf("Quel nom recherchez vous ? ");
scanf("%s",&chaine);
fseek(fd,0,SEEK_SET);
while (!feof(fd))
{
fscanf(fd,"%s",&nom2);
if (strcmp(chaine,nom2)==0)
{
fscanf(fd,"%s",&tel2);
printf("Nom: %s\n",nom2);
printf("Téléphone: %s\n",tel2);
printf("Poursuivre la recherche ? (o/n) ");
scanf("%s",&reponse);
while ((reponse[0]!='o') && (reponse[0]!='n'))
{
printf("Réponse invalide, recommencez\n");
scanf("%s",&reponse);
}
if (reponse[0]=='o') break;
if (reponse[0]=='n') main();
}
}
fclose(fd);
printf("Fin du fichier, appuyer sur une touche...\n");
getchar();
}

char *lecture(char chainenom[30])
{
int x;
for (x=1;x<=30;x++)
{
if(isupper(chainenom[x])==1) chainenom[x]=tolower(chainenom[x]);
}
return;
}

Merci beaucoup de votre aide
Configuration: Linux Mandriva
Firefox 3.0.10

14 réponses

  1. loupius
     
    Non, l'erreur doit se trouver là:
    char *lecture(char chainenom[30])
    {
      ...
      return;
    }
    Nota: le compilateur doit râler... et il faut en tenir compte!
    Bonne continuation.
    0
  2. jamsss Messages postés 36 Statut Membre
     
    Non non le compilo dit rien à part pour gets qu'il aime pas mais sinon non
    0
    1. loupius
       
      Oh si, il doit râler... à condition de lui demander de s'exprimer! Il ne faut pas lui mettre un baillon ;-)
      Bonne continuation.
      0
  3. jamsss Messages postés 36 Statut Membre
     
    Et bien en fait j'avais fais ça:
    strcpy(fiche->nom,*lecture(&chaine1));

    ce qui me provoquait un assigment error au niveau du malloc

    puis je l'ai remplacé par:
    strcpy(fiche->nom,lecture(&chaine1));

    et la plus d'erreur mais comme tu dis j'ai surement "masqué" le problème

    Tu dis que l'erreur vient de la fonction lecture ?
    0
    1. loupius
       
      Tu dis que l'erreur vient de la fonction lecture ?
      Je ne sais pas si l'erreur vient de la fonction lecture car je n'ai pas détaillé tout le programme, mais je suis certain, qu'à un moment ou un autre, la fonction lecture entraînera le plantage du programme.
      D'autre part, il ne faut pas oublier qu'une erreur dans l'utilisation des pointeurs ne se révèle pas forcément immédiatement et parfois ça peut même passer inaperçu; d'où la nécessité d'être très rigoureux dans leur utilisation et que, si cette qualité manque, il existe des langages qui ne demandent pas autant de rigorisme.
      -Wall fera parler ton compilateur.
      Bonne continuation.
      0
  4. jamsss Messages postés 36 Statut Membre
     
    oui je sais bien, je programmais en VB avant, là j'apprends le C, d'ou ma galère avec les pointeurs...
    0
  5. Vous n’avez pas trouvé la réponse que vous recherchez ?

    Posez votre question
  6. jamsss Messages postés 36 Statut Membre
     
    oui je sais bien, je programmais en VB avant, là j'apprends le C, d'ou ma galère avec les pointeurs...
    Merci de ton aide, je vais essayer wall, voir ce qu'il me dit, ça fait 2 jours que je cherche je vais pas tarder a m'arracher les cheveux !
    0
  7. stephane_mc2004 Messages postés 807 Statut Membre 96
     
    Bonjour, je simule le compilateur ^^

    ------------------------------------
    #include <stdio.h> 
    #include <stdlib.h> 
    #include <string.h> 
    
    
    void creation(); 
    void recherche(); 
    char *lecture(); 
    struct enreg 
    { 
    char nom[30]; 
    char tel[11]; 
    }; 
    FILE *fd; 
    
    main() 
    { 
    char choix[100]; 
    fd=fopen("/home/christophe/Test_C/test","a+"); 
    printf("1-Création d'une nouvelle fiche\n"); 
    printf("2-Recherche d'une fiche\n"); 
    printf("3-Fin du programme\n"); 
    scanf("%s",&choix); 
    while ((choix[0]!='1') && (choix[0]!='2') && (choix[0]!='3')) 
    { 
    printf("Réponse invalide, recommencez\n"); 
    scanf("%s",&choix);  // Les chaines de caractères sont des pointeurs sur des caractères. enlever le &
    } 
    if (choix[0]=='1') creation(); 
    if (choix[0]=='2') recherche(); 
    if (choix[0]=='3') exit(1); // Warning : exit 0, le 1 signifie que le programme ne s'est pas terminé correcteme,nt.. mais bon ^^
    } 
    
    void creation() 
    { 
    char reponse[100],*chaine1; 
    struct enreg *fiche; 
    fiche=malloc(sizeof(struct enreg)); 
    chaine1=(char *)malloc(31*sizeof(char)); */L'erreur se situe par ici*/  // Vraiment ??
    
    printf("Entrez le nom\n"); 
    gets(chaine1); 
    strcpy(fiche->nom,lecture(&chaine1)); 
    printf("Entrez le numéro de téléphone\n"); 
    scanf("%s",&(fiche->tel)); 
    printf("Voulez vous sauver cette fiche (o/n) ?\n"); 
    scanf("%s",&reponse); // reponse est un pointeur sur des caractères (donc une adresse). Enlever les &
    while ((reponse[0]!='o') && (reponse[0]!='n')) 
    { 
    printf("Réponse invalide, recommencez\n"); 
    scanf("%s",&reponse); // ??
    } 
    if (reponse[0]=='o') 
    { 
    fseek(fd,0,SEEK_END); 
    fprintf(fd,"%s\n",(fiche->nom)); 
    fprintf(fd,"%s\n",(fiche->tel)); 
    free(chaine1); 
    free(fiche); 
    fclose(fd); 
    main(); 
    } 
    else if (reponse[0]=='n') main(); 
    } 
    
    void recherche() 
    { 
    char chaine[30],nom2[30],tel2[11],reponse[100]; 
    printf("Quel nom recherchez vous ? "); 
    scanf("%s",&chaine); 
    fseek(fd,0,SEEK_SET); 
    while (!feof(fd)) 
    { 
    fscanf(fd,"%s",&nom2); 
    if (strcmp(chaine,nom2)==0) 
    { 
    fscanf(fd,"%s",&tel2); 
    printf("Nom: %s\n",nom2); 
    printf("Téléphone: %s\n",tel2); 
    printf("Poursuivre la recherche ? (o/n) "); 
    scanf("%s",&reponse); 
    while ((reponse[0]!='o') && (reponse[0]!='n')) 
    { 
    printf("Réponse invalide, recommencez\n"); 
    scanf("%s",&reponse); 
    } 
    if (reponse[0]=='o') break; 
    if (reponse[0]=='n') main(); 
    } 
    } 
    fclose(fd); 
    printf("Fin du fichier, appuyer sur une touche...\n"); 
    getchar(); 
    } 
    
    // SI J'AI BIEN COMPRIS, cette fonction ne fait QUE transformer des maj. en miniscules. elle ne renvoie rien. D'ou l'erreur
    char *lecture(char chainenom[30]) // Le compilateur ignore la taille 30
    { 
    int x; 
    for (x=1;x<=30;x++) 
    { 
    if(isupper(chainenom[x])==1) chainenom[x]=tolower(chainenom[x]); 
    } 
    return; 
    } 
    0
  8. stephane_mc2004 Messages postés 807 Statut Membre 96
     
    Tentative de correction..

    ------------------------------------
    #include <stdio.h> 
    #include <stdlib.h> 
    #include <string.h> 
    
    
    void creation(); 
    void recherche(); 
    char *lecture(); 
    struct enreg 
    { 
    char nom[30]; 
    char tel[11]; 
    }; 
    FILE *fd; 
    
    main() 
    { 
    char choix ; 
    fd=fopen("/home/christophe/Test_C/test","a+"); 
    
    
    printf("1-Création d'une nouvelle fiche\n"); 
    printf("2-Recherche d'une fiche\n"); 
    printf("3-Fin du programme\n"); 
    
    
    scanf("%s",&choix); 
    while ((choix !='1') && (choix !='2') && (choix !='3')) 
    { 
         printf("Réponse invalide, recommencez\n"); 
         scanf("%s",&choix);  // Ici on peut mettre & car choix n'est pas un pointeur, mais un caractère. (c'etait possible dans ton 1er cas de mettre &choix avec choix un pointeur, mais ce n'est pas ce que tu voulais faire)
    } 
    if (choix =='1') creation(); 
    if (choix =='2') recherche(); 
    if (choix =='3') exit(0);
    } // Fin du main 
    
    void creation() 
    { 
       char reponse,*chaine1; // Gaspillage de la mémoire avec un tableau  de 100 pour une seule lettre comme reponse   struct enreg *fiche; 
       fiche=malloc(sizeof(struct enreg)); 
       chaine1=(char *)malloc(31*sizeof(char)); 
    
       printf("Entrez le nom\n"); 
       gets(chaine1); 
       strcpy(fiche->nom,chaine1); //lecture, je trouve pas son utilité
       printf("\nEntrez le numéro de téléphone\n"); 
       scanf("%s",(fiche->tel)); // pas de & car tel est un pointeur sur des caractères (ch. de caract. si tu prefere)
       printf("Voulez vous sauver cette fiche (o/n) ?\n"); 
       scanf("%c",&reponse); 
    while ((reponse !='o') && (reponse !='n')) 
    { 
    printf("Réponse invalide, recommencez\n"); 
    scanf("%c",&reponse);
    }
    
     
    if (reponse =='o') 
    { 
    fseek(fd,0,SEEK_END); 
    fprintf(fd,"%s\n",(fiche->nom)); 
    fprintf(fd,"%s\n",(fiche->tel)); 
    free(chaine1); 
    free(fiche); 
    fclose(fd); 
    main(); 
    } 
    else if (reponse[0]=='n') main(); 
    } 
    
    void recherche() 
    { 
    char chaine[30],nom2[30],tel2[11],reponse[100]; 
    printf("Quel nom recherchez vous ? "); 
    scanf("%s",chaine); 
    fseek(fd,0,SEEK_SET); 
    while (!feof(fd)) 
    { 
    fscanf(fd,"%s",nom2); 
    if (strcmp(chaine,nom2)==0) 
    { 
    fscanf(fd,"%s",tel2); 
    printf("Nom: %s\n",nom2); 
    printf("Téléphone: %s\n",tel2); 
    printf("Poursuivre la recherche ? (o/n) "); 
    scanf("%s",reponse); 
    while ((reponse[0]!='o') && (reponse[0]!='n')) 
    { 
    printf("Réponse invalide, recommencez\n"); 
    scanf("%s",reponse); 
    } 
    if (reponse[0]=='o') break; 
    if (reponse[0]=='n') main(); 
    } 
    } 
    fclose(fd); 
    printf("Fin du fichier, appuyer sur une touche...\n"); 
    getchar(); 
    } 
    
    // Lec-ture sert a rien a mon avis
    char *lecture(char chainenom[30]) // Le compilateur ignore la taille 30
    { 
    int x; 
    for (x=1;x<=30;x++) 
    { 
    if(isupper(chainenom[x])==1) chainenom[x]=tolower(chainenom[x]); 
    } 
    return; 
    } 


    Ce code je l'ai pas testé, mais si t'as suivi le principe, tu devrais corriger ce que je n'ai pu voir

    Principe :

    Quand on utilise scanf, on met & pour pouvoir reperer la variable en question, et modifier sa valeur.
    ex :
    int n = 10;
    scanf("%d", &n);

    Si la variable en question est elle meme un pointeur (ou une adresse), c'est maintenant inutile d'ecrire &. Exemple :
    char mesLettres[4] ; // J'ai quatre lettres
    soit je fais :
    scanf("%c", &mesNotes[i]); // avec i allant de 0 à 4-1 ==> 3, j'y met des caractères, d'ou le %c

    ou alors je fais
    scanf("%s", mesNotes); // mesNotes represente un tableau de caractère, ou un pointeur sur des caractères, donc des adresses. D'ou l'inutilité du &

    J'espere que tu comprendras meiux les pointeurs et pourras améliorer ton code.
    0
    1. jamsss Messages postés 36 Statut Membre
       
      re

      Merci pour tes réponses, je connais le principe concernant les & et la différence entre char et string mais si j'ai fais ça pour les choix "reponse" c'est parce que ça ne fonctionnait pas, voila le code que j'ai fait au départ, avec un scanf a la place de gets et sans la fonction lecture() (qui sert effectivement a convertir les majuscules en minuscules, par contre j'avais oublié de retourner la valeur):

      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      void creation();
      void recherche();
      struct enreg
      {
      char nom[30];
      char tel[11];
      };
      FILE *fd;

      main()
      {
      char choix[100];
      fd=fopen("/home/christophe/Test_C/test","a+");
      printf("1-Création d'une nouvelle fiche\n");
      printf("2-Recherche d'une fiche\n");
      printf("3-Fin du programme\n");
      scanf("%s",&choix);
      while ((choix[0]!='1') && (choix[0]!='2') && (choix[0]!='3'))
      {
      printf("Réponse invalide, recommencez\n");
      scanf("%s",&choix);
      }
      if (choix[0]=='1') creation();
      if (choix[0]=='2') recherche();
      if (choix[0]=='3') exit(1);
      }

      void creation()
      {
      char reponse[100];
      struct enreg *fiche;
      fiche=malloc(sizeof(struct enreg));
      printf("Entrez le nom\n");
      scanf("%s",&(fiche->nom));
      printf("Entrez le numéro de téléphone\n");
      scanf("%s",&(fiche->tel));
      printf("Voulez vous sauver cette fiche (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')
      {
      fseek(fd,0,SEEK_END);
      fprintf(fd,"%s\n",(fiche->nom));
      fprintf(fd,"%s\n",(fiche->tel));
      free(fiche);
      fclose(fd);
      main();
      }
      else if (reponse[0]=='n') main();
      }

      void recherche()
      {
      char chaine[30],nom2[30],tel2[11],reponse[100];
      printf("Quel nom recherchez vous ? ");
      scanf("%s",&chaine);
      fseek(fd,0,SEEK_SET);
      while (!feof(fd))
      {
      fscanf(fd,"%s",&nom2);
      if (strcmp(chaine,nom2)==0)
      {
      fscanf(fd,"%s",&tel2);
      printf("Nom: %s\n",nom2);
      printf("Téléphone: %s\n",tel2);
      printf("Poursuivre la recherche ? (o/n) ");
      scanf("%s",&reponse);
      while ((reponse[0]!='o') && (reponse[0]!='n'))
      {
      printf("Réponse invalide, recommencez\n");
      scanf("%s",&reponse);
      }
      if (reponse[0]=='o') break;
      if (reponse[0]=='n') main();
      }
      }
      fclose(fd);
      printf("Fin du fichier, appuyer sur une touche...\n");
      getchar();
      }

      Ce code fonctionne parfaitement avec des tableaux de caractères pour les choix, je t'assure que si je met des char cela m'affiche des résultats du style:
      Voulez vous sauver cette fiche (o/n) ?
      Réponse invalide, recommencez
      sans donner l'occasion à l'utilisateur de répondre... j'avais donc trouvé cette solution de tableau de char

      Par contre maintenant que j'ai mis le return chainenom dans lecture(), plus d'erreur de segmentation mais le problème vient de la fonction gets qui ne demande rien: passage directement a la demande "numéro de téléphone"...

      Je te remercie encore pour ton aide
      0
  9. loupius
     
    Comme le signale ton compilateur, on ne devrait (voire doit) pas utiliser 'gets' qui est sensible à la faille de sécurité. Oublie donc 'gets' et utilise à la place 'fgets'. Je note d'ailleurs qu'il n'en existe plus dans ton code.
    Bonne soirée.
    0
  10. stephane_mc2004 Messages postés 807 Statut Membre 96
     
    "sans donner l'occasion à l'utilisateur de répondre... "
    C'est Parce que le buffer (tampon) d'entrée n'est pas vide que ca arrive.
    Quel est ton nouveau code qui bug ? Celui là ?

    PS: Comme l'a dis loupious, utilise fgets à la place de gets
    0
  11. jamsss Messages postés 36 Statut Membre
     
    Non celui la marche très bien justement, c'est celui avec gets qui me pose problème. Mais comment utiliser fgets puisque je ne lis pas dans un fichier ?
    0
    1. loupius
       
      Mais 'fgets' ne lit pas dans un fichier ... quelques secondes d'étonnement ... puis de réflexion ... reprenons, ne lit donc pas dans un fichier mais dans un 'flux'. Et tu n'est pas sans savoir que, sous Linux, il existe trois flux particuliers qui sont toujours ouverts, à moins évidemment de les avoir fermés ;-), et qui s'appellent: stdin, stdout et stderr. Je te laisse choisir le flux qui répond à ta demande.
      Bonne réflexion.
      0
  12. jamsss Messages postés 36 Statut Membre
     
    Ah ok donc si je fais fgets(chaine1, 30, stdin) ça devrait marcher si j'ai bien compris ?
    0
    1. loupius
       
      Je pense que tu as compris.
      N'oublie pas que tu as une aide qui s'appelle 'man'; il faut l'utiliser, cet 'homme' est là pour ça. Alors un petit 'man fgets' ou 'man stdin' t'en apprendra beaucoup.
      Bonne continuation.
      0
  13. jamsss Messages postés 36 Statut Membre
     
    oui man c'est ce que je viens de chercher pour trouver le prototype de fgets ;) merci
    0
  14. jamsss Messages postés 36 Statut Membre
     
    Bon voila ça fonctionne enfin ! Le problème venait de restes dans le flux, j'ai donc rajouté une fonction purger() pour nettoyer les "\n" qui restait de mes scanf et clean() pour nettoyer mes gets, je met le code qui marche:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    void creation();
    void recherche();
    char *lecture();
    void purger();
    void clean();
    struct enreg
    {
    char nom[30];
    char tel[11];
    };
    FILE *fd;

    int main()
    {
    char choix[1];
    fd=fopen("/home/christophe/Test_C/test","a+");
    printf("1-Création d'une nouvelle fiche\n");
    printf("2-Recherche d'une fiche\n");
    printf("3-Fin du programme\n");
    scanf("%s",choix);
    purger();
    while ((choix[0]!='1') && (choix[0]!='2') && (choix[0]!='3'))
    {
    printf("Réponse invalide, recommencez\n");
    scanf("%s",choix);
    purger();
    }
    if (choix[0]=='1') creation();
    if (choix[0]=='2') recherche();
    if (choix[0]=='3') exit(1);
    return 0;
    }

    void creation()
    {
    char reponse[100],*chaine1;
    struct enreg *fiche;
    fiche=malloc(sizeof(struct enreg));
    chaine1=malloc(30*sizeof(char *));
    printf("Entrez le nom\n");
    while(strcmp(chaine1,"")==0)
    {
    fgets(chaine1,30,stdin);
    }
    clean(chaine1);
    chaine1=lecture(chaine1);
    strcpy(fiche->nom,chaine1);
    printf("Entrez le numéro de téléphone\n");
    scanf("%s",(fiche->tel));
    printf("Voulez vous sauver cette fiche (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')
    {
    fseek(fd,0,SEEK_END);
    fprintf(fd,"%s\n",(fiche->nom));
    fprintf(fd,"%s\n",(fiche->tel));
    free(fiche);
    fclose(fd);
    main();
    }
    else if (reponse[0]=='n') main();
    }

    void recherche()
    {
    char *chaine,nom2[30],tel2[11],reponse[100];
    printf("Quel nom recherchez vous ? ");
    chaine=malloc(30*sizeof(char *));
    fgets(chaine,30,stdin);
    clean(chaine);
    chaine=lecture(chaine);
    fseek(fd,0,SEEK_SET);
    while (!feof(fd))
    {
    fscanf(fd,"%s",nom2);
    if (strcmp(chaine,nom2)==0)
    {
    fscanf(fd,"%s",tel2);
    printf("Nom: %s\n",nom2);
    printf("Téléphone: %s\n",tel2);
    printf("Poursuivre la recherche ? (o/n) ");
    scanf("%s",reponse);
    while ((reponse[0]!='o') && (reponse[0]!='n'))
    {
    printf("Réponse invalide, recommencez\n");
    scanf("%s",reponse);
    }
    if (reponse[0]=='o') break;
    if (reponse[0]=='n') main();
    }
    }
    fclose(fd);
    printf("Fin du fichier, appuyer sur une touche...\n");
    }

    char *lecture(char chainenom[30])
    {
    int x;
    for (x=0;x<=29;x++)
    {
    if(isupper(chainenom[x])) chainenom[x]=tolower(chainenom[x]);
    }
    return chainenom;
    }

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

    void clean(char *chaine)
    {
    char *p=strchr(chaine,'\n');
    if (p) *p = 0;
    else purger();
    }

    Merci à tous pour votre aide précieuse ;)
    0
  15. stephane_mc2004 Messages postés 807 Statut Membre 96
     
    De rien,. N'oublie pas de mettre le statut de ce Post en résolu ;)
    0