Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

cast de pointeur *, ** différence ?

114 réponses
Avatar
Nico
salut,

j'ai un petit code qui m'étonne... soit une fonction prenant un void*
en paramètre, lors de son appel, si je lui passe un double*, mon
compilateur dit rien... ok.
soit une fonction retournant un void *, lorsque j'assigne un double*
avec le retour de cette fonction, mon compilateur ne dit rien...

ici donc, pas besoin de caster ni le paramètre (en (void*)), ni le
retour de fonction (en (double*))...

maintenant, on prend les même et on recommence, à la différence près
que mon argument n'est plus un void* mais un void**, et mon retour
n'est plus un void* mais aussi un void **. là plus rien ne passe...
lors de l'appel de la fonction je suis obligé de caster mon double** en
void**, et lors du retour, je suis obligé de caster en double**,
pourquoi ?

pour un exemple plus parlant, considérez le code suivant :

void *
vect_new(size_t len, size_t size_type)
{
void *v = malloc(len * size_type);
return v;
}


void
vect_free(void *vect)
{
if(vect) free(vect);
}

/*declaration du vecteur...
pas besoin de faire un cast (double*)*/

double *vect = vect_new(3,sizeof(double));

/*appel sans probleme a la compilation :
pas besoin de faire (void*)vect*/
vect_free(vect);


et maintenant avec des void** :

void **
mat_new(unsigned int nrow, unsigned int ncol, size_t size_type)
{
int i,j;
void **m = malloc(nrow * size_type);
if(m)
{
for(i=0; i<nrow; i++)
{
m[i] = malloc(ncol * size_type);
if(!m[i])
{
for(j=0; j<=i; j++)
free(m[i]);
free(m);
m = NULL;
}
}
}
return m;
}

void
mat_free(void **m,unsigned int nrow)
{
int i;
if(m)
{
for(i=0; i<nrow; i++)
if(m[i])
free(m[i]);
free(m);
}
}

/*declaration de la matrice*/
double **matrice = (double**)mat_new(4,3,sizeof(double));

/*appel sans probleme a la compilation : */
mat_free((void**)matrice,4);

là si je cast pas l'un et l'autre... warning... où se situe la
différence avec le 1er exemple ?

merci de m'éclairer à ce propos.

--
Nico,
http://astrosurf.com/nicoastro
http://nicolas.aunai.free.fr

10 réponses

1 2 3 4 5
Avatar
Nico


Le cast de void** en double** ne va pas aller changer le tableau
intermediaire. Reprenons le coeur de ce que je pensais qu'avait fait
Nico (voir plus bas, il y a un probleme en plus dans ce qu'a fait
Nico):



problème, involontaire bien sûr :-)


void** tab = malloc(dim1 * sizeof(void*));
for (int i = 0; i < dim1; ++i) {
tab[i] = malloc(dim2 * sizeof(double));
}

double** theTab = (double**) tab;

Ce cast va ajuster la valeur de tab comme il faut, mais pas celle de
*tab: or on y a stocke des pointeurs vers void, pas des pointeurs vers
double et rien ne garanti qu'ils ont le meme format ou meme la meme
taille. (En pratique je ne connais pas d'architecture recente ou ca
va poser un probleme.)

En realite, Nico n'utilise pas sizeof(void*) pour la premiere
allocation mais sizeof(double). Il est vraissemblable qu'il ne fait
qu'allouer trop car je ne connais pas d'architecture (recente ou non)
ou sizeof(double) < sizeof(void*). Mais s'il y en avait une...



