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

travail sur les pointeurs

17 réponses
Avatar
Vincent
Bonjour,

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.

#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <winsock2.h>
#include <ws2tcpip.h>

#define MALLOC(x) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (x))
#define FREE(x) do { HeapFree(GetProcessHeap(), HEAP_NO_SERIALIZE, (x));
(x)=NULL; } while(0)
#define REALLOC(pt, x) HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
(pt), (x))

static void foo (char ***RcptList, char **email)
{
int i = 0, j = 0;
if (!email || !RcptList || !*RcptList)
return;

while (*RcptList[i])
i++;

while(email[j])
{
/* if (!IsPresentInList(*RcptList, email[j]))
{*/
*RcptList[i] = MALLOC(strlen(email[j])+1);
memset(*RcptList[i], '\0', strlen(email[j])+1);
strcpy(*RcptList[i], email[j]);
i++;
*RcptList = REALLOC(*RcptList, (i+1)*sizeof(char *));
*RcptList[i] = NULL;
/*}*/
j++;
}
return;
}

int main (int argc, char ** argv)
{
char ** to = NULL;
char ** rcpt = NULL;
to = MALLOC(3*sizeof(char*));
to[0] = MALLOC(50);
to[1] = MALLOC(50);
to[2] = NULL;

rcpt = MALLOC(sizeof(char *));
rcpt[0] = NULL;

sprintf(to[0],"toto@titi.com");
sprintf(to[1],"qrsfrferf@zer.com");

foo(&rcpt,to);
int i = 0;
while (rcpt[i]) {
printf("%d:%s\n",i,rcpt[i]);
i++;
}
return 0;
}

10 réponses

1 2
Avatar
-ed-
On 29 août, 23:19, Vincent wrote:
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 f ois sortie
de foo().



3 *, ça me donne mal à la tête. Ceci fonctionne :

#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#define MALLOC(x) malloc(x)
#define FREE(x) free (x)
#define REALLOC(pt, x) realloc (pt, x)

static char **foo (char **RcptList, char **email)
{
int i = 0, j = 0;

while (RcptList[i])
i++;

while (email[j])
{
RcptList[i] = MALLOC (strlen (email[j]) + 1);

strcpy (RcptList[i], email[j]);
i++;
RcptList = REALLOC (RcptList, (i + 1) * sizeof *RcptList);
RcptList[i] = NULL;

j++;
}
return RcptList;

}

int main (void)
{
char **to = MALLOC (3 * sizeof *to);

to[0] = MALLOC (50);
to[1] = MALLOC (50);
to[2] = NULL;
strcpy (to[0], "");
strcpy (to[1], "");

{
char **rcpt = MALLOC (1 * sizeof *rcpt);
rcpt[0] = NULL;

rcpt = foo (rcpt, to);

if (rcpt != NULL)
{
int i = 0;
while (rcpt[i])
{
printf ("%d:%sn", i, rcpt[i]);
i++;
}
}
}

return 0;
}

0:
1:

Process returned 0 (0x0) execution time : 0.037 s
Press any key to continue.



Mais il y a des précautions à prendre quand on utilise realloc() :

http://mapage.noos.fr/emdel/notes.htm#realloc
Avatar
Marc Boyer
On 2008-08-29, Vincent wrote:
Bonjour,

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.

#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <winsock2.h>
#include <ws2tcpip.h>



Ben, si déjà tu nous donnais du code C compilable ailleurs
que sur une machine Win*, tu augmenterais l'audience des gens
susceptibles de t'aider.

#define MALLOC(x) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (x))
#define FREE(x) do { HeapFree(GetProcessHeap(), HEAP_NO_SERIALIZE, (x));
(x)=NULL; } while(0)
#define REALLOC(pt, x) HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
(pt), (x))

static void foo (char ***RcptList, char **email)



Elle est sensée faire quoi cette fct ? Elle reçoit une
ref sur un tableau de char (RcptList), mais **email,
c'est quoi ?

