Erreur de segmentation

Résolu/Fermé
jamsss Messages postés 36 Date d'inscription dimanche 6 septembre 2009 Statut Membre Dernière intervention 19 septembre 2011 - 20 sept. 2009 à 22:41
stephane_mc2004 Messages postés 755 Date d'inscription samedi 12 juillet 2008 Statut Membre Dernière intervention 8 février 2011 - 22 sept. 2009 à 22:57
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

14 réponses

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
jamsss Messages postés 36 Date d'inscription dimanche 6 septembre 2009 Statut Membre Dernière intervention 19 septembre 2011
21 sept. 2009 à 00:09
Non non le compilo dit rien à part pour gets qu'il aime pas mais sinon non
0
Oh si, il doit râler... à condition de lui demander de s'exprimer! Il ne faut pas lui mettre un baillon ;-)
Bonne continuation.
0
jamsss Messages postés 36 Date d'inscription dimanche 6 septembre 2009 Statut Membre Dernière intervention 19 septembre 2011
21 sept. 2009 à 08:49
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
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
jamsss Messages postés 36 Date d'inscription dimanche 6 septembre 2009 Statut Membre Dernière intervention 19 septembre 2011
21 sept. 2009 à 14:50
oui je sais bien, je programmais en VB avant, là j'apprends le C, d'ou ma galère avec les pointeurs...
0

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

Posez votre question
jamsss Messages postés 36 Date d'inscription dimanche 6 septembre 2009 Statut Membre Dernière intervention 19 septembre 2011
21 sept. 2009 à 14:50
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
stephane_mc2004 Messages postés 755 Date d'inscription samedi 12 juillet 2008 Statut Membre Dernière intervention 8 février 2011 96
21 sept. 2009 à 15:20
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
stephane_mc2004 Messages postés 755 Date d'inscription samedi 12 juillet 2008 Statut Membre Dernière intervention 8 février 2011 96
21 sept. 2009 à 15:38
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
jamsss Messages postés 36 Date d'inscription dimanche 6 septembre 2009 Statut Membre Dernière intervention 19 septembre 2011
21 sept. 2009 à 22:46
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
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
stephane_mc2004 Messages postés 755 Date d'inscription samedi 12 juillet 2008 Statut Membre Dernière intervention 8 février 2011 96
22 sept. 2009 à 00:57
"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
jamsss Messages postés 36 Date d'inscription dimanche 6 septembre 2009 Statut Membre Dernière intervention 19 septembre 2011
22 sept. 2009 à 07:34
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
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
jamsss Messages postés 36 Date d'inscription dimanche 6 septembre 2009 Statut Membre Dernière intervention 19 septembre 2011
22 sept. 2009 à 12:43
Ah ok donc si je fais fgets(chaine1, 30, stdin) ça devrait marcher si j'ai bien compris ?
0
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
jamsss Messages postés 36 Date d'inscription dimanche 6 septembre 2009 Statut Membre Dernière intervention 19 septembre 2011
22 sept. 2009 à 12:59
oui man c'est ce que je viens de chercher pour trouver le prototype de fgets ;) merci
0
jamsss Messages postés 36 Date d'inscription dimanche 6 septembre 2009 Statut Membre Dernière intervention 19 septembre 2011
22 sept. 2009 à 21:54
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
stephane_mc2004 Messages postés 755 Date d'inscription samedi 12 juillet 2008 Statut Membre Dernière intervention 8 février 2011 96
22 sept. 2009 à 22:57
De rien,. N'oublie pas de mettre le statut de ce Post en résolu ;)
0