Est ce que ma liste chainee generique est bien faite?
juju0169
Messages postés15Date d'inscriptiondimanche 1 août 2004StatutMembreDernière intervention28 avril 2008
-
30 sept. 2006 à 00:27
cs_AlexN
Messages postés694Date d'inscriptionlundi 5 décembre 2005StatutMembreDernière intervention 8 janvier 2014
-
1 oct. 2006 à 16:43
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.
cs_AlexN
Messages postés694Date d'inscriptionlundi 5 décembre 2005StatutMembreDernière intervention 8 janvier 201419 30 sept. 2006 à 16:02
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.
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.
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. http://cslibrary.stanford.edu/104/
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.
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é.
Vous n’avez pas trouvé la réponse que vous recherchez ?
juju0169
Messages postés15Date d'inscriptiondimanche 1 août 2004StatutMembreDernière intervention28 avril 2008 1 oct. 2006 à 15:23
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.
cs_AlexN
Messages postés694Date d'inscriptionlundi 5 décembre 2005StatutMembreDernière intervention 8 janvier 201419 1 oct. 2006 à 16:43
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.
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).