[C] Perte de référence & pointeurs

oBooBo Membre
01:36 modifié dans API UIKit #1
Bonjour,

Une petite question pour les pro du C. J'utilise la librairie gsoap et je dois créer les arguments de mes appels.
Je pensais avoir bien compris les mécanismes entourant les struct, les pointeurs, les références, les pointeurs de struct, etc... mais finalement je me heurte au problème suivant :

struct ns1__num_USCOREassoc<br />{<br />	char *index;	/* required element of type xsd:integer */<br />	char *numero;	/* required element of type xsd:string */<br />};<br /><br />struct array_USCOREof_USCOREnum_USCOREassoc<br />{<br />	struct ns1__num_USCOREassoc **__ptr;<br />	int __size;<br />};<br /><br />//inputNums est un NSDictionnary initialisé avant...<br />//...<br />struct ns1__num_USCOREassoc *inputNumList[[inputNums count]];<br />int i=0;<br />NSLog(@&quot;%d appairages à  envoyer =&gt; &quot;, [inputNums count]);<br />for(id key in inputNums) {<br />	struct ns1__num_USCOREassoc temp;<br />	temp.numero = (char*)[[inputNums objectForKey:key] UTF8String];<br />	temp.index = (char*)[(NSString*)key UTF8String];<br />	inputNumList[i] = &amp;temp;<br />	NSLog(@&quot;#### - Appairage théorique 1 de : %s / %s&quot;, inputNumList[i]-&gt;index, inputNumList[i]-&gt;numero); //NSLOG 1<br />	i++;<br />}<br />synchro_list.__size = [inputNums count]; // synchro_list est un objet de type array_USCOREof_USCOREnum_USCOREassoc<br />synchro_list.__ptr = inputNumList; // synchro_list est un objet de type array_USCOREof_USCOREnum_USCOREassoc<br />for(int i=0;i&lt;[inputNums count];i++) {<br />	NSLog(@&quot;#### - Appairage théorique 2 de : %s / %s&quot;, inputNumList[i]-&gt;index, inputNumList[i]-&gt;numero); //NSLOG 2<br />	NSLog(@&quot;#### - Appairage effectif de : %s / %s&quot;, synchro_list.__ptr[i]-&gt;index, synchro_list.__ptr[i]-&gt;numero); //NSLOG 3<br />}

Voici les traces obtenues :


3 appairages à  envoyer =>
#### - Appairage théorique 1 de : 006 / 0622222222
#### - Appairage théorique 1 de : 005 / 0611111111
#### - Appairage théorique 1 de : 004 / +33622222222
#### - Appairage théorique 2 de : 004 / +33622222222
#### - Appairage effectif de : 004 / +33622222222
#### - Appairage théorique 2 de : 004 / +33622222222
#### - Appairage effectif de : 004 / +33622222222
#### - Appairage théorique 2 de : 004 / +33622222222
#### - Appairage effectif de : 004 / +33622222222


On voit que au moment de mon appairage effectif (LOG 3), tous les pointeurs de mon tableau théorique inputNumList ont été modifiés entre la première boucle (LOG 1) et la deuxième (LOG 2).

Quelqu'un serait susceptible de m'expliquer le pourquoi ?

Merci d'avance,
oBo.

