begin process at 2012 05 29 06:30:13
  Trouver un code source :
 
dans
 
Accueil > Forum > 

C

 > 

Algorithme

 > 

Maths

 > 

Est ce que ma liste chainee generique est bien faite?


Derniers messages déposésPoser une question dans le forum ou lancer une discussion

Est ce que ma liste chainee generique est bien faite?

samedi 30 septembre 2006 à 00:27:33 | Est ce que ma liste chainee generique est bien faite?

juju0169

    Bonsoir a tous. Je vais une nouvelle fois avoir besoin de vous.

Je viens de finir un module de liste chainee generique et je voudrais savoir s'il est bien code.

Je m'explique au dela de la simple culture generale je vais devoir utiliser ce code pour un projet dans mes etudes et je ne voudrais pas partir sur de mauvaise base.

Je ne demande qu'a l'ameliorer et surtour a eviter les ERREURS.
PS : desole pour la longueur

*******************************************************************************
typedef void (* Traitement)(void *);

struct Cellule
{
    void * Element;                        //L'element stocke dans la cellule.
    struct Cellule * Cellule_Suivante;   //Pointeur sur la cellule suivante.
    Traitement Fonction_De_Traitement;
};

struct Liste
{
    struct Cellule * Premiere_Cellule; //Pointeur sur la premiere adresse de la liste.
};
*******************************************************************************
 
struct Liste * li_Initialiser_Liste (void)
{
    struct Liste * L1;
 
    if ( !(L1 = (struct Liste *) malloc (sizeof (struct Liste))) )
    {
       perror("ERREUR");
       exit(1);
    }     
     
    L1->Premiere_Cellule = NULL;
    return L1;
}
 
void li_Ajoute_EnTete (struct Liste * L1, const void * Element, const Traitement T)
{
    struct Cellule * Nouvelle_Cellule;     
 
    if ( !(Nouvelle_Cellule = (struct Cellule *) malloc (sizeof (struct Cellule))) ) 
    {
       perror("ERREUR");
       exit(1);
    }
   
    Nouvelle_Cellule->Element = (void *) Element;
    Nouvelle_Cellule->Fonction_De_Traitement = T;
    Nouvelle_Cellule->Cellule_Suivante = L1->Premiere_Cellule;
    L1->Premiere_Cellule = Nouvelle_Cellule;
}
 
void li_Supprimer_EnTete (struct Liste * L1)
{
    struct Cellule * Pointeur_Travail = L1->Premiere_Cellule;
 
    if (li_Tester_Liste_Vide(L1))
        printf("La liste est deja vide\n");
   
    else
    {
        L1->Premiere_Cellule = Pointeur_Travail->Cellule_Suivante;
        free(Pointeur_Travail);
    }
}

void li_Afficher_Liste (const struct Liste * L1)
{
        struct Cellule * Pointeur_Travail = L1->Premiere_Cellule;
       
        if (li_Tester_Liste_Vide(L1))
            printf("La liste est vide\n");

        else
        {
            while (Pointeur_Travail != NULL)
            {
                Pointeur_Travail->Fonction_De_Traitement (Pointeur_Travail->Element);
                Pointeur_Travail = Pointeur_Travail->Cellule_Suivante;
            }
           
            printf("\n");
        }
}
 
void li_Afficher_Entier (const void * Element)
{
        int * Pointeur_Sur_Entier = (int *) Element;
        printf("%d, ", * Pointeur_Sur_Entier);
}

void li_Afficher_Charactere (const void * Element)
{
        char * Pointeur_Sur_Charactere = (char *) Element;
        printf("%c, ", * Pointeur_Sur_Charactere);
}

void li_Afficher_Chaine_De_Characteres (const void * Element)
{
        printf("%s , ", (char *)Element);
}


******************************************************************************
    int i;
    struct Liste  * l;
    char * T[3] = {"PAPA", "MAMAN", "BEBE"};
   
    l = li_Initialiser_Liste();

    for (i = 9; i > 0; i--)
    {     
        int * p = (int *) malloc (sizeof (int));
        *p = i;
        li_Ajoute_EnTete (l, (int *) p, (void *) li_Afficher_Entier);
    }

    li_Afficher_Liste(l);
     
    for (i = 'E'; i >= 'A'; i--)
    {
        char * c = (char *) malloc (sizeof (char));
        *c = i;
        li_Ajoute_EnTete (l, (char *) c, (void *) li_Afficher_Charactere);
    }

    li_Afficher_Liste(l);

   for (i = 0; i <= 2; i++)
        li_Ajoute_EnTete (l, (char **) T[i], (void *)
                                   li_Afficher_Chaine_De_Characteres);
  
   li_Afficher_Liste(l);      