{
int i = 0, j = 0;
if (!email || !RcptList || !*RcptList)
return;



Ca n'a rien à voir avec ton problème, mais penses-tu
que ce soit une bonne idée de faire un simple "return"
si RcptList == NULL ?

while (*RcptList[i])
i++;



Ton tableau des NULL-terminated, et tu cherches sa fin.
C'est ça ?
Au fait, tu connais par coeur tes priorités d'opérateurs ?
Ce serait pas
while ( (*RcptList)[i])


que tu voudrait tester ?

Marc Boyer
--
Si tu peux supporter d'entendre tes paroles
Travesties par des gueux pour exciter des sots
IF -- Rudyard Kipling (Trad. André Maurois)
Avatar
-ed-
On 30 août, 22:18, Marc Boyer
wrote:
On 2008-08-29, Vincent wrote:



> Bonjour,

> 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 d e
> 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.

> #include <windows.h>
> #include <stdlib.h>
> #include <string.h>
> #include <stdio.h>
> #include <winsock2.h>
> #include <ws2tcpip.h>

  Ben, si déjà tu nous donnais du code C compilable ailleurs
que sur une machine Win*, tu augmenterais l'audience des gens
susceptibles de t'aider.



> #define MALLOC(x) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (x))
> #define FREE(x) do { HeapFree(GetProcessHeap(), HEAP_NO_SERIALIZE, (x)) ;
> (x)=NULL; } while(0)
> #define REALLOC(pt, x) HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
> (pt), (x))

> static void foo (char ***RcptList, char **email)

  Elle est sensée faire quoi cette fct ? Elle reçoit une
ref sur un tableau de char (RcptList), mais **email,
c'est quoi ?

> {
>    int i = 0, j = 0;
>    if (!email || !RcptList || !*RcptList)
>      return;

  Ca n'a rien à voir avec ton problème, mais penses-tu
que ce soit une bonne idée de faire un simple "return"
si RcptList == NULL ?

>    while (*RcptList[i])
>      i++;

  Ton tableau des NULL-terminated, et tu cherches sa fin.
C'est ça ?
   Au fait, tu connais par coeur tes priorités d'opérateurs ?
Ce serait pas>    while ( (*RcptList)[i])

  que tu voudrait tester ?

Marc Boyer
--
Si tu peux supporter d'entendre tes paroles
Travesties par des gueux pour exciter des sots
                           IF -- Rudyard Kipl ing (Trad. André Maurois)



Comme je l'
Avatar
-ed-
On 30 août, 22:18, Marc Boyer
wrote:
> static void foo (char ***RcptList, char **email)


<...>
   Au fait, tu connais par coeur tes priorités d'opérateurs ?
Ce serait pas>    while ( (*RcptList)[i])

  que tu voudrait tester ?



Je recommence.

Comme je l'ai dit, 3 *, ça rend fou...
Avatar
Marc Boyer
On 2008-09-01, -ed- wrote:
On 30 août, 22:18, Marc Boyer
> static void foo (char ***RcptList, char **email)


<...>
   Au fait, tu connais par coeur tes priorités d'opérateurs ?
Ce serait pas>    while ( (*RcptList)[i])

  que tu voudrait tester ?



Je recommence.

Comme je l'ai dit, 3 *, ça rend fou...



En général, j'essaye d'éviter moi aussi.
Mais bon, là, ça fait un peu d'exercice ;-)

Marc Boyer
--
Si tu peux supporter d'entendre tes paroles
Travesties par des gueux pour exciter des sots
IF -- Rudyard Kipling (Trad. André Maurois)
Avatar
Vincent
> 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.

J'ai bien pensé à utiliser ce que vous proposez. Juste pour être sûr et
clair : dans main() char **rcpt est initialisé à sizeof *rcpt. Imaginons
que le REALLOC() de foo() décide qu'il n'y a plus assez de place
contigüe et décide de réallouer à un autre endroit: le pointeur rcpt
pointe sur une zone non valide jusqu'au moment ou foor() retourne la
valeur du pointeur valide sur la nouvelle zone, n'est-ce pas? Il n'y a
donc en aucun cas de fuite mémoire la dedans, je me trompe?

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. J'ai bien l'ensemble des
chaines copiée tant que je suis dans foo(), mais une fois revenu dans
main(), seule la première, soit rcpt[0] est copiée correctement, rcpt[1]
est NULL et rcpt[2] aussi.

Merci en tout cas de l'aide apporté.

Vincent
Avatar
Vincent
Marc Boyer wrote:

Ben, si déjà tu nous donnais du code C compilable ailleurs
que sur une machine Win*, tu augmenterais l'audience des gens
susceptibles de t'aider.



Cetes vous avez raison..

static void foo (char ***RcptList, char **email)



Elle est sensée faire quoi cette fct ? Elle reçoit une
ref sur un tableau de char (RcptList), mais **email,
c'est quoi ?



Elle est censée recopier les chaines contenues dans le tableau de char
(email), à la fin des chaines présentes dans le tableau référencé par
RcptList.

Ca n'a rien à voir avec ton problème, mais penses-tu
que ce soit une bonne idée de faire un simple "return"
si RcptList == NULL ?




Pour ne pas lancer un débat pour rien oui, vous avez raison sur le fond,
bien que dans le reste du programme, l'algorithme gère naturellement ce
cas d'erreur.

while (*RcptList[i])
i++;



Ton tableau des NULL-terminated, et tu cherches sa fin.
C'est ça ?
Au fait, tu connais par coeur tes priorités d'opérateurs ?
while ( (*RcptList)[i])





Non, mais merci d'avoir pointer cela.

Ceci dit, sur le fond du problème, je ne suis guère avancé.

Vincent
Avatar
Jean-Marc Bourguet
Vincent writes:

Marc Boyer wrote:

>> while (*RcptList[i])
>> i++;
>
> Ton tableau des NULL-terminated, et tu cherches sa fin.
> C'est ça ?
> Au fait, tu connais par coeur tes priorités d'opérateurs ?
>> while ( (*RcptList)[i])

Non, mais merci d'avoir pointer cela.



Si, c'est la solution probleme (en corrigeant aussi aux autres endroits
ou tu as commis la meme erreur)