Réponses

  • zoczoc Membre
    juin 2009 modifié #2
    C'est simple... A chaque itération de la première boucle boucle, tu modifies le contenu d'une seule instance de ta struct ns1__num_USCOREassoc. C'est toujours la même à  chaque itération, et par conséquent l'itération n écrase ce que l'itération n-1 a fait...

    De même, inputNumList = &temp; va mettre la même adresse dans chaque élément du tableau du coup...


    il faut donc allouer un ns1__num_USCOREassoc à  chaque itération. (Et ne pas oublier, plus tard, de libérer la mémoire allouée quand elle n'est plus utilisée).

    Autre problème, il faut faire des copies des chaines retournées par UTF8String pour éviter les problèmes (surtout si inputNums est détruit en fait)... Et détruire les copies quand elles ne sont plus utilisées.

    Ca doit donner ça en gros:

    <br />for(id key in inputNums) {<br />   struct ns1__num_USCOREassoc *pTemp = (struct ns1__num_USCOREassoc)malloc(sizeof(struct ns1__num_USCOREassoc));<br />   pTemp-&gt;numero = strdup((char*)[[inputNums objectForKey:key] UTF8String]);<br />   pTemp-&gt;index = strdup((char*)[(NSString*)key UTF8String]);<br />   inputNumList[i] = pTemp;<br />   NSLog(@&quot;#### - Appairage théorique 1 de : %s / %s&quot;, inputNumList[i]-&gt;index, inputNumList[i]-&gt;numero); //NSLOG 1<br />   i++;<br />}
    


    Et attention, tu prends également l'adresse de la variable locale inputNumList pour l'affecter à  synchro_list.__ptr, ce qui te garantira un plantage à  coup sur dès que tu utiliseras synchro_list.__ptr en dehors de cette fonction, car à  ce moment cela pointera sur un tableau qui n'existe plus...

    Il va falloir réviser sérieusement la notion de pointeurs en C, d'après moi ;)
  • oBooBo Membre
    01:36 modifié #3
    Tout à  fait d'accord pour les révisions sur les pointeurs  ::)

    Quoiqu'il en soit tout fonctionne, j'ai du remplacer la ligne
    <br />(struct ns1__num_USCOREassoc)malloc(sizeof(struct ns1__num_USCOREassoc))<br />
    

    par
    <br />malloc(sizeof(struct ns1__num_USCOREassoc))<br />
    


    Autrement il me sortait une erreur conversion to non-scalar type requested.

    Merci pour la rapidité de ta réponse.
  • zoczoc Membre
    01:36 modifié #4
    dans 1245339417:

    Tout à  fait d'accord pour les révisions sur les pointeurs  ::)

    Quoiqu'il en soit tout fonctionne, j'ai du remplacer la ligne
    <br />(struct ns1__num_USCOREassoc)malloc(sizeof(struct ns1__num_USCOREassoc))<br />
    



    Parce que j'aurais du écrire

    (struct ns1__num_USCOREassoc *)malloc(sizeof(struct ns1__num_USCOREassoc))
  • oBooBo Membre
    01:36 modifié #5
    dans 1245339529:

    dans 1245339417:

    Tout à  fait d'accord pour les révisions sur les pointeurs  ::)

    Quoiqu'il en soit tout fonctionne, j'ai du remplacer la ligne
    <br />(struct ns1__num_USCOREassoc)malloc(sizeof(struct ns1__num_USCOREassoc))<br />
    



    Parce que j'aurais du écrire

    (struct ns1__num_USCOREassoc *)malloc(sizeof(struct ns1__num_USCOREassoc))


    Pourrait-il y avoir des problèmes si on ne met pas le pointeur devant le malloc ?
  • zoczoc Membre
    01:36 modifié #6
    Non.

    Tout au plus un warning selon le niveau de warning activé lors de la compilation (parce que le type de retour de la fonction malloc est "void *").
  • oBooBo Membre
    01:36 modifié #7
    Très bien merci ! 
  • Philippe49Philippe49 Membre
    juin 2009 modifié #8
    C'est une inutilité très répandue de mettre un cast devant le malloc(). Les pointeurs génériques void* sont faits justement pour ne pas avoir à  faire de cast.
    La bonne écriture est

    struct ns1__num_USCOREassoc *pTemp = malloc(sizeof(struct ns1__num_USCOREassoc));
    


    Le seul cas où l'absence de cast entraà®ne un warning dans un programme C c'est lorsque l'on n'inclut pas la bibliothèque stdlib.h car alors le prototype implicite de malloc renvoie un int et non un void *. Mais l'erreur en ce cas est l'absence du #include <stdlib.h>, pas l'absence du cast.
    Dans un projet XCode les bibliothèques standards comme stdlib.h sont incluses automatiquement, ce problème ne se pose pas.
    Mais je le répète devant un malloc, on ne met pas de cast.
Connectez-vous ou Inscrivez-vous pour répondre.