******************************************************************************

Merci pour tous vos futurs conseils et j'espere ne pas m'etre prompte de section pour poster.

Bonne soiree

samedi 30 septembre 2006 à 11:48:43 | Re : Est ce que ma liste chainee generique est bien faite?

Joky

Membre Club
Tu alloues de la mémoire avec malloc mais tu libères rien... y'a un souci quelque part :)


ULARGE_INTEGERJokyQi=QI("Joky"

samedi 30 septembre 2006 à 16:02:52 | Re : Est ce que ma liste chainee generique est bien faite?

AlexN

Ta liste va poser des problèmes de mémoire.

Tu fais des malloc (int) et des malloc (char) mais tu ne fais pas les free() qui vont avec. Même si tu libères ta liste (Supprimer), des blocs de mémoires vont restés occupés par des résidus de ta liste.

Ta fonction supprimer() peut faire des free() sur des chaînes de caractères ou des structures qui n'auront pas été allouées sur le tas par malloc(), calloc() ou realloc(). Ton programme peut avoir des comportements indeterminés.

Il faut par exemple rajouter un champ dans la Cellule
int ALiberer;
pour que la fonction Supprimer() sache si elle doit libérer ou non ce qui ce trouve pointé par Element.

Tester les appels système est un bon reflexe et ne pas croire que parce qu'on invoque malloc() ça réussi à tous les coups.

perror() affiche un message d'erreur plus clair qu'un simple code d'erreur, mais le paramètre "ERREUR" est trop succint. perror("malloc(main)"), perror("free(Supprimer)"), etc permet de localiser plus facilement une erreur et d'éviter de se servir d'un debugger pour localiser simplement un free() oublié dans un programme de quelques lignes.

samedi 30 septembre 2006 à 18:49:25 | Re : Est ce que ma liste chainee generique est bien faite?

juju0169

OK merci pour ces premiers conseils ils sont les biens venus Par contre il y a surtout deux trucs qui me travaille. 1er truc ********************************************************************* dans ma fonction ajouter est ce que cela suffit de faire Nouvelle_Cellule->Element = (void *) Element; car si au depart ça me semble correct je me suis rendu compte que j'avais un probleme quand j'utilise ma liste comme ceci struct Liste * l; l = li_Initialiser_Liste(); int * p = (int *) malloc (sizeof (int)); *p = 10; li_Ajoute_EnTete (l, (int *) p, (void *) li_Afficher_Entier); *p =12; li_Ajoute_EnTete (l, (int *) p, (void *) li_Afficher_Entier); Est bien la je me retrouve avec une liste 12, 12 (le dernier element apparait dans toute ma liste c est a dire si j'insere 10 elements (Nouvelle_Cellule->Element = (void *) Element) de cette maniere la liste sera 9, 9 ,9 9 ,9 9,9...9, Ne faut il pas plutot utiliser une fonction clone comme gere? Nouvelle_Cellule->Element = clone (Element); Ou alors je fais bien d'utiliser une nouvelle variable a chaque fois 2ieme truc********************************************************************* SI j'ai bien compris les indications que j'avais pour faire cette liste il est impossible de faire Ajouter_Entete(l, p, (void *)li_Afficher_Entier); ou p serait un simple int p = 10; ou p char p = 'E"; Encore merci pour toutes vos reponses je cherche vraiment a faire le truc le plus propre (au niveau code) et le plus efficace au niveau implantion et surtout ne pas passer a coter de quelque chose. Bonne soiree
dimanche 1 octobre 2006 à 15:06:48 | Re : Est ce que ma liste chainee generique est bien faite?

AlexN

la différence entre (1)

for (i = 9; i > 0; i--)
{     
   int * p = (int *) malloc (sizeof (int));
   *p = i;
   li_Ajoute_EnTete (l, (int *) p, (void *) li_Afficher_Entier);
}

et (2)

int * p = (int *) malloc (sizeof (int));
*p = 10;
li_Ajoute_EnTete (l, (int *) p, (void *) li_Afficher_Entier);
*p =12;
li_Ajoute_EnTete (l, (int *) p, (void *) li_Afficher_Entier);

est que dans le premier cas tu alloues dix blocs de mémoires différents que tu remplis chacun avec une valeur différentes (de 9 à 1), tandis que dans le second cas tu n'alloues qu'un seul bloc de mémoire auquel tu affectes differentes valeurs (10 puis 12).
Or ce que tu passes à la fonction Ajouter(), ce n'est pas la valeur elle même, mais l'adresse (la valeur du pointeur p) du bloc mémoire contenant cette valeur. La fonction Ajouter() ne recopie pas cette valeur mais recopie seulement l'adresse du bloc contenant cette donnée. Comme dans le second c'est toujours le même bloc donc toujours la même adresse (ou la même valeur du pointeur p), toutes les cellules pointent vers le même bloc mémoire. La valeur (la dernière que tu auras mise dans le bloc pointé par p) affichée est alors toujours la même puisqu'il s'agit du même bloc.

La fonction clone() n'est pas un standard du c, mais une fonction de l'api linux qui concerne la programmation multiprocessus, elle n'a rien à voir avec la gestion de la mémoire (malloc, calloc, realloc, free..).

Finalement voici l'adresse d'un tutorial vidéo sur les pointeurs qui est dans la bibliothèque de l'université de standford. Malgré le fait que ce tutorial ait l'air simpliste, il contient les notions essentielles qu'il faut comprendre pour maîtriser cette notion. Il vaut mieux le regarder plusieurs fois avant d'être sur d'avoir compris. [ Lien ]

2ieme truc*********************************************************************

Si c'est possible, parce que lorsque tu écris :
int p1 = 10;
Ajouter(p1);
int p2 = 11;
Ajouter(p2);
char c1 = 'E';
Ajouter(c1);
A chaque déclaration, une zone est reservée dans la pile d'exécution du programme pour contenir la valeur déclarée. Et chacune de tes cellules pointera sur une zone distincte dans cette pile.
Le seul problème que tu auras c'est qu'ayant déjà déclaré p comme int, le compilateur refusera que tu le redéclares en char. (d'où les p1, p2...).

Enfin une petite remarque sur la concision des écritures. Le langage c est un langage concis, qui permet d'écrire beaucoup de chose avec peu de symbôles. Il n'est pas nécessaire de faire du Baudelaire ou du Proust quand on écrit en c et c'est même nuisible à la lisibilité. J'aurais plutôt écris des nom de fonction comme Ajouter() ou AjouterListe() et des nom de variables comme cell plutôt que Pointeur_Travail. Mais il ne faut pas être trop court non plus. Un nom de  fonction comme a() ou b() ça ne veut rien dire.

Certaines variables sont inutiles :
void li_Afficher_Charactere (const void * Element)
{
        char * Pointeur_Sur_Charactere = (char *) Element;
        printf("%c, ", * Pointeur_Sur_Charactere);
}
peut devenir :
void Afficherc (const void * e) { printf("%c, ", (char *) e);  }

Les boucle for sont très puissantes et très utiles :

void li_Afficher_Liste (const struct Liste * L1)
{
        struct Cellule * Pointeur_Travail = L1->Premiere_Cellule;
       
        if (li_Tester_Liste_Vide(L1))
            printf("La liste est vide\n");

        else
        {
            while (Pointeur_Travail != NULL)
            {
                Pointeur_Travail->Fonction_De_Traitement (Pointeur_Travail->Element);
                Pointeur_Travail = Pointeur_Travail->Cellule_Suivante;
            }
           
            printf("\n");
        }
}

pourrait devenir :

void li_Afficher_Liste (const struct Liste * L1)
{
        struct Cellule * cell;
       
        if (li_Tester_Liste_Vide(L1))
            printf("La liste est vide\n");
        else {
                for ( cell = L1->Premiere_Cellule; cell; cell = cell->Cellule_Suivante)
                        cell->Fonction_De_Traitement (cell->Element);
                puts("");
        }
}

Maintenant faire du générique avec le c, c'est un peu de la haute volée, c++ est plus adapté.
dimanche 1 octobre 2006 à 15:23:27 | Re : Est ce que ma liste chainee generique est bien faite?

juju0169

Merci AlexN pour ces nouvelles infos Pour ce qui conserne la fonction Clone je ne savez meme pas qu'il existait une fonction comme ca je voulais en cree une a moi. Et en ce qui conserne le langage c'est quelque chose qui met impose. Par contre j'ai cree cette fonction clone alors voici les modifs. Et cette fois ci si je ne me trompe pas on peut utiliser la meme variable pour ajouter (du genre int * p1= (int *) malloc .... *p1 = 15; ajout(..,*p1, ....) *p1 = 20; ajout(..,*p1, ....) et on a bien 20, 15 et plus 20,20 ) PS : La version que je poste date d'avant les conseils, donc pas de panique vous conseils ne sont pas tombes dans l'oreille d'un sourd. ***************************************************************************** typedef void * (* Ajouter) (void *); typedef void (* Traiter)(void *); struct Cellule { void * Element; struct Cellule * Cellule_Suivante; Traiter Fonction_De_Traitement; Ajouter Fonction_D_Ajout; }; struct Liste { struct Cellule * Premiere_Cellule; //Pointeur sur la premiere adresse de la liste. }; ****************************************************************************** void li_Ajouter_EnTete (struct Liste * L1, const void * Element, const Traiter Traite, const Ajouter Ajoute) { struct Cellule * Nouvelle_Cellule; if ( !(Nouvelle_Cellule = (struct Cellule *) malloc (sizeof (struct Cellule))) ) { perror("ERREUR"); exit(1); } Nouvelle_Cellule->Fonction_D_Ajout = Ajoute; Nouvelle_Cellule->Fonction_De_Traitement = Traite; Nouvelle_Cellule->Element = Nouvelle_Cellule->Fonction_D_Ajout( (void *) Element); Nouvelle_Cellule->Cellule_Suivante = L1->Premiere_Cellule; L1->Premiere_Cellule = Nouvelle_Cellule; } int * li_Ajouter_Entier (const void * Element) { int * Pointeur_Entier; if ( !(Pointeur_Entier = (int *) malloc (sizeof (int))) ) { perror("ERREUR"); exit(1); } *Pointeur_Entier = * (int *)Element; return Pointeur_Entier; } char * li_Ajouter_Charactere (const void * Element) { char * Pointeur_Charactere; if ( !(Pointeur_Charactere = (char *) malloc (sizeof (char))) ) { perror("ERREUR"); exit(1); } *Pointeur_Charactere = * (char *)Element; return Pointeur_Charactere; } char ** li_Ajouter_Chaine_De_Characteres (const void * Element) { char ** Pointeur_Chaine_Characteres; if ( !(Pointeur_Chaine_Characteres = (char **) malloc ( (4 * sizeof (char )) )) ) { perror("ERREUR"); exit(1); } *Pointeur_Chaine_Characteres = * (char **)Element; return Pointeur_Chaine_Characteres; }
dimanche 1 octobre 2006 à 16:43:53 | Re : Est ce que ma liste chainee generique est bien faite?

AlexN

Oui, c'est une bonne solution, elle consiste à créer un nouveau bloc et à y recopier le contenu du bloc passé en argument pour devenir une donnée propre à la liste. Mais incomplète pour les chaînes de caractères :
En fait lorsque tu écris :
*Pointeur_Entier = * (int *)Element;
le contenu du bloc pointé par Element est recopié dans le bloc pointé par Pointeur_Entier, parce que ce sont des types simples, et que l'affectation provoque en interne la recopie du contenu du bloc. Il se passe un peu l'équivalent de :
memcpy ((void *)Pointeur_Entier, (void *) Element, sizeof (int));
C'est la même chose avec
*Pointeur_Charactere = * (char *)Element;
qui provoque l'équivalent de :
memcpy ((void *)Pointeur_Charactere, (void *) Element, sizeof (char));

Mais :
*Pointeur_Chaine_Characteres = * (char **)Element;
ne provoque que la recopie d'une adresse d'un pointeur dans un autre. Pas les données elles même.

Un autre problème avec les chaines de caractères :
if ( !(Pointeur_Chaine_Characteres = (char **) malloc ( (4 * sizeof (char ))    )) )
Pour toutes les chaînes. tu n'alloues un bloc que pour quatre caractères (3 plus le '\0')
Tes chaînes de caractères vont déborder. Il vaut mieux écrire quelquechose comme :
if ( ! (Pointeur_Chaine_Characteres = (char *) malloc ( strlen((char *)Element) + 1) ))

Enfin les pointeurs de pointeur sont plutôt utiles quand on utilise des tableaux.

char * li_Ajouter_Chaine_De_Characteres (const void * Element)
{
char * Pointeur_Chaine_Characteres;

if ( ! (Pointeur_Chaine_Characteres = (char *) malloc(strlen((char *) Element) + 1) ))
{
perror("ERREUR");
exit(1);
}
if ( ! strcpy (Pointeur_Chaine_Characteres, (char *)Element) )
{
perror("strcpy()");
exit(1);
}
return Pointeur_Chaine_Characteres;
}

Finalement tu n'auras pas besoin de fonction clone() puisque la recopie des données sera assurée par les fonctions Ajouter().

Tu es en train de faire du pseudo objet (générique) avec du c. C'est un bon exercice qui permet entre autre de bien comprendre les pointeurs, mais aussi pourquoi le c++ a été créé. Tes Cellules contiennent chacune des pointeurs vers les fonctions capables de gérer (afficher, ajouter, etc) le type contenu dans la cellule (les fonctions membres). En c++, pour simplifier le tout et éviter d'avoir 15 pointeurs de fonctions dans chaque cellule (objet), chaque objet contient un pointeur vers sa classe qui est chargée d'appeler la fonction adaptée (les fonctions virtuelles) au type (classe) contenu dans la Cellule (objet).


Cette discussion est classée dans : liste, cellule, void, struct, li


Répondre à ce message

Sujets en rapport avec ce message

liste chainée en C [ par liliefr2000 ] bonjour!!j'ai besoin d'aide s'il vous plait!jai le tp suivant a faire:SujetEcrire un programme qui permet de saisir un texte et de l'afficher à l'écra liste chainée double générique [ par issoux ] Bonsoir ,  j'ai un probleme dans mon code :  Code: #include <stdlib.h& fonctions de listes chainees en c [ par loftiteau ] bonjourje souhaite avoir d'aide pour faire des fonctions d'ajout et suppression et modification en utilisant la liste chainé suivante en language c :s Fonction recherche (listes chainées) [ par adri10 ] Bonjour à tous, Bon voilà j'ai un gros problème avec ma fonction recherche en liste chainées. Je pensais que mon programme était correct puisqu'en le Fichier + liste chainée [ par Evisu ] Bonsoir,J'ai une question concernant l'écriture et la lecture de liste chainée dans un fichier.dataJ'ai une structure PERS qui contient des infos (nom Trier une liste chainée [ par ango973 ] Bonjour,J'ai un probleme avec une fonction qui doit me trier une liste chainée selon le nom mais apres le passage dans ma fonction la liste reste iden Problème avec liste chainée [ par MasterShadows ] Bonjour à tous ,alors voilà dans le cadre de mon tp de C je dois créer une liste simplement chainée tout ce qu'il y'a de plus générique.donc on nous d Suppression cellule d'une liste doublement chainée [ par donlefou ] Quelqu'un pourrait m'écrire le code pour supprimer une cellule à une position dans une liste.J'ai un fichier C_Cellule.hpp / C_Cellule.cpp de cette st Listes chainées [ par angelfire0808 ] Bonjour voila voici mon, code j'ai une ereeur de compilation mais je ne comprend pas ;-(l'erreur c'est ici :   " nouveau->suivant=(*tete); ".De plus j classe avec liste simple [ par Olive512005 ] Bonjour ,je voudrais avant tout remercier pour les réponses que j'ai eu à propos du tableau. voila j'ai un petit problème à résoudre encore, il faud


Nos sponsors


Sondage...

CalendriCode

Mai 2012
LMMJVSD
 123456
78910111213
14151617181920
21222324252627
28293031   

Consulter la suite du CalendriCode

A découvrir



 
Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils.
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés

Google Coop CodeS-SourceS Google Coop CodeS-SourceS
Temps d'éxécution de la page : 0,718 sec (3)

Nous contacter | Annoncer sur CodeS-SourceS | Mentions légales