static void foo (char ***RcptList, char **email)
{
int i = 0, j = 0;
if (!email || !RcptList || !*RcptList)
return;

while ((*RcptList)[i])
i++;

while(email[j])
{
(*RcptList)[i] = MALLOC(strlen(email[j])+1);
memset((*RcptList)[i], '', strlen(email[j])+1);
strcpy((*RcptList)[i], email[j]);
i++;
*RcptList = REALLOC(*RcptList, (i+1)*sizeof(char *));
(*RcptList)[i] = NULL;
j++;
}
return;
}

(En passant, la reallocation avec +1 a chaque fois, c'est un comportement
quadratique...)

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
Antoine Leca
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.

Cette digression semble peut-être inutile et superfétatoire, mais comme par
la suite ton code semble vouloir utiliser exactement mon formalisme...


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 ne sais pas si j'ai été bien clair, dans le cas contraire, je
tenterai d'expliquer différemment mon problème.



Non non, c'est très clair, en tous cas pour nous...


static void foo (char ***RcptList, char **email)



static void foo (char *(*RcptList)[], char *entetes[])

{ int i = 0, j = 0;
while (*RcptList[i]) i++;



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.

Marc dans news: n'a pas été plus
loin, car il a dû lui paraître évident que ce n'était pas nécessaire.
En fait, si tu ne corriges _que_ cette occurence, tu vas améliorer le
fonctionnement trop bancal de ton code mais pas corriger le bogue que tu
observes ; je suppose que c'est ce qui t'es arrivé ce matin
(news:48bce70c$0$30867$). Mais non : il faut corriger
de la même manière toutes les occurences de RcptList.

Si tu avais fait du Pascal avant, tu aurais écrit au début de ta fonction

static void foo (char *(*pRcpts)[], char *entetes[])
#define TabRcpt (*pRcpts)

et en utilisant TabRcpt, comme dans
while (TabRcpt[i]) i++;
on retrouve un comportement sain ; comme dirait Emmanuel 3 c'est trop...

(J'évite List parce que cela me donne des boutons d'utiliser List dans un
identificateur pour une fonction donc l'alpgorithme évident est d'utiliser
une liste, mais dont l'implémentation proposée est un tableau dynamique à
incrément unitaire.)


Pour continuer avec les commentaires de code en passant

#define MALLOC(x) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (x))


^^^^^^^^^^^^^^^^
*RcptList[i] = MALLOC(strlen(email[j])+1);
memset(*RcptList[i], '', strlen(email[j])+1);



Ceinture et bretelles ?

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.


Antoine
Avatar
Marc Boyer
On 2008-09-02, Antoine Leca wrote:
{ int i = 0, j = 0;
while (*RcptList[i]) i++;



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.

Marc dans news: n'a pas été plus
loin, car il a dû lui paraître évident que ce n'était pas nécessaire.



Ben, en effet.
OK, j'ai été un peu lapidaire dans ma remarque.

(news:48bce70c$0$30867$). Mais non : il faut corriger
de la même manière toutes les occurences de RcptList.



Ca aussi ça me paraissait évident.

Marc Boyer
--
Si tu peux supporter d'entendre tes paroles
Travesties par des gueux pour exciter des sots
IF -- Rudyard Kipling (Trad. André Maurois)
1 2