Dans le code ci-dessous, j'utilise des tableaux de pointeurs sur des
chaines de char (char **). Afin de permettre à la fonction foo() de
travailler sur le contenue, je passe une référence à ce tableau de
pointeur (char ***). foo() semble faire correctement sont travail, du
moins tant qu'on est dans la fonction (gdb me confirme que les chaines
ont bien été copiée). Or je ne récupère pas le résultat une fois sortie
de foo().
Je ne sais pas si j'ai été bien clair, dans le cas contraire, je
tenterai d'expliquer différemment mon problème.
C'est vrai que ce n'est pas le plus simple pour l'esprit, mais passons les arguments qui m'ont poussé à l'utiliser, disons simplement que c'est un exercice qui, normalement, devrait fonctionner.
Ceci fonctionne :
static char **foo (char **RcptList, char **email)
Mais il y a des précautions à prendre quand on utilise realloc() :
http://mapage.noos.fr/emdel/notes.htm#realloc
Je suis entièrement d'accord la dessus, ainsi qu'avec les remarques de M.Boyer sur les défauts de ce code. Il doit y en avoir d'autres, mais je souhaite tout d'abord comprendre le non fonctionnement de ce que je propose.
Comme dit par Antoine: tu t'es emméllé les pinceaux dans ton ***. Il y a un niveau d'indirection pour panipuler des char*, un autre pour le tableau, et un troisième pour le mode in/out (ie, modif de la valeur). Et tu penses d'une manière, et tu utilise d'une autre.
Maintenant retournons à la demande initiale, soit un exercice sur char ***. J'ai beau retourner le pb dans tous les sens, faire des petits dessins définissant les zone mémoire et empilement de pointeurs, je ne comprend pas pourquoi ca ne fonctionne pas.
Parce que *RcpList[i] est interprété comme *(RcpList[i]) alors que tu dois faire tes dessins avec (*RcpList)[i].
Marc Boyer -- Si tu peux supporter d'entendre tes paroles Travesties par des gueux pour exciter des sots IF -- Rudyard Kipling (Trad. André Maurois)
On 2008-09-02, Vincent <vin-vin-cefr@yahoo.fr> wrote:
3 *, ça me donne mal à la tête.
C'est vrai que ce n'est pas le plus simple pour l'esprit, mais passons
les arguments qui m'ont poussé à l'utiliser, disons simplement que c'est
un exercice qui, normalement, devrait fonctionner.
Ceci fonctionne :
static char **foo (char **RcptList, char **email)
Mais il y a des précautions à prendre quand on utilise realloc() :
http://mapage.noos.fr/emdel/notes.htm#realloc
Je suis entièrement d'accord la dessus, ainsi qu'avec les remarques de
M.Boyer sur les défauts de ce code. Il doit y en avoir d'autres, mais je
souhaite tout d'abord comprendre le non fonctionnement de ce que je
propose.
Comme dit par Antoine: tu t'es emméllé les pinceaux dans ton ***.
Il y a un niveau d'indirection pour panipuler des char*, un autre
pour le tableau, et un troisième pour le mode in/out (ie, modif
de la valeur). Et tu penses d'une manière, et tu utilise d'une autre.
Maintenant retournons à la demande initiale, soit un exercice sur char
***. J'ai beau retourner le pb dans tous les sens, faire des petits
dessins définissant les zone mémoire et empilement de pointeurs, je ne
comprend pas pourquoi ca ne fonctionne pas.
Parce que *RcpList[i] est interprété comme *(RcpList[i]) alors
que tu dois faire tes dessins avec (*RcpList)[i].
Marc Boyer
--
Si tu peux supporter d'entendre tes paroles
Travesties par des gueux pour exciter des sots
IF -- Rudyard Kipling (Trad. André Maurois)
C'est vrai que ce n'est pas le plus simple pour l'esprit, mais passons les arguments qui m'ont poussé à l'utiliser, disons simplement que c'est un exercice qui, normalement, devrait fonctionner.
Ceci fonctionne :
static char **foo (char **RcptList, char **email)
Mais il y a des précautions à prendre quand on utilise realloc() :
http://mapage.noos.fr/emdel/notes.htm#realloc
Je suis entièrement d'accord la dessus, ainsi qu'avec les remarques de M.Boyer sur les défauts de ce code. Il doit y en avoir d'autres, mais je souhaite tout d'abord comprendre le non fonctionnement de ce que je propose.
Comme dit par Antoine: tu t'es emméllé les pinceaux dans ton ***. Il y a un niveau d'indirection pour panipuler des char*, un autre pour le tableau, et un troisième pour le mode in/out (ie, modif de la valeur). Et tu penses d'une manière, et tu utilise d'une autre.
Maintenant retournons à la demande initiale, soit un exercice sur char ***. J'ai beau retourner le pb dans tous les sens, faire des petits dessins définissant les zone mémoire et empilement de pointeurs, je ne comprend pas pourquoi ca ne fonctionne pas.
Parce que *RcpList[i] est interprété comme *(RcpList[i]) alors que tu dois faire tes dessins avec (*RcpList)[i].
Marc Boyer -- Si tu peux supporter d'entendre tes paroles Travesties par des gueux pour exciter des sots IF -- Rudyard Kipling (Trad. André Maurois)
Vincent
> Non. D'abord cela s'écrit char*[]. Tableau ([]) de chaînes (char*), écrit à l'envers comme il se doit. Ensuite, ce ne sont pas des pointeurs vers des chaînes, ce sont des chaînes tout court.
[...]
Et si on se ramène à l'écriture ci-dessus, on obtient plutôt char *(*)[] : j'ai rajouté l'indirection au bon endroit, c'est-à-dire au milieu, et cela impose donc de rajouter une paire de parenthèse.
Cette digression semble peut-être inutile et superfétatoire, mais comme par la suite ton code semble vouloir utiliser exactement mon formalisme...
D'accord, mais pas inutile pour moi en tout cas (manifestement).
foo() semble faire correctement sont travail, du moins tant qu'on est dans la fonction
Donc mon petit doigt me dit que tes contrôles et autres assertions (qui ont été supprimés du code que tu as posté certainement dans la louable intention d'alléger le message) ne font complètement leur travail
(gdb me confirme que les chaines ont bien été copiée).
Mais il ne semble pas te dire où...
Je n'ai pas la sortie de gdb pour le montrer, mais à moins que j'ai fait une erreur, les adresses pointés étaient les même dans l'un et l'autre fonction. Le contenu pointé n'étant pas le même, c'est cela qui m'a poussé à écrire. Si nécessaire, je rejouerai le debogage pour fournir les sorties.
Et nous y voilà. Si on se reporte au prototype, il saute aux yeux que l'on ne fait pas l'indexation au bon endroit, et qu'il manque une paire de parenthèses.
[...]
Mais non : il faut corriger de la même manière toutes les occurences de RcptList.
J'ai effectué tous les changements que je pense nécessaires, mais butte sur le REALLOC() : *RcptList = REALLOC(*RcptList, (i+1)*sizeof(char *));
Je ne vois pas comment modifier l'écriture de *RcptList.
Pour continuer avec les commentaires de code en passant
Tout a fait inutile dans ce contexte je vous l'accorde volontier
strcpy(*RcptList[i], email[j]);
man strlcpy
sprintf(to[0],""); sprintf(to[1],"");
Mauvaise habitude, le jour où tu le feras avec un argument HTTP ou une adresse mail encodée avec un % au milieu, tu t'en mordras les doigts. strlcpy() c'est mieux.
Malheureusement j'en suis plein de mauvaises habitudes. Je vais tenter d'en corriger certaines à l'issue de ce thread.
Merci de votre aide et commentaires.
Vincent
> Non. D'abord cela s'écrit char*[]. Tableau ([]) de chaînes (char*), écrit à
l'envers comme il se doit. Ensuite, ce ne sont pas des pointeurs vers des
chaînes, ce sont des chaînes tout court.
[...]
Et si on se ramène à l'écriture ci-dessus, on obtient plutôt char *(*)[] :
j'ai rajouté l'indirection au bon endroit, c'est-à-dire au milieu, et cela
impose donc de rajouter une paire de parenthèse.
Cette digression semble peut-être inutile et superfétatoire, mais comme par
la suite ton code semble vouloir utiliser exactement mon formalisme...
D'accord, mais pas inutile pour moi en tout cas (manifestement).
foo() semble faire correctement sont travail, du
moins tant qu'on est dans la fonction
Donc mon petit doigt me dit que tes contrôles et autres assertions (qui ont
été supprimés du code que tu as posté certainement dans la louable intention
d'alléger le message) ne font complètement leur travail
(gdb me confirme que les chaines ont bien été copiée).
Mais il ne semble pas te dire où...
Je n'ai pas la sortie de gdb pour le montrer, mais à moins que j'ai fait
une erreur, les adresses pointés étaient les même dans l'un et l'autre
fonction. Le contenu pointé n'étant pas le même, c'est cela qui m'a
poussé à écrire. Si nécessaire, je rejouerai le debogage pour fournir
les sorties.
Et nous y voilà.
Si on se reporte au prototype, il saute aux yeux que l'on ne fait pas
l'indexation au bon endroit, et qu'il manque une paire de parenthèses.
[...]
Mais non : il faut corriger
de la même manière toutes les occurences de RcptList.
J'ai effectué tous les changements que je pense nécessaires, mais butte
sur le REALLOC() :
*RcptList = REALLOC(*RcptList, (i+1)*sizeof(char *));
Je ne vois pas comment modifier l'écriture de *RcptList.
Pour continuer avec les commentaires de code en passant
Mauvaise habitude, le jour où tu le feras avec un argument HTTP ou une
adresse mail encodée avec un % au milieu, tu t'en mordras les doigts.
strlcpy() c'est mieux.
Malheureusement j'en suis plein de mauvaises habitudes. Je vais tenter
d'en corriger certaines à l'issue de ce thread.
> Non. D'abord cela s'écrit char*[]. Tableau ([]) de chaînes (char*), écrit à l'envers comme il se doit. Ensuite, ce ne sont pas des pointeurs vers des chaînes, ce sont des chaînes tout court.
[...]
Et si on se ramène à l'écriture ci-dessus, on obtient plutôt char *(*)[] : j'ai rajouté l'indirection au bon endroit, c'est-à-dire au milieu, et cela impose donc de rajouter une paire de parenthèse.
Cette digression semble peut-être inutile et superfétatoire, mais comme par la suite ton code semble vouloir utiliser exactement mon formalisme...
D'accord, mais pas inutile pour moi en tout cas (manifestement).
foo() semble faire correctement sont travail, du moins tant qu'on est dans la fonction
Donc mon petit doigt me dit que tes contrôles et autres assertions (qui ont été supprimés du code que tu as posté certainement dans la louable intention d'alléger le message) ne font complètement leur travail
(gdb me confirme que les chaines ont bien été copiée).
Mais il ne semble pas te dire où...
Je n'ai pas la sortie de gdb pour le montrer, mais à moins que j'ai fait une erreur, les adresses pointés étaient les même dans l'un et l'autre fonction. Le contenu pointé n'étant pas le même, c'est cela qui m'a poussé à écrire. Si nécessaire, je rejouerai le debogage pour fournir les sorties.
Et nous y voilà. Si on se reporte au prototype, il saute aux yeux que l'on ne fait pas l'indexation au bon endroit, et qu'il manque une paire de parenthèses.
[...]
Mais non : il faut corriger de la même manière toutes les occurences de RcptList.
J'ai effectué tous les changements que je pense nécessaires, mais butte sur le REALLOC() : *RcptList = REALLOC(*RcptList, (i+1)*sizeof(char *));
Je ne vois pas comment modifier l'écriture de *RcptList.
Pour continuer avec les commentaires de code en passant
Tout a fait inutile dans ce contexte je vous l'accorde volontier
strcpy(*RcptList[i], email[j]);
man strlcpy
sprintf(to[0],""); sprintf(to[1],"");
Mauvaise habitude, le jour où tu le feras avec un argument HTTP ou une adresse mail encodée avec un % au milieu, tu t'en mordras les doigts. strlcpy() c'est mieux.
Malheureusement j'en suis plein de mauvaises habitudes. Je vais tenter d'en corriger certaines à l'issue de ce thread.
Merci de votre aide et commentaires.
Vincent
Antoine Leca
En news:48c014a8$0$26984$, Vincent va escriure:
J'ai effectué tous les changements que je pense nécessaires, mais butte sur le REALLOC() : *RcptList = REALLOC(*RcptList, (i+1)*sizeof(char *));
Je ne vois pas comment modifier l'écriture de *RcptList.
Que veux-tu modifier ? *RcptList désigne le tableau, tu le redimensionne et tu mets à jour l'objet, il n'y a pas de raison ÀMHA pour écrire autre chose.
Cela ne marche toujours pas avec le REALLOC tel qu'écrit ci-dessus ? Bien évidemment le flag HEAP_GENERATE_EXCEPTIONS est posé sur le tas obtenu par GetProcessHeap (ou bien tu teste la valeur de retour d'une manière ou d'une autre et tu te déroutes en cas d'erreur), n'est-ce-pas ?
Essaye avec moins d'optimisation de la part du compilateur (ou change de version), ce ne serait pas la première fois qu'on verrait un bogue de compilateur dans ce genre de code (le compilo range la valeur pointée par RcptList dans une variable qu'il ne met pas à jour avec le retour de realloc(), et si le système a déplacé le tableau cela fait boum).
Antoine
En news:48c014a8$0$26984$426a74cc@news.free.fr, Vincent va escriure:
J'ai effectué tous les changements que je pense nécessaires, mais
butte sur le REALLOC() :
*RcptList = REALLOC(*RcptList, (i+1)*sizeof(char *));
Je ne vois pas comment modifier l'écriture de *RcptList.
Que veux-tu modifier ?
*RcptList désigne le tableau, tu le redimensionne et tu mets à jour l'objet,
il n'y a pas de raison ÀMHA pour écrire autre chose.
Cela ne marche toujours pas avec le REALLOC tel qu'écrit ci-dessus ?
Bien évidemment le flag HEAP_GENERATE_EXCEPTIONS est posé sur le tas obtenu
par GetProcessHeap (ou bien tu teste la valeur de retour d'une manière ou
d'une autre et tu te déroutes en cas d'erreur), n'est-ce-pas ?
Essaye avec moins d'optimisation de la part du compilateur (ou change de
version), ce ne serait pas la première fois qu'on verrait un bogue de
compilateur dans ce genre de code (le compilo range la valeur pointée par
RcptList dans une variable qu'il ne met pas à jour avec le retour de
realloc(), et si le système a déplacé le tableau cela fait boum).
J'ai effectué tous les changements que je pense nécessaires, mais butte sur le REALLOC() : *RcptList = REALLOC(*RcptList, (i+1)*sizeof(char *));
Je ne vois pas comment modifier l'écriture de *RcptList.
Que veux-tu modifier ? *RcptList désigne le tableau, tu le redimensionne et tu mets à jour l'objet, il n'y a pas de raison ÀMHA pour écrire autre chose.
Cela ne marche toujours pas avec le REALLOC tel qu'écrit ci-dessus ? Bien évidemment le flag HEAP_GENERATE_EXCEPTIONS est posé sur le tas obtenu par GetProcessHeap (ou bien tu teste la valeur de retour d'une manière ou d'une autre et tu te déroutes en cas d'erreur), n'est-ce-pas ?
Essaye avec moins d'optimisation de la part du compilateur (ou change de version), ce ne serait pas la première fois qu'on verrait un bogue de compilateur dans ce genre de code (le compilo range la valeur pointée par RcptList dans une variable qu'il ne met pas à jour avec le retour de realloc(), et si le système a déplacé le tableau cela fait boum).
Antoine
Vincent
Antoine Leca wrote:
En news:48c014a8$0$26984$, Vincent va escriure:
J'ai effectué tous les changements que je pense nécessaires, mais butte sur le REALLOC() : *RcptList = REALLOC(*RcptList, (i+1)*sizeof(char *));
Je ne vois pas comment modifier l'écriture de *RcptList.
Que veux-tu modifier ?
En fait je fait référence à l'erreur de gcc (mingw32) qui me dit : emc.c:29: error: invalid use of array with unspecified bounds
sur la ligne *RcptList = REALLOC(*RcptList, (i+1)*sizeof(char *));
J'ai sans doute fait une erreur quelque part. Voici la fonction. Notez que IsPresentInList() est une coquille vide pour l'instant et peut tout a fait être omise.
static void foo (char *(*RcptList)[], char *email[]) { int i = 0, j = 0; if (!email || !RcptList || !(*RcptList)) return;
En news:48c014a8$0$26984$426a74cc@news.free.fr, Vincent va escriure:
J'ai effectué tous les changements que je pense nécessaires, mais
butte sur le REALLOC() :
*RcptList = REALLOC(*RcptList, (i+1)*sizeof(char *));
Je ne vois pas comment modifier l'écriture de *RcptList.
Que veux-tu modifier ?
En fait je fait référence à l'erreur de gcc (mingw32) qui me dit :
emc.c:29: error: invalid use of array with unspecified bounds
sur la ligne *RcptList = REALLOC(*RcptList, (i+1)*sizeof(char *));
J'ai sans doute fait une erreur quelque part. Voici la fonction. Notez
que IsPresentInList() est une coquille vide pour l'instant et peut tout
a fait être omise.
static void foo (char *(*RcptList)[], char *email[])
{
int i = 0, j = 0;
if (!email || !RcptList || !(*RcptList))
return;
J'ai effectué tous les changements que je pense nécessaires, mais butte sur le REALLOC() : *RcptList = REALLOC(*RcptList, (i+1)*sizeof(char *));
Je ne vois pas comment modifier l'écriture de *RcptList.
Que veux-tu modifier ?
En fait je fait référence à l'erreur de gcc (mingw32) qui me dit : emc.c:29: error: invalid use of array with unspecified bounds
sur la ligne *RcptList = REALLOC(*RcptList, (i+1)*sizeof(char *));
J'ai sans doute fait une erreur quelque part. Voici la fonction. Notez que IsPresentInList() est une coquille vide pour l'instant et peut tout a fait être omise.
static void foo (char *(*RcptList)[], char *email[]) { int i = 0, j = 0; if (!email || !RcptList || !(*RcptList)) return;
J'ai effectué tous les changements que je pense nécessaires, mais butte sur le REALLOC() : *RcptList = REALLOC(*RcptList, (i+1)*sizeof(char *));
Je ne vois pas comment modifier l'écriture de *RcptList.
Que veux-tu modifier ?
En fait je fait référence à l'erreur de gcc (mingw32) qui me dit : emc.c:29: error: invalid use of array with unspecified bounds
sur la ligne *RcptList = REALLOC(*RcptList, (i+1)*sizeof(char *));
J'ai sans doute fait une erreur quelque part. Voici la fonction. Notez que IsPresentInList() est une coquille vide pour l'instant et peut tout a fait être omise.
static void foo (char *(*RcptList)[], char *email[]) { int i = 0, j = 0; if (!email || !RcptList || !(*RcptList)) return;
MALLOC et REALLOC ont quelles définitions ? En majuscule ce sont des macros (a priori).
(sinon le code va planter sur un échec d'allocation ou de réallocation : pas de traitement des cas d'erreur).
-- Le travail n'est pas une bonne chose. Si ça l'était, les riches l'auraient accaparé
Vincent <vin-vin-cefr@yahoo.fr> écrivait :
Antoine Leca wrote:
En news:48c014a8$0$26984$426a74cc@news.free.fr, Vincent va escriure:
J'ai effectué tous les changements que je pense nécessaires, mais
butte sur le REALLOC() :
*RcptList = REALLOC(*RcptList, (i+1)*sizeof(char *));
Je ne vois pas comment modifier l'écriture de *RcptList.
Que veux-tu modifier ?
En fait je fait référence à l'erreur de gcc (mingw32) qui me dit :
emc.c:29: error: invalid use of array with unspecified bounds
sur la ligne *RcptList = REALLOC(*RcptList, (i+1)*sizeof(char *));
J'ai sans doute fait une erreur quelque part. Voici la fonction. Notez
que IsPresentInList() est une coquille vide pour l'instant et peut
tout a fait être omise.
static void foo (char *(*RcptList)[], char *email[])
{
int i = 0, j = 0;
if (!email || !RcptList || !(*RcptList))
return;
J'ai effectué tous les changements que je pense nécessaires, mais butte sur le REALLOC() : *RcptList = REALLOC(*RcptList, (i+1)*sizeof(char *));
Je ne vois pas comment modifier l'écriture de *RcptList.
Que veux-tu modifier ?
En fait je fait référence à l'erreur de gcc (mingw32) qui me dit : emc.c:29: error: invalid use of array with unspecified bounds
sur la ligne *RcptList = REALLOC(*RcptList, (i+1)*sizeof(char *));
J'ai sans doute fait une erreur quelque part. Voici la fonction. Notez que IsPresentInList() est une coquille vide pour l'instant et peut tout a fait être omise.
static void foo (char *(*RcptList)[], char *email[]) { int i = 0, j = 0; if (!email || !RcptList || !(*RcptList)) return;
MALLOC et REALLOC ont quelles définitions ? En majuscule ce sont des macros (a priori).
(sinon le code va planter sur un échec d'allocation ou de réallocation : pas de traitement des cas d'erreur).
-- Le travail n'est pas une bonne chose. Si ça l'était, les riches l'auraient accaparé
Antoine Leca
En news:48c817d6$0$591$, Vincent va escriure:
En fait je fait référence à l'erreur de gcc (mingw32) qui me dit : emc.c:29: error: invalid use of array with unspecified bounds
sur la ligne *RcptList = REALLOC(*RcptList, (i+1)*sizeof(char *));
Groumpf :-(
Pour mémoire, j'écrivis dans news:g9j725$2pe$: : En news:48b867f2$0$16334$, Vincent va escriure: :> Dans le code ci-dessous, j'utilise des tableaux de pointeurs sur des :> chaines de char : : D'accord. : :> (char **). : : Non. D'abord cela s'écrit char*[]. Tableau ([]) de chaînes (char*), : écrit à l'envers comme il se doit. Ensuite, ce ne sont pas des : pointeurs vers des chaînes, ce sont des chaînes tout court. Pas : besoin de faire plus compliqué que cela ne l'est au départ. : : :> Afin de permettre à la fonction foo() de :> travailler sur le contenue, je passe une référence à ce tableau de :> pointeur (char ***). : : Et si on se ramène à l'écriture ci-dessus, on obtient plutôt char : *(*)[] : j'ai rajouté l'indirection au bon endroit, c'est-à-dire au : milieu, et cela impose donc de rajouter une paire de parenthèse. [...] :> static void foo (char ***RcptList, char **email) : : static void foo (char *(*RcptList)[], char *entetes[])
En fait, cette explication très bien au plan didactique. Sauf sur un point. Ce n'est pas du C correct. Groumpf. En effet, en C seul le _dernier_ qualificateur de tableau est transformé en pointeur, ce n'est pas le cas pour les autres qualificateurs de tableau.
Ainsi, dans
int machin(int tableau[N][M][P])
on définit un paramètre tableau qui est en fait un pointeur vers... int[M][P], pointeur vers une matrice à deux dimensions, et cette chose n'est *pas* un simple pointeur ; entre autre, il est nécessaire de spécifier les dimensions de la matrice (c'est tout le problème du passage des tableaux à plusieurs dimensions). Notons bien qu'ici, le compilateur néglige l'indication de la taille N qui indique la taille du « cube », et il est possible et même courant d'écrire
on y lit que entetes est un pointeur vers des chaînes (rangées dans un tableau, mais c'est juste la syntaxe qui nous renseigne, pour le compilateur c'est la même chose que char**, un pointeur vers pointeur vers un caractère), mais que par contre RcptList est un pointeur vers un tableau _incomplet_ de chaînes. BUG.
Évidemment, lorsque tu demandes à redimensionner le tableau incomplet, le compilateur proteste, on est pas en Basic Microsoft ici.
Donc en fait, il n'y a pas de moyen d'échapper à l'horrible ***. De fait, si l'on regarde le cas des chaînes, en fait ce sont bien des char[] mais dans la pratique toutes les fonctions les manipulent comme des char* : c'est pour la même raison.
En conséquence, mon écriture du prototype était très bien pour [faire] comprendre le problème, mais pas correcte pour le compilateur. Snif+Groumpf.
J'ai sans doute fait une erreur quelque part.
Non non. L'erreur est de ma part. L'exemple était trop parlant, et j'ai trop fait de Pascal dans ma vie. D'ailleurs en C, comme je l'écrivais, je n'aurais pas utilisé des char*[] mais des (vraies) listes chaînées ; et cette discussion est une preuve supplémentaire de la justesse de ce point de vue.
Antoine
En news:48c817d6$0$591$426a74cc@news.free.fr, Vincent va escriure:
En fait je fait référence à l'erreur de gcc (mingw32) qui me dit :
emc.c:29: error: invalid use of array with unspecified bounds
sur la ligne *RcptList = REALLOC(*RcptList, (i+1)*sizeof(char *));
Groumpf :-(
Pour mémoire, j'écrivis dans news:g9j725$2pe$1@shakotay.alphanet.ch:
: En news:48b867f2$0$16334$426a74cc@news.free.fr, Vincent va escriure:
:> Dans le code ci-dessous, j'utilise des tableaux de pointeurs sur des
:> chaines de char
:
: D'accord.
:
:> (char **).
:
: Non. D'abord cela s'écrit char*[]. Tableau ([]) de chaînes (char*),
: écrit à l'envers comme il se doit. Ensuite, ce ne sont pas des
: pointeurs vers des chaînes, ce sont des chaînes tout court. Pas
: besoin de faire plus compliqué que cela ne l'est au départ.
:
:
:> Afin de permettre à la fonction foo() de
:> travailler sur le contenue, je passe une référence à ce tableau de
:> pointeur (char ***).
:
: Et si on se ramène à l'écriture ci-dessus, on obtient plutôt char
: *(*)[] : j'ai rajouté l'indirection au bon endroit, c'est-à-dire au
: milieu, et cela impose donc de rajouter une paire de parenthèse.
[...]
:> static void foo (char ***RcptList, char **email)
:
: static void foo (char *(*RcptList)[], char *entetes[])
En fait, cette explication très bien au plan didactique.
Sauf sur un point.
Ce n'est pas du C correct. Groumpf.
En effet, en C seul le _dernier_ qualificateur de tableau est transformé en
pointeur, ce n'est pas le cas pour les autres qualificateurs de tableau.
Ainsi, dans
int machin(int tableau[N][M][P])
on définit un paramètre tableau qui est en fait un pointeur vers...
int[M][P], pointeur vers une matrice à deux dimensions, et cette chose n'est
*pas* un simple pointeur ; entre autre, il est nécessaire de spécifier les
dimensions de la matrice (c'est tout le problème du passage des tableaux à
plusieurs dimensions).
Notons bien qu'ici, le compilateur néglige l'indication de la taille N qui
indique la taille du « cube », et il est possible et même courant d'écrire
on y lit que entetes est un pointeur vers des chaînes (rangées dans un
tableau, mais c'est juste la syntaxe qui nous renseigne, pour le compilateur
c'est la même chose que char**, un pointeur vers pointeur vers un
caractère), mais que par contre RcptList est un pointeur vers un tableau
_incomplet_ de chaînes. BUG.
Évidemment, lorsque tu demandes à redimensionner le tableau incomplet, le
compilateur proteste, on est pas en Basic Microsoft ici.
Donc en fait, il n'y a pas de moyen d'échapper à l'horrible ***.
De fait, si l'on regarde le cas des chaînes, en fait ce sont bien des char[]
mais dans la pratique toutes les fonctions les manipulent comme des char* :
c'est pour la même raison.
En conséquence, mon écriture du prototype était très bien pour [faire]
comprendre le problème, mais pas correcte pour le compilateur. Snif+Groumpf.
J'ai sans doute fait une erreur quelque part.
Non non. L'erreur est de ma part. L'exemple était trop parlant, et j'ai trop
fait de Pascal dans ma vie.
D'ailleurs en C, comme je l'écrivais, je n'aurais pas utilisé des char*[]
mais des (vraies) listes chaînées ; et cette discussion est une preuve
supplémentaire de la justesse de ce point de vue.
En fait je fait référence à l'erreur de gcc (mingw32) qui me dit : emc.c:29: error: invalid use of array with unspecified bounds
sur la ligne *RcptList = REALLOC(*RcptList, (i+1)*sizeof(char *));
Groumpf :-(
Pour mémoire, j'écrivis dans news:g9j725$2pe$: : En news:48b867f2$0$16334$, Vincent va escriure: :> Dans le code ci-dessous, j'utilise des tableaux de pointeurs sur des :> chaines de char : : D'accord. : :> (char **). : : Non. D'abord cela s'écrit char*[]. Tableau ([]) de chaînes (char*), : écrit à l'envers comme il se doit. Ensuite, ce ne sont pas des : pointeurs vers des chaînes, ce sont des chaînes tout court. Pas : besoin de faire plus compliqué que cela ne l'est au départ. : : :> Afin de permettre à la fonction foo() de :> travailler sur le contenue, je passe une référence à ce tableau de :> pointeur (char ***). : : Et si on se ramène à l'écriture ci-dessus, on obtient plutôt char : *(*)[] : j'ai rajouté l'indirection au bon endroit, c'est-à-dire au : milieu, et cela impose donc de rajouter une paire de parenthèse. [...] :> static void foo (char ***RcptList, char **email) : : static void foo (char *(*RcptList)[], char *entetes[])
En fait, cette explication très bien au plan didactique. Sauf sur un point. Ce n'est pas du C correct. Groumpf. En effet, en C seul le _dernier_ qualificateur de tableau est transformé en pointeur, ce n'est pas le cas pour les autres qualificateurs de tableau.
Ainsi, dans
int machin(int tableau[N][M][P])
on définit un paramètre tableau qui est en fait un pointeur vers... int[M][P], pointeur vers une matrice à deux dimensions, et cette chose n'est *pas* un simple pointeur ; entre autre, il est nécessaire de spécifier les dimensions de la matrice (c'est tout le problème du passage des tableaux à plusieurs dimensions). Notons bien qu'ici, le compilateur néglige l'indication de la taille N qui indique la taille du « cube », et il est possible et même courant d'écrire
on y lit que entetes est un pointeur vers des chaînes (rangées dans un tableau, mais c'est juste la syntaxe qui nous renseigne, pour le compilateur c'est la même chose que char**, un pointeur vers pointeur vers un caractère), mais que par contre RcptList est un pointeur vers un tableau _incomplet_ de chaînes. BUG.
Évidemment, lorsque tu demandes à redimensionner le tableau incomplet, le compilateur proteste, on est pas en Basic Microsoft ici.
Donc en fait, il n'y a pas de moyen d'échapper à l'horrible ***. De fait, si l'on regarde le cas des chaînes, en fait ce sont bien des char[] mais dans la pratique toutes les fonctions les manipulent comme des char* : c'est pour la même raison.
En conséquence, mon écriture du prototype était très bien pour [faire] comprendre le problème, mais pas correcte pour le compilateur. Snif+Groumpf.
J'ai sans doute fait une erreur quelque part.
Non non. L'erreur est de ma part. L'exemple était trop parlant, et j'ai trop fait de Pascal dans ma vie. D'ailleurs en C, comme je l'écrivais, je n'aurais pas utilisé des char*[] mais des (vraies) listes chaînées ; et cette discussion est une preuve supplémentaire de la justesse de ce point de vue.
Antoine
Erwan David
Mickaël Wolff écrivait :
Erwan David a écrit :
MALLOC et REALLOC ont quelles définitions ? En majuscule ce sont des macros (a priori).
Tu devrais relire le premier article du thread ;)
Oups je n'étais pas remonté assez haut...
-- Le travail n'est pas une bonne chose. Si ça l'était, les riches l'auraient accaparé