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 :

Liste chainée de liste chainée


Sujet :

C

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

    Informations forums :
    Inscription : Novembre 2008
    Messages : 4
    Points : 3
    Points
    3
    Par défaut Liste chainée de liste chainée
    Bonjour, je rencontre un pb pour lire une liste chainée contenant une autre liste chainée dans un fichier.
    La structure de ses listes est la suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    typedef struct Famille {
    	char nom[30];
    	struct Famille *next;
    	struct Enfant *tete;
    } Famille;
     
    typedef struct Enfant {
    	char prenom[30];
    	struct Enfant *next;
    } Enfant;
    Pour enregistrer cette liste dans un fichier, j'utilise la fonction suivante :

    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
     
    void sauvegarder(Famille **tete) {
    	Famille *p = *tete;
    	Enfant *e = NULL;
    	FILE *f = fopen("db3", "wb");
     
    	while(p != NULL) {
    		fwrite(p, sizeof(Famille), 1, f);
     
    		e = p->tete;
    		while(e != NULL) {
    			fwrite(e, sizeof(Enfant), 1, f);
    			e = e->next;
    		}
     
    		p = p->next;
    	}
     
    	fclose(f);
    }
    Mon probleme se trouve dans la fonction charger. Je ne sais pas quoi mettre dans la boucle qui va relier chaque enfant à une famille.
    Voila le code de la fonction :

    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
     
    void charger(Famille **tete) {
    	Famille *p = NULL, *q = NULL;
    	Enfant *e = NULL, *ep = NULL;
    	FILE *f = fopen("db3", "rb");
     
    	*tete = NULL;
     
    	while(!feof(f)) {
    		p = (Famille *) malloc(sizeof(Famille));
    		fread(p, sizeof(Famille), 1, f);
     
    		if(*tete == NULL)
    			*tete = p;
    		else
    			q->next = p;
    		p->next = NULL;
    		q = p;
     
    		p->tete = NULL;
     
     		while() {
     			e = (Enfant *) malloc(sizeof(Enfant));
    			fread(e, sizeof(Enfant), 1, f);
     
     			if(p->tete == NULL)
     				p->tete = e;
     			else
     				ep->next = e;
     			e->next = NULL;
     			ep = e;
     		}
    	}
     
    	fclose(f);
    }
    Merci d'avance pour votre aide.

  2. #2
    Membre émérite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2008
    Messages
    1 515
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 515
    Points : 2 505
    Points
    2 505
    Par défaut
    Le format de ton fichier n'est pas correct, puisqu'il ne contient pas le lien qu'il y a entre un enfant et une famille. Il faut bien que tu réalises que sauvegarder les pointeurs dans le fichier comme tu le fais n'est d'aucun secour. Un pointeur est une adresse en mémoire. Quant tu lis ton fichier et que tu recréé tes structures, elles seront à des adresses différentes, et les pointeurs pointeront dans le vide.

  3. #3
    Rédacteur/Modérateur
    Avatar de Trap D
    Profil pro
    Inscrit en
    Septembre 2003
    Messages
    4 942
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2003
    Messages : 4 942
    Points : 6 498
    Points
    6 498
    Par défaut
    Tu peux sauvegarder ton fichier sous forme texte style CVS de la forme
    famille; enfant; enfant; enfant
    famille; enfant
    famille; enfant; enfant

    la fonction sauvegarde serait de la forme

    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 sauvegarder(Famille **tete) {
    	Famille *p = *tete;
    	Enfant *e = NULL;
    	FILE *f = fopen("db3", "w");
     
    	while(p != NULL) {
    		fprintf(f, p->nom, f);
     
    		e = p->tete;
    		while(e != NULL) {
    			fprintf(f, ";%s", e->prenom);
    			e = e->next;
    		}
                    fprintf(f, "\n");
    		p = p->next;
    	}
     
    	fclose(f);
    }
    la fonction de lecture est un peu plus compliquée :
    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
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    void charger(Famille **tete) {
    	Famille *p = NULL, *q = NULL;
    	Enfant *e = NULL, *ep = NULL;
    	chat buf[1024];
     
    	FILE *f = fopen("db3", "r");
     
    	*tete = NULL;
     
    	while(fgets(buf, sizeof buf, f) != NULL) {
    		// on supprime d'abor le '\n' à la fin pour voir
    		// si la taille du buffer est assez grande
    		char *ptr = strchr(buf, '\n');
    		char *ptr1;
     
    		if (ptr == NULL)
    		{
    			// ici il y a problème
    			// a toi de voir ce que tu veux faire
    			return ???
    		}
    		// on supprime le '\n'
    		*ptr = 0;
     
    		// les cast sont inutiles en C
    		p = malloc(sizeof(Famille));
     		if (p == NULL)
    		{
    			// ici il y a problème
    			// a toi de voir ce que tu veux faire
    			return ???
    		}
     
    		// on lit le nom de famille
    		ptr = strchr(buf, ';');
    		if (ptr != NULL)
    		{
    			*ptr = 0; 
    			ptr1 = ptr+1;
    		}
     
    		strcpy(p->nom, buf);
     
    		if(*tete == NULL)
    			*tete = p;
    		else
    			q->next = p;
    		p->next = NULL;
    		q = p;
     
    		p->tete = NULL;
     
    		// on entre dans la boucle de lecture des enfants
    		while (ptr != NULL)
    		{
    			ptr1 = ptr+1;
    			ptr = strchr(ptr1, ';');
    			if (ptr != NULL)
    				*ptr = 0;
     
    			e = malloc(sizeof(Enfant));
    			if (e == NULL)
    			{
    				// ici il y a problème
    				// a toi de voir ce que tu veux faire
    				return ???
    			}
     			strcpy(e->prenom, ptr1);
     			if(p->tete == NULL)
     				p->tete = e;
     			else
     				ep->next = e;
     			e->next = NULL;
     			ep = e;
     
    		}
     	}
     
    	fclose(f);
    }
    n'ayant pas le C sur ma machine actuellement, ce n'est pas testé, mais c'est l'idée.
    Evidemment, comme le séparateur de champ est ';', celà ne marche pas s'il y en a un dans les noms de famille, mais c'est quand même assez rare, enfin je crois !
    "La haine seule fait des choix" - Koan Zen
    "Il ne faut pas être meilleur que les autres, il faut être meilleur que soi." Albert Jacquard
    "Ceux qui savent où ils ont posé leur parapluie ne sont pas alcooliques." - pgibonne.
    Faites du Prolog, ça vous changera les idées !
    Ma page Prolog
    Mes codes sources commentés

    Mon avatar : La Madeleine à la veilleuse de Georges de La Tour

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

    Informations forums :
    Inscription : Novembre 2008
    Messages : 4
    Points : 3
    Points
    3
    Par défaut
    Merci pour cette reponse rapide !
    J'arrive bien à ecrire et a récupérer correctement mes familles. J'ai ajouter un char contenant 'F' quand j'enregistre une famille et un contenant 'E' quand j'enregistre un enfant.
    Je recupere ce caractere et je le test dans ma fonction charger pour choisir le bon fread.

    Je met ici les deux fonctions pour les gens que ca interesse.

    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
     
    void sauvegarder(Famille **tete) {
    	Famille *p = *tete;
    	Enfant *e = NULL;
    	FILE *f = fopen("db3", "wb");
    	char cF = 'F', cE = 'E';
     
    	while(p != NULL) {
    		fwrite(&cF, sizeof(char), 1, f);
    		fwrite(p, sizeof(Famille), 1, f);
     
    		e = p->tete;
    		while(e != NULL) {
    			fwrite(&cE, sizeof(char), 1, f);
    			fwrite(e, sizeof(Enfant), 1, f);
    			e = e->next;
    		}
     
    		p = p->next;
    	}
     
    	fclose(f);
    }
    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
     
    void charger(Famille **tete) {
    	Famille *p = NULL, *q = NULL;
    	Enfant *e = NULL, *ep = NULL;
    	FILE *f = fopen("db3", "rb");
    	char c;
     
    	*tete = NULL;
     
    	while(!feof(f)) {
    		fread(&c, sizeof(char), 1, f);
    		if(c == 'F') {
    			p = (Famille *) malloc(sizeof(Famille));
    			fread(p, sizeof(Famille), 1, f);
     
    			if(*tete == NULL)
    				*tete = p;
    			else
    				q->next = p;
    			p->next = NULL;
    			q = p;
     
    			p->tete = NULL;
    		} else {
    			e = (Enfant *) malloc(sizeof(Enfant));
    			fread(e, sizeof(Enfant), 1, f);
     
    			if(p->tete == NULL)
    				p->tete = e;
    			else
    				ep->next = e;
    			e->next = NULL;
    			ep = e;
    		}
    	}
     
    	fclose(f);
    }

  5. #5
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Je pense qu'un format "Famille, nombre d'enfants, enfants" serait plus facile à lire, car il ne restreint pas le format de lecture. Ainsi, si tu faisais un programme utilisant des tableaux plutôt que des listes, il pourrait quand même lire le fichier facilement.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  6. #6
    Rédacteur/Modérateur
    Avatar de Trap D
    Profil pro
    Inscrit en
    Septembre 2003
    Messages
    4 942
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2003
    Messages : 4 942
    Points : 6 498
    Points
    6 498
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Je pense qu'un format "Famille, nombre d'enfants, enfants" serait plus facile à lire, car il ne restreint pas le format de lecture. Ainsi, si tu faisais un programme utilisant des tableaux plutôt que des listes, il pourrait quand même lire le fichier facilement.
    Ça oblige à parcourir d'abord la liste des enfants, ou faire des positionnements toujours un peu dangereux dans le fichier.
    Je reste persuadé que le format CSV (et non pas CVS comme je l'ai écrit tout à l'heure) est le meilleur pour ce genre de problème, même s'il la lecture/ecriture est plus lente.
    "La haine seule fait des choix" - Koan Zen
    "Il ne faut pas être meilleur que les autres, il faut être meilleur que soi." Albert Jacquard
    "Ceux qui savent où ils ont posé leur parapluie ne sont pas alcooliques." - pgibonne.
    Faites du Prolog, ça vous changera les idées !
    Ma page Prolog
    Mes codes sources commentés

    Mon avatar : La Madeleine à la veilleuse de Georges de La Tour

  7. #7
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    En effet, il faudrait parcourir la liste avant.
    D'un autre côté, c'est la même chose que faire un strlen() avant de dupliquer une chaîne: C'est une recherche de la valeur sentinelle pour calculer la taille.

    À moins d'avoir un besoin vraiment critique en termes de performances, ça ne me parait pas handicapant.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  8. #8
    Candidat au Club
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    4
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 4
    Points : 3
    Points
    3
    Par défaut
    Je n'ai pas utilisé de tableau ici car je ne voulais pas devoir reallouer un nouveau tableau à chaque fois que j'ajoute une famille ou un enfant.
    D'autre part je ne pouvais pas non plus utiliser le format csv car j'enregistre dans cette structure d'autres elements binaires (des types propres à qt par exemple) que je n'ai pas postés ici pour ne pas alourdir le poste.
    La methode que j'ai utilisée d'en mon dernier post est suffisante pour lier les enfants à chaque famille car comme j'enregistre tous les elements dans l'odre, des que je lis une famille, je sais que toutes les structures enfant suivantes appartiennent à cette famille.
    Merci de votre aide.
    Je reviendrais surement pour d'autres soucis

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

Discussions similaires

  1. [AC-2007] Zone de liste dépend de liste déroulante et chaine de caractère
    Par vincent1746 dans le forum IHM
    Réponses: 4
    Dernier message: 11/05/2010, 14h12
  2. Comparer deux chaines de liste
    Par zooffy dans le forum Développement
    Réponses: 9
    Dernier message: 20/02/2009, 12h35
  3. Réponses: 12
    Dernier message: 03/07/2008, 13h53
  4. Liste de tableau de chaine de caractère
    Par johnnydepp dans le forum C
    Réponses: 2
    Dernier message: 25/02/2007, 12h26
  5. Liste modifiable : longueur de chaine.
    Par pifou02 dans le forum Access
    Réponses: 8
    Dernier message: 09/01/2006, 15h47

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