IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

Double liste chainées : problème d'insertion


Sujet :

C

  1. #1
    Candidat au Club
    Profil pro
    Inscrit en
    Novembre 2012
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2012
    Messages : 7
    Points : 3
    Points
    3
    Par défaut Double liste chainées : problème d'insertion
    Bonjour, je cherche en vain depuis une 10aine d'heures le problème dans les fonctions qui suivent. Avant, voici les quelques explications :

    J'ai une fonction main, qui appelle en boucle à chaque ligne une fonction buildEntryFieldList (qui parse la ligne en deux chaines de caractères : nom et valeur), qui elle même appelle insertTailListEntrFi, qui insère ce qui a été obtenu dans une liste.

    Le problème : Au final, quand j'utilise ma fonction printList, je me retrouve avec X fois (X étant le nombrede lignes qui ont été lues) la valeur et le nom de la DERNIERE ligne seulement. Voici un screen :

    http://img4.hostingpics.net/pics/971...2012155429.png

    Les deux lignes commençant par des '#' et les deux lignes qui suivent sont des lignes écrites au niveau de l'insertion dans la liste, et déjà à ce niveau on se rend compte que la valeur qui vient d'être insérée a été aussi insérée à la place de la valeur PRECEDENTE (et de toutes les autres valeurs en fait)

    Le résultat de la liste est affichée après, avec le "author" qui est comme on le voit remplacé par des symboles, et toutes les autres lignes similaires.

    Voici mon code :
    main
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    int main(int argc,char* argv[]) 
    {
     
    	FILE* fp;
    	char actualCaracter;
    	char* line = (char*) malloc(2000*sizeof(char));
    	Entry tempEntry;
    	tempEntry.listEntryFields=NULL;
     
    	initializeEntry(&tempEntry);
     
    	fp = fopen("test.txt","r");
    	if(fp==NULL)
    	{
    		printf("FAILED TO OPEN THE FILE\n");
    	}
    	else
    	{
    		actualCaracter = fgetc(fp);
    		while(actualCaracter != EOF)
    		{
    			if(actualCaracter == '@')
    			{
    				tempEntry.listEntryFields=NULL; /*to make the listEntryField reboot*/
    				printf("> Entry was found\n");
                    fscanf(fp,"%s",line);
                    strcpy(tempEntry.type,strtok(line,"{"));
                    strcpy(tempEntry.key,strtok(NULL,","));
                    printf("Type = %s\nKey = %s\n",tempEntry.type,tempEntry.key);
                    actualCaracter=fgetc(fp); /*to go after the comma and go to the CR*/
                    fscanf(fp,"%s",line);
                    printf("%s\n",line);
                    getchar();
                    do
    				{
    					printf("Entryfield was found\n");
    					tempEntry.listEntryFields = buildEntryFieldList(tempEntry.listEntryFields,line,fp);
    					fseek(fp,-1,SEEK_CUR); /*we go back to the previous caracter, because we are too far and we have to read the line)*/
    					fscanf(fp,"%s",line);
    					printf("%s\n",line);
     
    				}while(strcmp(line,"}")!=0); /*a line that has only "}" can only be the last line of the entry*/
    				printEntryFieldList(tempEntry.listEntryFields);
    			}
    			actualCaracter = fgetc(fp);
    		}
    		fclose(fp);
     
    	}
     
    	freeEntry(&tempEntry);
     
     
    	return 0;
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    ListEntryFields buildEntryFieldList(ListEntryFields listEntryFields,char* line,FILE* fp)
    {
    	int i=0; /*an iteration variable*/
     
    	EntryField tempEntryField;
    	char actualCaracter;
    	int verif = 0;
     
        char* buffer = (char *) malloc(2000*sizeof(char));
        tempEntryField.fieldname = (char *) malloc(2000*sizeof(char));
        tempEntryField.value = (char *) malloc(2000*sizeof(char));
     
        strcpy(tempEntryField.fieldname,strtok(line,"="));
     
        do
    	{
    		actualCaracter=fgetc(fp);
        }while(actualCaracter!='{');
     
        do
        {
    		actualCaracter=fgetc(fp);
    		buffer[i]=actualCaracter; /*We copy the contents of the entryfield caracter by caracter*/
    		if(actualCaracter=='\n')
    		{
    			actualCaracter=fgetc(fp);
    			if(actualCaracter=='\t' || actualCaracter=='}') /*we check that there is a '\t' after the '\n', meaning that it's the end of the entryfild, of simply the end of the entry*/
    			{
    				verif=1;
    			}
    		}
    		i++;
    	}while(verif != 1); /*until the caracter is the CR*/
     
    	buffer[i-4]='\0'; /* to delete the "}," at the end of the line*/
    	strcpy(tempEntryField.value,buffer);
     
    	getchar();
     
        listEntryFields = insertTailListEntrFi(&tempEntryField,listEntryFields);
     
    	free(tempEntryField.fieldname);
        free(tempEntryField.value);
    	free(buffer);
     
    	return listEntryFields;
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    ListEntryFields insertTailListEntrFi(EntryField *tempEntryField,ListEntryFields listEntryFields)
    {
    	EntryFieldElem* newel = (EntryFieldElem *) malloc(sizeof(EntryFieldElem));
    	EntryFieldElem* p;
    	newel->entryField = *tempEntryField;
    	newel->next = NULL;
    	newel->prev = NULL;
    	if(listEntryFields==NULL)
    	{
    		listEntryFields=newel;
    	}
    	else
    	{	
    		p=listEntryFields;
    		while(p->next != NULL)
    		{
    			p=p->next;
    		}
    		p->next = newel;
    		newel->prev = p;
    		printf("PREVIOUS\n#Fieldname : %s\n#Value : %s\n",newel->prev->entryField.fieldname,newel->prev->entryField.value);
     
    	}
    	printf("Fieldname : %s\nValue : %s\n",newel->entryField.fieldname,newel->entryField.value);
    	return listEntryFields;
    }


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    void printEntryFieldList(ListEntryFields listEntryFields)
    {
    	ListEntryFields p;	
     
    	if(listEntryFields == NULL)
    	{
    		printf("Liste vide !!\n");
    	}
    	else
    	{
    		p=listEntryFields;
     
    		while(p!=NULL)
    		{
    			printf("Fieldname : %s\n Value : %s\n",p->entryField.fieldname,p->entryField.value);
    			p=p->next;
    		}
    	}
    }
    Ainsi que mes structures :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    	typedef struct {
    		char* fieldname;
    		char* value;
    	}EntryField;
     
    	typedef struct entrfi{
    		EntryField entryField;
    		struct entrfi* next;
    		struct entrfi* prev;
    	}EntryFieldElem;
     
    	/*the list of entryfields*/
    	typedef EntryFieldElem*  ListEntryFields;
     
    	typedef struct {
    		char* type;
    		char* key;
    		ListEntryFields listEntryFields;
    	}Entry;

    Si vous pouviez m'aider, je vous serait graaandement reconnaissants...

  2. #2
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    Ce symptome est souvent le fait de la recopie d'un pointeur, au lieu de la recopie de la donnée, mais cela ne semble pas être le cas ici.

    Le code est assez touffu mais il me semble y voir la faille suivante.
    Dans main(), on a une boucle qui appelle buildEntryFieldList() qui elle a la trame, en expurgeant le code pour mettre en évidence et en commentant ce qui se passe :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    ListEntryFields buildEntryFieldList(ListEntryFields listEntryFields,char* line,FILE* fp)
    {
    ...
        EntryField tempEntryField;
    ...
    // Construction d'un EntryField en créant par allocation dynamique 
    // 2 tableaux (2000 char, pourquoi une telle taille arbitraire ?) dont l'adresse
    // est mise dans les champs fieldname et value et en les initialisant par recopie des chaines.
        tempEntryField.fieldname = (char *) malloc(2000*sizeof(char));
        tempEntryField.value = (char *) malloc(2000*sizeof(char));
        strcpy(tempEntryField.fieldname,strtok(line,"="));
    ...
        strcpy(tempEntryField.value,buffer);
    ...
    // Construction d'un nouveau maillon, insertion dans la liste 
    // après avoir initialisé les champs du maillon par recopie des champs fieldname et value
    // de la structure tempEntryField, autrement dit par recopie des adresses des
    // tableaux de char alloués dynamiquement. 
        listEntryFields = insertTailListEntrFi(&tempEntryField,listEntryFields); 
    
    // Destruction des tableaux : le maillon qu'on vient d'insérer a des champs
    // qui pointent vers des zones désallouées
        free(tempEntryField.fieldname);
        free(tempEntryField.value);
    ...
    }
    Ce qui peut alors se passer, est que, fortuitement, la fonction alloue toujours les 2 tableaux à la même adresse. Les maillons ont alors tous les mêmes adresses (d'où le même contenu) correspondant à deux zones désallouées mais sans doute non encore réutilisées ce qui fait qu'on y retrouve quelque chose.
    Publication : Concepts en C

    Mon avatar : Glenn Gould

    --------------------------------------------------------------------------
    Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !

  3. #3
    Candidat au Club
    Profil pro
    Inscrit en
    Novembre 2012
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2012
    Messages : 7
    Points : 3
    Points
    3
    Par défaut
    Oui, mais à l'intérieur de insertTailListEntrFi, on réalloue dynamiquement tempEntryField pour le placer dans un nouveau maillon, donc je ne voit pas en quoi les "free" pourraient désalouer la mémoire.

    On a bien :

    1) allocation de la mémoire
    2) remplissage des tableaux
    3) copie des tableaux dans la liste grâce à insertTailListEntrFi
    4) libération de la mémoire

    Je ne saisit vraiment pas où j'utilise une donnée désalouée...

  4. #4
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    Oui, mais à l'intérieur de insertTailListEntrFi, on réalloue dynamiquement tempEntryField pour le placer dans un nouveau maillon, donc je ne voit pas en quoi les "free" pourraient désalouer la mémoire.
    Non, on alloue dynamiquement un EntryFieldElem* dans lequel on recopie le contenu de tempEntryField, donc les deux pointeurs en question. Il n'y a pas de réallocation, ni de recopie, faite pour les chaines, seul le pointeur est copié.
    Publication : Concepts en C

    Mon avatar : Glenn Gould

    --------------------------------------------------------------------------
    Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !

  5. #5
    Candidat au Club
    Profil pro
    Inscrit en
    Novembre 2012
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2012
    Messages : 7
    Points : 3
    Points
    3
    Par défaut
    Aaaaaaaaaah, oui en effet, merci.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Liste chainée problème
    Par chmek firas dans le forum Débuter
    Réponses: 2
    Dernier message: 08/05/2012, 22h13
  2. Liste chainée - problème de return
    Par ghorg dans le forum Débuter
    Réponses: 10
    Dernier message: 06/12/2009, 19h54
  3. Liste chainée triée sans insertion de doublon
    Par Bogs dans le forum Débuter
    Réponses: 1
    Dernier message: 22/03/2009, 18h50
  4. Double liste chainée pour un memory manager
    Par FunkyTech dans le forum C++
    Réponses: 8
    Dernier message: 01/03/2008, 11h36
  5. Vider liste chainée, problème
    Par hunter99 dans le forum C
    Réponses: 39
    Dernier message: 28/03/2007, 21h08

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo