Précédent   Forum du club des développeurs et IT Pro > C et C++ > C
C Forum d'entraide technique sur le langage C. Avant de poster -> F.A.Q. C, Avant de poster.
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse
 
Outils de la discussion
Publicité
'
Vieux 20/11/2012, 13h41   #1
Chaosus
Invité de passage
 
Inscription : novembre 2012
Messages : 7
Détails du profil
Informations forums :
Inscription : novembre 2012
Messages : 7
Points : 0
Points : 0
Par défaut Erreur de segmentation à la lecture d'un fichier et l'insertion dans une liste chainée

Bonjour, j'ai créé un programme qui a pour objectif de : lire dans un fichier ligne par ligne, puis extraire les mots de chacun de ces lignes, et enfin placer ces mots dans une liste. Tout marche, jusqu'à la rentrée dans une liste, où j'obtiens une segmentation fault, mais je vois pas d'où ça vient. Voilà le main.c et la définition de ma liste :

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
 
 
typedef struct elem {
char* word;
struct elem* next;
} Element;
 
typedef Element* List;
 
int main(int argc,char* argv[])
{
	List l=NULL;
	char str[200];
	FILE *fp = fopen("./test.txt","r");
	char* wrd; /*a array of caracters representing ONE word*/
 
   	if(!fp) return 1; /* bail out if file not found*/
 
    /*
    fgets function :
 
    La fonction fgets() prends comme premier paramètre la chaîne dans laquelle elle va placer la saisie. Le deuxième paramètre est le nombre maximal 
    de caractères (n-1 plus exactement) qui seront lus et le dernier paramètre est le flux à lire. Ici se sera stdin. (le flux est un fichier)
    */
 
	while(fgets(str,sizeof(str),fp) != NULL)
	{
		/* strip trailing '\n' if it exists*/
		int len = strlen(str)-1;
		if(str[len] == '\n')
		{ 
	    	str[len] = 0;
	    	}
 
		/*
		char * strtok ( char * str, const char * delimiters );
		str :
		C string to truncate.
		Notice that the contents of this string are modified and broken into smaller strings (tokens).
		Alternativelly, a null pointer may be specified, in which case the function continues scanning where a previous successful call to the function ended.
		delimiters :
		C string containing the delimiter characters.
		These may vary from one call to another.
		*/
 
  		printf ("Splitting string \"%s\" into words:\n",str);
		wrd = strtok (str," ");
		l = insertTail(l,wrd);
		while (wrd != NULL)
		{
			printf ("word extracted : %s\n",wrd);
			wrd = strtok(NULL," "); /* the second time we call the function, we have to put NULL into the second parameter*/
			if(wrd != NULL)
			{
				l = insertTail(l,wrd);
			}
		}
 
	}
	printf("\n");
	fclose(fp);
 
 
 
	printList(l);
 
	return EXIT_SUCCESS;
}
voici maintenant les fonctions printlist et inserttail :

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
 
List insertTail(List l, char* p)
{
	List newel; 
	List pl;
 
	newel = (Element *) malloc(sizeof(Element));
	newel->word = p;
	newel->next = NULL;
 
	if(l == NULL)
	{
		l = newel;
	} else {
		pl = l;
		while(pl->next != NULL){
			pl=pl->next;
		}
		pl->next=newel;
	}
 
	return l;
}
 
void printList(List l)
{
	if(l==NULL)
	{
		printf("Empty List\n");
	}
	else
	{
		Element* w = w;
		while(w->next != NULL)
		{
			printf("%s",w->word);
			w=w->next;
		}
		printf("%s\n",w->word);
	}
}
Si vous pouviez m'aider ou m'indiquer comment trouver, ça m'aiderait beaucoup... Merci
Chaosus est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/11/2012, 13h56   #2
kwariz
Expert Confirmé
 
Homme Fred Kwariz
Chef de projet en SSII
Inscription : octobre 2011
Messages : 745
Détails du profil
Informations personnelles :
Nom : Homme Fred Kwariz
Âge : 40
Localisation : France, Moselle (Lorraine)

Informations professionnelles :
Activité : Chef de projet en SSII
Secteur : Conseil

Informations forums :
Inscription : octobre 2011
Messages : 745
Points : 2 941
Points : 2 941
Bonjour,