ok j'ai bien compris le problème, le cast ne converti pas tout le
tableau...., mais je n'ai pas vu dans tous vos posts (ou peut-etre
est-ce moi qui ai du mal) la solution au problème ?
(hormis de faire l'hypothèse que sizeof(double*)==sizeof(void*))

--
Nico,
http://astrosurf.com/nicoastro
http://nicolas.aunai.free.fr

Avatar
Marc Boyer
In article , Nico wrote:
ok j'ai bien compris le problème, le cast ne converti pas tout le
tableau...., mais je n'ai pas vu dans tous vos posts (ou peut-etre
est-ce moi qui ai du mal) la solution au problème ?
(hormis de faire l'hypothèse que sizeof(double*)==sizeof(void*))


Passer un argument size_t size_prt_type en plus à ta fonction ?

Marc Boyer
--
Je ne respecte plus le code de la route à vélo depuis une double fracture
due au fait que j'étais le seul à le respecter.

Avatar
Nico
Marc Boyer a utilisé son clavier pour écrire :


Passer un argument size_t size_prt_type en plus à ta fonction ?



beh... ok pour mat_new je peux faire :

void **
mat_new(unsigned int nrow, unsigned int ncol, size_t size_type, size_t
size_ptr_type)
{
int i,j;
void **m = malloc(nrow * sizeof(size_ptr_type));
if(m)
{
for(i=0; i<nrow; i++)
{
m[i] = malloc(ncol * size_type);
if(!m[i])
{
for(j=0; j<=i; j++)
free(m[i]);
free(m);
m = NULL;
}
}
}
return m;
}

mais que se passe-t-il lors de l'assignation avec l'appel de cette
fonction ?
double **matrice =
(double**)mat_new(4,3,sizeof(double),sizeof(double*));
ça me parait louche je dois pas encore avoir compris l'histoire... je
suis toujours obligé de faire un cast.

et pour les autres fonctions...
comme mat_free
void
mat_free(void **m,unsigned int nrow)
{
int i;
if(m)
{
for(i=0; i<nrow; i++)
if(m[i])
free(m[i]);
free(m);
}
}
je suis également obligé de faire le cast lors de l'appel :
mat_free((void**)matrice,4);
et là je me demande aussi ce qui se passe clairement, car mon tableau a
été alloué à la *))à la bonne taille (sizeof(double*)), mais tout ça
sent la bidouille a plein nez...

--
Nico,
http://astrosurf.com/nicoastro
http://nicolas.aunai.free.fr

Avatar
Jean-Marc Bourguet
Nico writes:

ok j'ai bien compris le problème, le cast ne converti pas tout le
tableau...., mais je n'ai pas vu dans tous vos posts (ou peut-etre
est-ce moi qui ai du mal) la solution au problème ?


Il n'y a que des solutions de complexite au moins egale a ecrite une
fonction par type pour lequel tu veux allouer des matrices
(p.e. passer une fonction qui fait l'assignation

Avec des macros tu peux faciliter un peu l'utilisation. Il doit bien
avoir quelqu'un qui a fait ca. Tu peux toujours chercher dans les
archives de ce groupe et de fr.comp.lang.c++ avec generic.h comme mot
cle pour voir ce que ca donne -- je me souviens qu'on en a cause au
moins une fois.

Je suis pas sur que je me donnerais cette peine, j'aurais plutot
tendance a batir un type matrice qui alloue un tableau unidimentionnel
et assure une indexation adequate.

A+

--
Jean-Marc
FAQ de fclc: http://www.isty-info.uvsq.fr/~rumeau/fclc
Site de usenet-fr: http://www.usenet-fr.news.eu.org

Avatar
Jean-Marc Bourguet
Marc Boyer writes:

In article , Nico wrote:
ok j'ai bien compris le problème, le cast ne converti pas tout le
tableau...., mais je n'ai pas vu dans tous vos posts (ou peut-etre
est-ce moi qui ai du mal) la solution au problème ?
(hormis de faire l'hypothèse que sizeof(double*)==sizeof(void*))


Passer un argument size_t size_prt_type en plus à ta fonction ?


Et? Le probleme est que quand il faut
tab[i] = malloc(...);
il faudrait que tab[i] soit un double* et donc et l'indexation de tab
doit tenir compte de la taille (ca l'argument peut permettre de le
faire) mais aussi le pointeur doit etre converti au bon format (et ca
connaitre la taille n'aide en rien). Il peut passer un pointeur de
fonction et ecrire a la place
assign(tab, i, malloc(...));
mais a quoi bon?

A+

--
Jean-Marc
FAQ de fclc: http://www.isty-info.uvsq.fr/~rumeau/fclc
Site de usenet-fr: http://www.usenet-fr.news.eu.org


Avatar
Charlie Gordon
"Richard Delorme" wrote in message
news:418f47fd$0$15754$

Mais peux-tu citer une architecture où ce n'est pas vrai ? (NULL pas all
bits 0)



http://www.eskimo.com/~scs/C-faq/q5.17.html


Alors, une de moins de 20 ans ? Tout ça c'est de la paléo-informatique.
Je n'en appelais pas à ta culture générale, mais à ton expérience personnelle.

calloc est plus sûr que malloc parce que la mémoire est initialisée à 0, ce
qui


rend le comportement des programmes plus reproductible dans le cas ou le
programmeur "oublie" d'initialiser tout ou partie de la zone allouée. Cela
permet même de ne pas avoir à initialiser les champs qui doivent êtres nuls.


Non, cela n'initialise pas les champs, mais met tous les bits à 0. En
particulier pour les flottants (float, double, ...) et les pointeurs, il
n'y a aucune garantie que cela corresponde à des valeurs nulles.


Les initialiser à all-bit-zero, c'est toujours mieux que de les laisser à
garbage.
Quant aux flottants, s'ils sont IEEE, 0 = all-bits-zero. Mais bien sûr on peut
trouver des archi exotiques. Je ne pensais pas aux flottants dans mon
affirmation, juste aux entiers et tableaux de caractères.

Cela permet aussi que les tableaux de char, qui sont souvent valués par un
strcpy ne contiennent pas de résidus qui pourraient malencontreusement se
propager sur disque, voire ailleurs, lors de stockages bruts de structures,
une


pratique peu recommandable, non portable et peu flexible, mais
malheureusement


assez courante.


C'est marrant que tu critiques strncpy alors qu'il a ce comportement...


Très fort ! tu fais partie de l'infime minorité qui sait cela. Ce n'est pas cet
aspect là qui est le plus criticable ;-)

void *reallocp(void **pp, size_t size, size_t count, size_t last_count) {
void *p = realloc(*pp, size * count);
if (p) {
if (count > last_count)
memset((char *)p + size * count, 0, size * (count -
last_count));



memset() souffre évidemment du même problème que calloc().


Vrai, mais ce n'est rien en regard des problème de realloc en général ! En
particulier pour des structures multiréférencées.

Je préfère une méthode imparfaite qui évite des problèmes qu'un champ de mines
tout juste mentionné sur une doc.

Chqrlie.


Avatar
Marc Boyer
Jean-Marc Bourguet wrote:
Marc Boyer writes:

In article , Nico wrote:
ok j'ai bien compris le problème, le cast ne converti pas tout le
tableau...., mais je n'ai pas vu dans tous vos posts (ou peut-etre
est-ce moi qui ai du mal) la solution au problème ?
(hormis de faire l'hypothèse que sizeof(double*)==sizeof(void*))


Passer un argument size_t size_prt_type en plus à ta fonction ?


Et? Le probleme est que quand il faut
tab[i] = malloc(...);
il faudrait que tab[i] soit un double* et donc et l'indexation de tab
doit tenir compte de la taille (ca l'argument peut permettre de le
faire) mais aussi le pointeur doit etre converti au bon format (et ca
connaitre la taille n'aide en rien). Il peut passer un pointeur de
fonction et ecrire a la place
assign(tab, i, malloc(...));
mais a quoi bon?


OK, j'étais allé un peu vite.
On peut éventuellement s'en sortir à grand coup de memcpy
en lieu et place des affectations, mais tout devient extrèmement
compliqué.
Un tableau à une dimension, ça doit en effet être bien mieux.

Marc Boyer
--
Je ne respecte plus le code de la route à vélo depuis une double fracture
due au fait que j'étais le seul à le respecter.



Avatar
Marc Boyer
Jean-Marc Bourguet wrote:
Nico writes:
ok j'ai bien compris le problème, le cast ne converti pas tout le
tableau...., mais je n'ai pas vu dans tous vos posts (ou peut-etre
est-ce moi qui ai du mal) la solution au problème ?


Il n'y a que des solutions de complexite au moins egale a ecrite une
fonction par type pour lequel tu veux allouer des matrices
(p.e. passer une fonction qui fait l'assignation

Avec des macros tu peux faciliter un peu l'utilisation. Il doit bien
avoir quelqu'un qui a fait ca.


Oui, moi ;-)
<pub>
http://www.enseeiht.fr/~boyer/Tools.html

La BPL est une tentative de traduction de la STL en C à grand
coups de macros comme au temps de generic.h

Il y a un vecteur, et on peut faire un vecteur de vecteur.
Tous les retours d'utilisateurs sont bienvenus.
</pub>

Je suis pas sur que je me donnerais cette peine, j'aurais plutot
tendance a batir un type matrice qui alloue un tableau unidimentionnel
et assure une indexation adequate.


Voui.

Marc Boyer
--
Je ne respecte plus le code de la route à vélo depuis une double fracture
due au fait que j'étais le seul à le respecter.


Avatar
Marc Boyer
In article , Nico wrote:
Marc Boyer a utilisé son clavier pour écrire :
Passer un argument size_t size_prt_type en plus à ta fonction ?


beh... ok pour mat_new je peux faire :

void **
mat_new(unsigned int nrow, unsigned int ncol, size_t size_type, size_t
size_ptr_type)
{
int i,j;
void **m = malloc(nrow * sizeof(size_ptr_type));
if(m)
{
for(i=0; i<nrow; i++)
{
m[i] = malloc(ncol * size_type);


Oui, en effet, là, ça devient très chaud.

if(!m[i])
{
for(j=0; j<=i; j++)
free(m[i]);
free(m);
m = NULL;
}
}
}
return m;
}

mais que se passe-t-il lors de l'assignation avec l'appel de cette
fonction ?
double **matrice =
(double**)mat_new(4,3,sizeof(double),sizeof(double*));
ça me parait louche je dois pas encore avoir compris l'histoire... je
suis toujours obligé de faire un cast.


Le cast coté utilisateur, c'est pas le pire.

Marc Boyer
--
Je ne respecte plus le code de la route à vélo depuis une double fracture
due au fait que j'étais le seul à le respecter.


Avatar
Yves ROMAN

Marc Boyer a utilisé son clavier pour écrire :

Passer un argument size_t size_prt_type en plus à ta fonction ?


beh... ok pour mat_new je peux faire :

void **
mat_new(unsigned int nrow, unsigned int ncol, size_t size_type, size_t
size_ptr_type)
{
int i,j;
void **m = malloc(nrow * sizeof(size_ptr_type));


Tu voulais surement écrire :
void **m = malloc(nrow * size_ptr_type);

if(m)
{
for(i=0; i<nrow; i++)
{
m[i] = malloc(ncol * size_type);


Ici, m[i] va se déplacer dans la zone pointé par m de sizeof(*m) == sizeof(void
*)
Alors que tu as alloué pour chaque élément que size_ptr_type
Ca ne marchera que si, une fois encore, sizeof(void *) == size_ptr_type
Il faudrait donc que m soit du bon type.
D'ou l'idée de créer cette fonction avec une macro() utilisée pour produire le
code de la fonction correspondant à chaque type.

Question:
Quelque soit le type de donnée T, a-t-on
sizeof(void *) >= sizeof(T *)
ou bien
sizeof(void *) <= sizeof(T *)

if(!m[i])
{
for(j=0; j<=i; j++)
free(m[i]);
free(m);
m = NULL;
}
}
}
return m;
}




1 2 3 4 5