Il y a 5 ans de cela, je vous entretenais sur la beauté des SLIST, un concept issu du monde BSD permettant de facilement manipuler des listes chainées dans votre code C sans avoir à réinventer la roue à chaque code.
Comme je n’avais plus manipulé ce type d’objet depuis un certain temps, je me suis replongé dans ce petit tutoriel, mais je lui ai trouvé un manque que je m’apprète à combler ici même.
La manipulation des SLIST est très aisée lorsque l’on a la possibilité de déclarer sa liste de manière globale, il suffit alors, dans chaque fonction, d’appeler la “tête de liste”, souvent appelée head, via les multiples macros présentes dans queue.h.
J’ai ecrit, toujours dans la documentation sus-citée, un minuscule passage sur la façon d’utiliser les SLIST avec les macros SLIST_FIRST et SLIST_NEXT, mais je m’aperçois qu’on ne se rend pas compte de leur utilité.
Prenons le cas suivant, je veux créer une liste chainée de type SLIST dans une fonction. Je souhaite pouvoir ballader cette liste de fonctions en fonctions, et evidemment, la libérer à la fin de mes travaux. Nous utiliserons notre liste de la sorte :
/* headers et diverses déclarations */
#include <sys/queue.h>
typedef struct Mastruct {
int id;
char *element;
SLIST_ENTRY(, Mastruct) next;
} Mastruct;
/* plein de trucs */
Mastruct *
initialisation(int id, const char *str)
{
Mastruct *mesdatas;
/* on déclare la tête de liste */
SLIST_HEAD(, Mastruct) datahead;
/* on l'initialise à NULL */
SLIST_INIT(&datahead);
if ((mesdatas = malloc(sizeof(Mastruct)) == NULL)
err("malloc error");
mesdatas->id = id;
if (str != NULL) {
mesdatas->element = strdup(str);
} else {
mesdatas->element = NULL;
}
/* on accroche la structure fraichement allouée à la tête de liste */
SLIST_INSERT_HEAD(&datahead, mesdatas, next);
/* et on renvoie le premier élément de datahead, ici, mesdatas*/
return SLIST_FIRST(&datahead);
}
Dans ce cas de figure, nous ne renvoyons pas la tête de la liste mais simplement le premier élément de la liste chainée. Pour parcourir simplement cette liste, nous utiliserons la macro SLIST_NEXT :
Mastruct *mesdatas, *p;
/* des trucs */
mesdatas = initialisation(id, unechaine);
for (p = mesdatas; p != NULL; p = SLIST_NEXT(p, next))
printf("%d -> %s", p->id, p->element);
De la même façon, on pourra simplement libérer cette liste simplement chainée grace à une boucle de ce type :
void
free_datas(Mastruct *mesdatas)
{
struct Mastruct *p;
/* on boucle tant que le nouveau chainon n'est pas nul */
while (mesdatas != NULL) {
/* on sauvegarde le prochain chainon */
p = SLIST_NEXT(mesdatas, next);
/* on libère le contenu */
free(mesdatas->element);
/* puis le chainon courant */
free(mesdatas);
/* puis on fait pointer la variable principale vers la sauvegarde */
mesdatas = p;
}
}
Désormais, avec un effort minimum, nous voici en mesure de très simplement créer des listes de données rapides et dynamiques.
Recent Comments