Je n'ai que regardé ton code en diagonal, mais je suppose que le problème vient d'une mauvaise utilisation de strtok (cf la man page). Le pointeur que tu insères dans ta liste sera modifié par les appels ultérieurs à fgets et strtok.
Le plus simple pour le constater et confirmer mon intuition est d'utiliser ton débugueur favori ( printf manuels, gdb, ddd, celui de ton ide ...).
kwariz est actuellement connecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/11/2012, 14h50   #3
diogene
Responsable Modération
 
Avatar de diogene
 
Homme Patrick Gonord
Enseignant Chercheur
Inscription : juin 2005
Messages : 5 435
Détails du profil
Informations personnelles :
Nom : Homme Patrick Gonord
Localisation : France, Essonne (Île de France)

Informations professionnelles :
Activité : Enseignant Chercheur
Secteur : Enseignement

Informations forums :
Inscription : juin 2005
Messages : 5 435
Points : 12 967
Points : 12 967
w mal initialisé
Code :
1
2
3
4
void printList(List l)
{
...
		Element* w = w;
Par ailleurs, tu stockes les pointeurs sur des éléments de la chaine str. Mais cette chaine change à chaque tour de boucle. Tous les éléments de la liste vont pointer sur des éléments du dernier str lu. Les éléments de la liste doivent stocker les chaines elles-mêmes, pas des pointeurs.
__________________
Publication : Concepts en C

Mon avatar : Glenn Gould

--------------------------------------------------------------------------
Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !
diogene est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 20/11/2012, 21h35   #4
Chaosus
Invité de passage
 
Inscription : novembre 2012
Messages : 7
Détails du profil
Informations forums :
Inscription : novembre 2012
Messages : 7
Points : 0
Points : 0
Merci beaucoup diogene, c'est ça qui pêchait effectivement. Maintenant, j'ai un autre problème, mes codes ont changé en :

le main.c

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
 
main.c
 
int main(int argc,char* argv[])
{
	List l=NULL;
	char str[200];
	FILE *fp = fopen("./test.txt","r");
	char* wrd; /*a array of caracters representing ONE word*/
 
   	if(!fp) return 1; /* bail out if file not found*/
 
    /*
    fgets function :
    La fonction fgets() prends comme premier paramètre la chaîne dans laquelle elle va placer la saisie. Le deuxième paramètre est le nombre maximal 
    de caractères (n-1 plus exactement) qui seront lus et le dernier paramètre est le flux à lire. Ici se sera stdin. (le flux est un fichier)
    */
	while(fgets(str,sizeof(str),fp) != NULL)
	{
		/* strip trailing '\n' if it exists*/
		int len = strlen(str)-1;
		if(str[len] == '\n')
		{ 
	    	str[len] = 0;
	    }
 
		/*
		char * strtok ( char * str, const char * delimiters );
		str :
		C string to truncate.
		Notice that the contents of this string are modified and broken into smaller strings (tokens).
		Alternativelly, a null pointer may be specified, in which case the function continues scanning where a previous successful call to the function ended.
		delimiters :
		C string containing the delimiter characters.
		These may vary from one call to another.
		*/
 
  		printf ("Splitting string \"%s\" into words:\n",str);
 
		wrd = strtok(str," ");
		if(wrd != NULL)
		{
			l = insertTail(l,wrd);
			printf("Extracted word : %s\n",wrd);
		}
		while(wrd != NULL)
		{
			wrd = strtok(NULL," ");
			if(wrd != NULL)
			{
				l = insertTail(l,wrd);
				printf("Ectracted word : %s\n",wrd);
 
			}
 
 
 
		}
 
	}
	printf("\n");
	fclose(fp);
 
 
	printf("Number of words in the list : %d\n",nbwords(l));
	printList(l); /*le problème du programme ne vient pas de la printList, mais de l'insertion des mots, 
	(de plus, la fonction insertTail fait bien son job) puisqu'il y a bien 8 mots (mais les mauvais)*/
 
	return EXIT_SUCCESS;
}
printlist et insertTail :

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
 
List insertTail(List l, char* p)
{
	List newel; 
	List pl;
 
	newel = (Element *) malloc(sizeof(Element));
	newel->word = p;
	newel->next = NULL;
 
	if(l == NULL)
	{
		l = newel;
	} else {
		pl = l;
		while(pl->next != NULL){
			pl=pl->next;
		}
		pl->next=newel;
	}
 
	return l;
}
 
 
void printList(List l) /*bug in this function : every words are always the first of the last line, and the last word is the last of the last line*/
{
 
	printf("Visionnage de la chaine extraite :\n");
	if(l==NULL)
	{
		printf("Empty List\n");
	}
	else
	{
		Element* w = l;
 
		while(w->next != NULL)
		{
			printf("%s ",w->word);
			w=w->next;
		}
 
		printf("%s\n",w->word);
	}
}
"Et l'output est la suivante :
Splitting string "pourquoi" into words:
Extracted word : pourquoi
Splitting string "il" into words:
Extracted word : il
Splitting string "veut" into words:
Extracted word : veut
Splitting string "pas" into words:
Extracted word : pas
Splitting string "commencer" into words:
Extracted word : commencer
Splitting string "par" into words:
Extracted word : par
Splitting string "le début" into words:
Extracted word : le
Ectracted word : début

Number of words in the list : 8
Visionnage de la chaine extraite :
le le le le le le le début"
Chaosus est déconnecté   Envoyer un message privé Réponse avec citation 01
Vieux 20/11/2012, 22h41   #5
diogene
Responsable Modération
 
Avatar de diogene
 
Homme Patrick Gonord
Enseignant Chercheur
Inscription : juin 2005
Messages : 5 435
Détails du profil
Informations personnelles :
Nom : Homme Patrick Gonord
Localisation : France, Essonne (Île de France)

Informations professionnelles :
Activité : Enseignant Chercheur
Secteur : Enseignement

Informations forums :
Inscription : juin 2005
Messages : 5 435
Points : 12 967
Points : 12 967
J'ai répondu, par anticipation, à cette question dans mon message précédent
Citation:
.... Tous les éléments de la liste vont pointer sur des éléments du dernier str lu. ...
__________________
Publication : Concepts en C

Mon avatar : Glenn Gould

--------------------------------------------------------------------------
Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !
diogene est déconnecté   Envoyer un message privé Réponse avec citation 20
Vieux 21/11/2012, 08h47   #6
Chaosus
Invité de passage
 
Inscription : novembre 2012
Messages : 7
Détails du profil
Informations forums :
Inscription : novembre 2012
Messages : 7
Points : 0
Points : 0
Le problème est que je n'arrive pas à visualiser le problème ni à trouver une solution../
Chaosus est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 21/11/2012, 10h43   #7
diogene
Responsable Modération
 
Avatar de diogene
 
Homme Patrick Gonord
Enseignant Chercheur
Inscription : juin 2005
Messages : 5 435
Détails du profil
Informations personnelles :
Nom : Homme Patrick Gonord
Localisation : France, Essonne (Île de France)

Informations professionnelles :
Activité : Enseignant Chercheur
Secteur : Enseignement

Informations forums :
Inscription : juin 2005
Messages : 5 435
Points : 12 967
Points : 12 967
Il faut stocker dans le maillon la chaine elle même et non pas un pointeur sur une chaine dont le contenu varie (str) au cours de l'exécution. Du genre :

Code :
1
2
3
4
5
6
newel =  malloc(sizeof(Element));
if(newel != NULL)
{
   newel->word = malloc(strlen(p)+1);
   if(newel->word != NULL) strcpy(newel->word,p);
   ....
__________________
Publication : Concepts en C

Mon avatar : Glenn Gould

--------------------------------------------------------------------------
Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !
diogene est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 21/11/2012, 12h40   #8
Chaosus
Invité de passage
 
Inscription : novembre 2012
Messages : 7
Détails du profil
Informations forums :
Inscription : novembre 2012
Messages : 7
Points : 0
Points : 0
Ca fonctionne, merci beaucoup . J'ai compris le problème, et je pense que j'aurais pu résoudre le problème en utilisant fscanf au lieu de fgets.
Chaosus est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse
Outils de la discussion

Navigation rapide


Fuseau horaire GMT +2. Il est actuellement 00h45.


 
 
 
 
Partenaires

Hébergement Web