listes chainees et void *

Le problème exposé dans ce sujet a été résolu.

Bonjour,

Alors je vais essayer d'énoncer mon problème le plus clairement possible avec le minimum de code (pour l'instant):

J'ai fait un ensemble de fonctions qui gèrent une liste chaînée. Voici les structures utilisées:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
typedef struct s_list
{
    size_t size;
    struct s_llnode *first;
    struct s_llnode *last;
} t_llist;

typedef struct s_llnode
{
    void *val;
    size_t val_size;
    struct s_llnode *next;
} t_llnode

J'ai une fonction array_to_list qui prend un tableau et renvoie la ll correspondante :

t_llist *array_to_list(void *array, size_t size, size_t val_size);

Chaque valeur des maillons est créé par copie avec memcpy(new->val, val, val_size);

Si je créer un tableau de char ou d'int et que je le passe, je trouve bien un tableau contenant les adresses des chars ou des ints. Maintenant si je créer un tableau de chaînes de caractères, je retrouve n'importe quoi en sortie. En fait en affichant le premier élément ((char *)(list->first->val)) le premier caractère est correct, mais la suite c'est n'importe quoi. Est-ce que vous pouvez m'aider à trouver d'où vient le problème ?

Je pense que ce tu entends par val_size, c'est la taille de tes lignes, donc ligne 27 je pense que ca serait 2 et pas sizeof(char *).

D'ailleurs, normalement l'arithmetique sur void* comme dans array+i c'est pas tres standard en C. C'est dommage parce que tu castes a peu pres tout alors que c'est pas forcement necessaire, mais par contre, pour le coup on devrait plutot ecrire (char*)array+i.

+0 -0

En fait je ne sais pas si j'aurais des (char *), ou bien un autre type de donnée, donc je ne peux pas caster en char * mon tableau dans la fonction. Pour le reste je m'embrouille, en effet en mettant 2 ça marche. Je reverrai ça demain parce que là je suis claqué. Merci en tout cas.

En fait je ne sais pas si j'aurais des (char *), ou bien un autre type de donnée, donc je ne peux pas caster en char * mon tableau dans la fonction.

matthieuj

En fait le char * de (char *)array + i n'a pas de lien avec le type des donnees que tu representes, ici on a choisi char * parce qu'il a une taille de 1 byte, et l'arithmetique des pointeurs nous assure que (char *)array + i c'est effectivement "mathematiquement" i bytes apres array. Par exemple (int *)array + i, c'est sizeof(int)*i bytes apres array. On aurait aussi pu ecrire (unsigned char *)array + i par exemple, ca aurait egalement marche quel que soit le type des donnees que tu stockes.

Re.

Pour l'exemple ça marche avec un tableau de tableau, mais si je fais un tableau de pointeurs de char, ça ne marche plus. char *tab[5] = {"9", "2", "3", "4", "5"};

=> je devrais avoir un tableau de 5 pointeurs sur char.

=> j'envoie le tableau a array_to_list avec val_size = sizeof(char *)

=> il devrait creer une ll de strings ?

Salut,

Le problème t'a été exposé par Lucas-84 et vient de la ligne 52 de ton code.

1
llist_add_last(list, array + i, val_size);

L'expression array + i produit un pointeur sur void qui référence le ième multiplet suivant celui pointé par array. L'expression correcte est array + i * val_size. Par ailleurs, comme l'a également souligné Lucas-84, la norme du langage ne permet pas d'employer un pointeur sur void pour effectuer de l'arithmétique des pointeurs, il t'est donc nécessaire de convertir array vers le type char ou le type unsigned char pour obtenir le comportement souhaité.

+1 -0

[…] L'expression correcte est array + i * val_size. […]

Taurre

Non, c'est bien (char *)array + i et pas (char *)array + i*val_size car i est incrémenté de val_size ligne 53.
Mais je suis naturellement d'accord sur le reste. ;)

Pour résumer, ce que je propose :

  • Changer la ligne 52 en llist_add_last(list, (char *)array + i, val_size); pour toujours. Je prétends que ça marche toujours (cf. le message de Taurre).

  • Deux utilisations possibles (par exemple) :

1
2
3
4
5
6
// Ligne 26
char tab[5][2] = {"9", "2", "3", "4", "5"};
// Ligne 27
t_llist *l1 = array_to_llist(tab, 5, 2);
// Ligne 32
printf("|%s|", (char *)cur->val);
1
2
3
4
5
6
// Ligne 26
char *tab[5] = {"9", "2", "3", "4", "5"};
// Ligne 27
t_llist *l1 = array_to_llist(tab, 5, sizeof(char *));
// Ligne 32
printf("|%s|", *(char **)cur->val);
+0 -0

Bonsoir.

Toujours avec cette structure de liste, j'ai un bug similaire dans plusieurs programme. Quand je met une structure contenant un pointeur, sur char par exemple, et que je veux récupérer le contenu de ce pointeur, je découvre que le pointeur est passé à NULL. J'ai déjà eu du mal à isoler le bug, et je n'arrive pas à trouver sa source. C'est certainement quelque chose de tout bête comme d'habitude.

Voici le code: http://pastebin.com/SwsaHKY5

Et le résultat:

1
2
3
4
str from start=||
id from start=|5|
str from cur=|(null)|
id from cur=|5|

EDIT: l'erreur est en effet toute bête: j'ai mis la taille d'un pointeur sur la structure contenu dans le maillon plutôt que la taille de la structure directement. J'en aurai perdu du temps pour une étoile en trop…

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte