Pourquoi la fonction LIST_DESTROY, GRATUITE Pourquoi devons-nous taper Casting Gratuit pour Cordes (Char *) mais pas INT, supposerait-il de le faire à tous les types? P> Didacticiel original: https : //pseudomuto.com/2013/05/Implementaling-a-generic-linked-list-in-c/ p> void list_destroy(list* list)
{
listNode* current;
while (list->head != NULL) {
current = list->head;
list->head = current->next;
if (list->freeFn) {
list->freeFn(current->data);
}
free(current->data);
free(current);
}
}
void free_string(void* data)
{
free(*(char**)data);
}
void list_new(list* list, int elementSize, freeFunction freeFn)
{
assert(elementSize > 0);
list->logicalLength = 0;
list->elementSize = elementSize;
list->head = list->tail = NULL;
list->freeFn = freeFn;
}
void main()
{
...
list list;
list_new(&list, sizeof(char*), free_string);
...
list_destroy(&list);
}
3 Réponses :
Le résultat de Le tutoriel est faux, car les données de membre ne sont pas attribuées. Une solution possible serait de changer: p> à: p> et modifier: p> freefn (actuel-> données) code> est
gratuit (* (* (* * *)) code> qui est différent de
gratuit (actuel-> données) code>; Bien que soit douteux. Notez que la différence provient de la déséroférance de l'argument Data (& Current-> Data).
void free_string(void* data)
{
free(*(char**)data);
*(char **)data = 0;
}
Vous avez tort - lorsqu'un nœud de liste est créé, l'espace est i> attribué pour les données.
Je pense que vous pouvez le voir si vous faites votre propre intacte. Prenez la ligne de free_string et mettez-la dans la liste_Destroy. Ce que vous avez, c'est que vous faites des données gratuites deux fois, mais les données ont déjà été libérées. Une fois que l'option est de modifier le free_string sur ce qui suit (la coulée n'est pas requise): et l'appelez avec list-> freefn (& actuel-> données); code> p> p>
Je pense que cela rendrait la mise en œuvre de la liste moins générique. A void * code> peut pointer sur un objet de n'importe quel type, mais un
void ** code> peut seulement pointer sur un
vide * code>.
Est-ce que ça importe? Free code> est déclaré comme
gratuit (vide *); code>, nous avons donc un vide * de toute façon.
Le point est que le rappel freefn code> doit pouvoir être utilisé pour nettoyer n'importe quelle valeur. Par exemple, si la liste a été utilisée pour stocker des valeurs
struct FOO code> avec le type défini comme
struct foo {char * a; Char * b; } code> avec le
A code> et
B code> Membres pointant vers des chaînes allouées dynamiquement, le rappel code> freefn code> serait quelque chose comme:
vide free_foo (void * données) { code>
struct foo * p = données; code>
gratuit (p-> a); Gratuit (p-> B); code>
} code>. Voir ce que je veux dire par "générique"?
Je ne pense pas que cela vaut la peine de -1, mais c'est ce que c'est.
L'implémentation de la liste générique stocke les valeurs d'élément d'une taille fixe fournie à Dans l'exemple de chaîne, la valeur à stocker est un Le S'il est plus facile de voir ce que Comme vous pouvez le voir, list_new () code> avec un pointeur sur une fonction de rappel en option pour libérer la valeur de l'élément lorsqu'un nœud de liste est détruit. La taille de l'élément est stockée dans le membre
ELSIZE code> de la liste et le pointeur de fonction de rappel (qui est
null code> si aucune fonction de rappel doit être appelée) est stockée dans le
freefn code> membre.
list_append () code> et
list_prepend () code> Ajouter un nouveau nœud à la liste et est fourni avec un pointeur à la valeur de l'élément à ajouté à la liste. Ils allouent un nouveau nœud de liste et allouer un bloc de mémoire pointé par
nœud-> données code> pour maintenir la valeur d'élément, qui est copié dans le bloc de mémoire alloué à l'aide de
memcpy () code> . P>
list_destroy () code> libère tous les nœuds de la liste, appelant la fonction
freefn code> Fonction de rappel (si fourni) avec les données
code > Pointeur pour chaque valeur d'élément. Il appartient à la fonction de rappel pour définir ce qu'il faut faire avec la valeur de l'élément pour la libérer. La fonction de rappel ne libère pas la mémoire pointée par le pointeur code> Data Code>. Il utilise la valeur indiquée par le pointeur code> code>. Il est
list_destroy () code> qui libère le bloc de mémoire code> code> alloué par
list_append () code> ou
list_prepend () < /code >.
loget> Entier, la valeur à stocker est juste une valeur de type int code>. Le membre
éléments code> de la liste est
Tailleof (int) code>. Le pointeur de la fonction de rappel code> freefn code> est
null code> car rien ne doit être fait pour libérer un
int code> - il n'est qu'un chiffre. L'exemple appelle
list_append () code> avec un pointeur sur la valeur
int code> à stocker.
list_append () code> attribue un bloc de taille
Tailleof (int) code>, pointé par
noeud-> données code> et copie le
int < / CODE> VALEUR EN IT. P>
char * code> qui pointe sur un tampon à chaîne alloué de manière dynamique allouée par
STRUP () code>. Ce tampon doit être libéré lorsque le nœud de la liste est détruit. Par conséquent, l'exemple de chaîne fournit un pointeur à la fonction
free_string code> pour libérer le tampon de chaîne attribué par
STRUP () code>. L'exemple d'appels
list_append () code> avec un pointeur sur la valeur
Char * CODE> Valeur à stocker.
list_append () code> attribue un bloc de taille
Tailleof (Char *) Code>, pointé par
noeud-> données code> et copie le
* code> la valeur. (Remarque: il copie la valeur du pointeur code> Char * code>, pas le contenu de la chaîne. Le contenu de la chaîne a été copié par
STRUP () code>.) P>
free_string () code> La fonction de rappel reçoit un indicateur
Void (code> VOID * / code> sur une copie de la valeur pointée dans l'appel à
list_append () code >. Il pointe de la valeur
char * code>, la première chose à faire est de convertir le pointeur Generic
Void * code> sur un
Char ** code> Pointeur . Cela fait-il avec un opérateur de type de type:
(char * **) données code>. Ensuite, il déréférences em> le
Char ** code> Pour obtenir un
Char * code> Valeur:
* (Char **) Données CODE>. Ce
Char * code> Pointe de la valeur sur la mémoire allouée par
STRUP () code> et qui doit être libéré:
gratuit (* (* (* **) données); code>. p>
free_string () code> fait, il aurait pu définir certaines variables locales pour contenir les valeurs de pointeur intermédiaires, comme ceci: p>
free_string code> ne libère pas le tampon pointé par le pointeur code> "/ code>. Il ne fait que libérer la mémoire tampon indiquée par la valeur
char * code> que le pointeur code> pointer sur. P> p>
Vous ne montrez pas tout, mais probablement
actuel-> data code> et
actuel code> indique à différents
malloc code> Mémoire ED.