IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

mes pointeurs se "croisent"


Sujet :

C

  1. #1
    Membre éclairé
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    1 298
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 298
    Points : 886
    Points
    886
    Par défaut mes pointeurs se "croisent"
    Bonjour, mon code a une erreur que j'arrive à réparer mais en soit je ne la comprends pas. Pouvez-vous me l'expliquer s'il vous plait ? Je vous envoie d'abord mon code qui marche (pour que vous puissiez le compiler si vous avez envie) et ensuite je vous explique le problème

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
     
    #include<stdio.h>
    #include<stdlib.h>
    #include<assert.h>
     
    typedef struct t_tab
    {
        int dim; // dimension du tableau
        double * data;
    } Tableau;
     
    Tableau * alloc_Tableau(unsigned int dim_,double val)
    {
    // alloue un espace memoire pour creer le tableau t et l'initialise a val
        assert(dim_>=0);
     
        Tableau * t=malloc(sizeof(Tableau));
        assert(t!=NULL);
     
        if(dim_==0) // si dim_==0 on considere que le tableau est vide
        {
    	t->dim=0;
    	t->data=NULL;
        }
        else
        {
    	t->dim=dim_;
    	t->data=malloc(dim_*sizeof(double));
    	assert(t->data!=NULL);
    	int i;
    	for(i=0;i<dim_;i++)
    	    t->data[i]=val;
        }
        return t;
    }
     
    void free_Tableau(Tableau * t)
    {
        t->dim=0;
    // libere la memoire
        if(t->data!=NULL)
        {
    	free(t->data);
    	t->data=NULL;
        }
        free(t);
        t=NULL;
        return ;
    }
     
    Tableau * Tableau_vide(void)
    {
        Tableau * t=malloc(sizeof(Tableau));
        t->dim=0;
        t->data=NULL;
        return t;
    }
     
    void affiche_Tableau(Tableau * t)
    {
        if(t->data==NULL)
    	printf("\nTableau vide\n");
        else
        {
    	int i;
    	for(i=0;i<t->dim;i++)
    	    printf("%7.10g\t",t->data[i]);
    	printf("\n");
        }
        printf("\n");
        return;
    }
     
    void copie_Tableau(Tableau * t,Tableau * out)
    {
    // copie le tableau *t dans le tableau *out
     
        if(t->data!=out->data) // permet de faire copie_Tableau(t,t)
        {
    	free_Tableau(out);
     
    	if(t->dim==0) // tableau vide
    	    out=Tableau_vide();
    	else
    	{
    	    out=alloc_Tableau(t->dim,0.0);
    	    int i;
    	    for(i=0;i<out->dim;++i)
    		out->data[i]=t->data[i];
    	}
        }
        return;
    }
     
    void f(Tableau * t1,Tableau * t2)
    {
    // Cree deux tableau t1 et t2
     
        free_Tableau(t1);
        t1=alloc_Tableau(3,2);
     
        free_Tableau(t2);
        t2=alloc_Tableau(4,1);
     
       return;
    }
     
    int main()
    {
        Tableau * t1=Tableau_vide();
        Tableau * t2=Tableau_vide();
     
        f(t1,t2);
     
        printf("affichage de t1\n");
        affiche_Tableau(t1);
     
        printf("affichage de t2\n");
        affiche_Tableau(t2);
     
        free_Tableau(t1);
        free_Tableau(t2);
     
        return 0;
    }
    Les sorties sont correctes :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    affichage de t1
          2       2       2
     
    affichage de t2
          1       1       1       1
    Maintenant, je modifie la fonction f de la manière suivante (et là il y a une erreur) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    void f(Tableau * t1,Tableau * t2)
    {
    // Cree deux tableau t1 et t2
     
        free_Tableau(t1);
        free_Tableau(t2);
     
        t1=alloc_Tableau(3,2);
        t2=alloc_Tableau(4,1);
     
       return;
    }
    Donc en soit je n'ai fait que déplacer le free_Tableau(t2); et la sortie est :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    affichage de t1
     
     
    affichage de t2
          2       2       2
     
    Erreur de segmentation
    donc pour l'affichage de t2 il m'affiche t1, pour l'affichage de t1 il ne m'affiche rien du tout (même pas Tableau vide) et j'ai une erreur de segmentation.

    Savez-vous pourquoi s'il vous plait ?

    Merci d'avance;

  2. #2
    Membre actif Avatar de Biosox
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    298
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Mai 2005
    Messages : 298
    Points : 203
    Points
    203
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    Tableau * alloc_Tableau(unsigned int dim_,double val)
    {
    	// alloue un espace memoire pour creer le tableau t et l'initialise a val
        assert(dim_>=0);
     
        Tableau * t=malloc(sizeof(Tableau));
        assert(t!=NULL);
     
        if(dim_==0) // si dim_==0 on considere que le tableau est vide
        {
    		t->dim=0;
    		t->data=NULL;
        }
        else
        {
    		t->dim=dim_;
    		t->data=malloc(dim_*sizeof(double));
    		assert(t->data!=NULL);
    		int i;
    		for(i=0;i<dim_;i++)
    			t->data[i]=val;
        }
        return t;
    }
    dans cette fonction, tu crées un nouveau tableau, que tu remplis de façon correcte, malheureusement t est sur la pile. ça signifie qu'à la fin de la fonction, la zone de mémoire utilisée par t sera modifiée pas l'appel de la fonction suivante. Or tu retourne t!!!
    Donc, après l'appel:
    t1 pointe vers la pile. Il y a toutes les chances que t1 soit modifié n'importe comment la prochaine fois que tu utilises la pile.

    d'une règle générale, si tu veux que ta fonction modifie un de ses paramètres, utilise un pointeur vers ce paramètre.

    par exemple, ici, t1 est un pointeur vers un tableau.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Tableau * t1=Tableau_vide();
    pour modifier t1, il faut un pointeur vers t1! donc un pointeur vers un pointeur de tableau:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    //définis ta fonction ainsi:
    void fonctionQuiModifieLesTableau(Tableau ** t);
    {
     /* ton code*/
    }
     
    //appellela en lui passant un pointeur vers t1:
    fonctionQuiModifieLesTableau(&t1);

  3. #3
    Membre éclairé
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    1 298
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 298
    Points : 886
    Points
    886
    Par défaut
    Salut Biosox, merci de me répondre. Tu as écrit :

    dans cette fonction, tu crées un nouveau tableau, que tu remplis de façon correcte, malheureusement t est sur la pile. ça signifie qu'à la fin de la fonction, la zone de mémoire utilisée par t sera modifiée pas l'appel de la fonction suivante. Or tu retourne t!!!
    Mais je ne comprends pas pourquoi t est sur la pile et non dans le tas. je le crée pourtant dynamiquement car je fais :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    Tableau * t=malloc(sizeof(Tableau));
    mais peut être que je n'ai rien compris au malloc alors.

  4. #4
    Membre du Club
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    34
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 34
    Points : 40
    Points
    40
    Par défaut
    Je me permets de répondre pour Biosox (j'espère qu'il ne m'en voudra pas ).

    Ce qu'il a voulu dire, c'est que la variable t est une variable locale à la fonction, donc déclarée dans la pile. Par contre, effectivement, l'espace mémoire alloué par malloc() l'est bien dans le tas.

    Pour ce qui est de ton problème, Biosox l'a bien cerné. Une preuve? Teste ton programme avec le main() suivant:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    Tableau * t1=Tableau_vide(); 
     
    printf("Adresse de t1 avant vidage: %p", t1);
    free_Tableau(t1);
    printf("\nAdresse de t1 apres vidage: %p", t1);
    La fonction free_Tableau est censée mettre le pointeur à NULL, ce qui n'est pas le cas tu vas voir...

    Au fait: rajoute des cast avant les malloc(), ça fera pas de mal...

  5. #5
    Membre éclairé
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    1 298
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 298
    Points : 886
    Points
    886
    Par défaut
    Salut programan, j'ai bien fait ton code et voici mes sorties

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Adresse de t1 avant vidage: 0x501010
    Adresse de t1 apres vidage: 0x501010
    Dans la FAQ, j'ai lu que le fait de faire free(un pointeur) on "libère" la mémoire mais elle n'est pas effacée, si bien qu'on peut réécrire dessus. Donc pour le test de ton code, est-ce se qui se passe ? Les adresses sont les mêmes mais après vidage, la mémoire est libérée non ?

    Sinon, j'ai modifé ma fonction f de tout à l'heure. Voici donc ce que j'ai fait :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    void f(Tableau ** t1,Tableau ** t2)
    {
    // Cree deux tableaux t1 et t2
     
        free_Tableau(*t1);
        free_Tableau(*t2);
     
        *t1=alloc_Tableau(3,2);
        *t2=alloc_Tableau(4,1);
     
        return;
    }
    et ca marche (merci Biosox !)


    Programan, tu as dit :

    c'est que la variable t est une variable locale à la fonction, donc déclarée dans la pile. Par contre, effectivement, l'espace mémoire alloué par malloc() l'est bien dans le tas.
    ce que j'ai (encore) du mal à comprendre est que j'ai écrit

    et non
    dans le second je comprends que t soit dans la pile, mais dans le 1e cas, je ne comprends pas pourquoi (même si effectivement ceci est la cause de mon pb)

    Merci

  6. #6
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut Re: mes pointeurs se "croisent"
    Citation Envoyé par salseropom
    Donc en soit je n'ai fait que déplacer le free_Tableau(t2); et la sortie est :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    affichage de t1
     
     
    affichage de t2
          2       2       2
     
    Erreur de segmentation
    donc pour l'affichage de t2 il m'affiche t1, pour l'affichage de t1 il ne m'affiche rien du tout (même pas Tableau vide) et j'ai une erreur de segmentation.

    Savez-vous pourquoi s'il vous plait ?
    Ben oui. Tu modifies des paramètre (variables locales), ça ne modifie pas les valeurs originales.. Je ne sais pas ce que tu cherches à faire, mais c'est faux.

    Soit tu passes l'adresse du pointeur (lourd), soit tu retournes l'adresse (pas possible, il y en a 2), soit tu met tes pointeurs dans une structure et tu passes l'adresse de celle-ci. Je ferais comme ça.
    Pas de Wi-Fi à la maison : CPL

  7. #7
    Membre du Club
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    34
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 34
    Points : 40
    Points
    40
    Par défaut
    Citation Envoyé par salseropom
    dans le second je comprends que t soit dans la pile, mais dans le 1e cas, je ne comprends pas pourquoi
    Dans le premier cas, t est un pointeur. Or un pointeur est une variable comme les autres, si ce n'est qu'elle contient des adresses au lieu de valeurs entières ou réelles. Donc un pointeur obéit aux mêmes règles que les autres variables, et par conséquent si un pointeur est déclaré local à une fonction, de manière non dynamique, il le sera dans la pile, peu importe son contenu...

    Supposons par exemple que tu fasses ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    float *p1;
    float *p2;
    float f;
     
    p1 = (float*)malloc(sizeof(float));
    p2 = &f;
     
    printf("Contenu de p1: %p  Contenu de p2: %p", p1,p2);
    printf("\nAdresse de p1: %p  Adresse de p2: %p", &p1, &p2);
    La valeur que l'on met dans p1 correspond à l'adresse d'un espace qui a été alloué dans le tas (par malloc), alors que celle que l'on met dans p2 correspond à l'adresse d'un espace qui a été alloué dans la pile (l'adresse de la variable f).

    Mais dans les deux cas, les pointeurs ont été déclarés de la même manière, donc il n'y a aucune raison que l'un soit déclaré dans la pile et l'autre dans le tas... D'ailleurs tu verras que parmis les quatre adresses affichées, l'une d'elles est très éloignée des autres... C'est la seule du tas.

    EDIT: j'ai modifié mon exemple pour qu'il soit un peu plus explicite...

  8. #8
    Membre éclairé
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    1 298
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 298
    Points : 886
    Points
    886
    Par défaut
    Je saisis de mieux en mieux. En fait, pour modifier mon tableau en paramètre de ma fonction f, j'ai voulu m'inspirer du "fameux" exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    void f2(int * pint)
    {
        *pint=2* (*pint);
     
        return ;
    }
    qui me double mon argument de la fonction f2 (donc l'argument est modifié). Donc en faisant void f(Tableau * t1, Tableau * t2); j'ai voulu faire la même chose que void f2(int * pint). Le int est modifié donc le tableau aussi, mais je vois que ce n'est pas le cas.

  9. #9
    Membre du Club
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    34
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 34
    Points : 40
    Points
    40
    Par défaut
    Citation Envoyé par salseropom
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    void f2(int * pint) 
    { 
        *pint=2* (*pint); 
     
        return ; 
    }
    qui me double mon argument de la fonction f2 (donc l'argument est modifié). Donc en faisant void f(Tableau * t1, Tableau * t2); j'ai voulu faire la même chose que void f2(int * pint). Le int est modifié donc le tableau aussi, mais je vois que ce n'est pas le cas.
    Oui, mais regarde bien l'appel: on a quelque chose du style:
    Or ce qui est valable pour un int l'est aussi pour un pointeur: si celui-ci doit être modifié (et c'est le cas dans ton programme), c'est bien l'adresse du pointeur lui même (et non pas l'adresse qu'il contient) que tu dois passer en paramètre (voir tout ce qui a été dit jusqu'ici).

  10. #10
    Membre éclairé
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    1 298
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 298
    Points : 886
    Points
    886
    Par défaut
    Or ce qui est valable pour un int l'est aussi pour un pointeur: si celui-ci doit être modifié (et c'est le cas dans ton programme), c'est bien l'adresse du pointeur lui même (et non pas l'adresse qu'il contient) que tu dois passer en paramètre
    J'ai compris !!

    Merci de votre patience en tout cas.

    Donc, (pour me rassurer), si je fais

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    int main()
    {
    Tableau * t=alloc_Tableau(5,0.0);
    affiche_Tableau(t);
    free_Tableau(t);
     return 0;
    }
    Mon tableau t est bien dans le tas (et non dans la pile) et j'efface bien mon tableau par free_Tableau ou bien est-ce toujours le même problème (auquel cas je doit recommencer mes fonctions) car je veux que free_Tableau me modifie mon tableau en argument.

    dois-je faire alors

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    void free_Tableau(Tableau ** t)
    {
    blabla;
    }
    et ensuite je fais

    alors que là je fais seulement

    donc en fait je n'efface rien du tout alors.

  11. #11
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    Je reprends ton code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    void free_Tableau(Tableau * t) 
    { 
        t->dim=0; // Inutile , *t doit être détruit par le free(t)
    // libere la memoire 
        if(t->data!=NULL) 
        { 
       free(t->data); 
       t->data=NULL;   // Inutile , *t doit être détruit par le free(t)
        } 
        free(t); 
        t=NULL;    // Inutile t est local à la fonction et sera détruit
        return ; 
    }
    int main() 
    { 
    Tableau * t=alloc_Tableau(5,0.0); 
    affiche_Tableau(t); 
    free_Tableau(t); 
     return 0; 
    }
    alors que là je fais seulement donc en fait je n'efface rien du tout alors.
    t de main est l'adresse du premier élément du tableau alloué par alloc_Tableau. Dans free_Tableau, tu crée une variable locale t initialisée par une copie de cette valeur. Tu fais donc alors un free(t) sur cette adresse donc qui détruit bien le tableau alloué. Tu mets la variable locale t à NULL, puis la fonction se termine et le t de free_Tableau, est détruit. Tu retournes à main. Le t de main n'a pas changé. Il contient toujours la même adresse mais maintenant cette adresse est celle d'un bloc détruit. C'est le t dans main, qu'il faut mettre à NULL. Par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    void free_Tableau(Tableau * t) 
    { 
        if(t->data!=NULL)  free(t->data); 
        free(t); 
    }
    int main() 
    { 
       Tableau * t=alloc_Tableau(5,0.0); 
       affiche_Tableau(t); 
       free_Tableau(t) ;
       t = NULL;
        .....
       return 0; 
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    dois-je faire alors 
    void free_Tableau(Tableau ** t) 
    { 
    blabla; 
    } 
    et ensuite je fais 
    free_Tableau(*t)
    Si tu choisi cette option pour free_Tableau , alors l'appel doit êtreCeci permet de mettre depuis la fonction le t de main à NULL (puisque le paramètre est l'adresse du t de main) mais complique un peu l'écriture du code de free_Tableau
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    void free_Tableau(Tableau ** t) 
    { 
        if( (*t)->data!=NULL)  free((*)t->data); 
        free(*t);
        *t = NULL; 
    }
    Il te faut absolument intégrer ce fonctionnement du passage des paramètres à une fonction (par copie de l'argument ) et retenir que toutes les variables locales (y compris les arguments) sont détruites quand on quitte la fonction
    Bonne soirée
    Publication : Concepts en C

    Mon avatar : Glenn Gould

    --------------------------------------------------------------------------
    Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !

  12. #12
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Citation Envoyé par programan
    Au fait: rajoute des cast avant les malloc(), ça fera pas de mal...
    Non, c'est d'une part inutile, d'autre part déconseillé, car cela cache des erreurs/avertissements qui apparaitraient si <stdlib.h> n'était pas inclus...

    (moi aussi, j'en mettais, je suis venu sur le forum, et... J'ai vu la lumière)
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  13. #13
    Membre éclairé
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    1 298
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 298
    Points : 886
    Points
    886
    Par défaut
    Salut diogène,
    merci de cette réponse très détaillée.

    Si j'avais fais

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    Tableau t=alloc_Tableau(5,0.0);
    (en modifiant bien sûr ma fonction alloc_Tableau) alors ensuite la fonction

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    free_Tableau(* t);
    me détruit bien mon tableau (avec l'appel free_Tableau(&t) ) car le t de free_Tableau est le même que le t du main et la fonction free_Tableau deviendrait alors

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    void free_Tableau(Tableau * t)
    {
    free(t->data);
    t->data=NULL;
    }
     
    je pense que j'ai du confondre avec cette méthode (si j'ai bien compris ce que tu m'as dit).
     
    Merci encore.

  14. #14
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Tableau t=alloc_Tableau(5,0.0);;
    A l'inconvénient de renvoyer une copie de la structure Tableau. Je crois que la version précédente est meilleure.
    ne peut fonctionner puisque t n'est plus dans ce cas un pointeur mais un Tableau
    L'appel en
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    free_Tableau(&t)
     avec
     void free_Tableau(Tableau ** t){...}
    me semble meilleure car elle permet dans cette seule fonction de tout bien remettre à l'état de départ sans nécessité de t = NULL qu'un jour ou l'autre, on risque d'oublier. Le code de libération est alors bien localisé dans cette fonction
    Publication : Concepts en C

    Mon avatar : Glenn Gould

    --------------------------------------------------------------------------
    Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !

  15. #15
    Membre éclairé
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    1 298
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 298
    Points : 886
    Points
    886
    Par défaut
    Salut diogene, oui mais je pensais faire sinon

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Tableau t;
    alloc_Tableau(&t,5,0.0)
    où j'aurais créé une fonction void alloc_Tableau(Tableau *,int,double)
    Le seul intérêt est que je n'ai pas de Tableau ** mais seulement un Tableau * et ainsi j'évite la recopie temporaire. Bien entendu je dois modifier en conséquence toutes les autres fonctions.

    que me conseilles-tu ?

    Merci encore

  16. #16
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Tableau t; 
    alloc_Tableau(&t,5,0.0)
    où j'aurais créé une fonction void alloc_Tableau(Tableau *,int,double)
    Ton code construit un objet Tableau dont tu passes l'adresse ce qui permet à la fonction de consulter et de modifier cet objet.
    Dans ce cas, alloc_Tableau ne construira pas l'objet Tableau mais initialisera les membres ( Ce n'est plus une alloc_...).
    free_Tableau n'a plus qu'à récupérer la mémoire allouée à Data. Son argument peut être Tableau ou mieux Tableau * pour éviter la recopie locale.
    Le choix d'une solution dépend de ce que tu veux : Cette solution est simple MAIS t est détruit en sortie de la fonction où se trouve la déclaration Tableau t; donc la durée de vie de t est réduite. Par exemple, peut être que cela t'obligeras à avoir cette déclaration dans le main (c'est le cas actuellement). Si ton programme prend de l'ampleur ceci peut être un facteur gènant et t'obliger alors à le(s) construire de façon dynamique avant l'appel à la fonction alloc-Tableau. En pratique, ceci déplace du code entre l'actuelle alloc-Tableau et la fonction appelante et tout dépend combien de fois tu auras à en créer.
    Personnellemnt, la solution précédente me plait mieux, parce que :
    - tout le code de construction de l'objet est dans une seule fonction
    - tout le code de destruction de l'objet est dans une seule fonction
    Ces fonctions mises au point , l'utilisation en est très simple et transparente
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Tableau * t=alloc_Tableau(5,0.0); 
    ... 
    free_Tableau(&t);
    Si tu veux modifier la définition des objets Tableau pour les "perfectionner", seul le code de ces fonctions est à considérer et tous les objets Tableaux dispersés dans le programme se construiront et se détruiront correctement
    Le seul intérêt est que je n'ai pas de Tableau ** mais seulement un Tableau * et ainsi j'évite la recopie temporaire.
    Dans les 2 cas, tu as la copie temporaire d'un pointeur. C'est chou vert , vert chou

    Mais c'est à toi de choisir, c'est toi qui connais le projet total !
    Publication : Concepts en C

    Mon avatar : Glenn Gould

    --------------------------------------------------------------------------
    Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !

  17. #17
    Membre éclairé
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    1 298
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 298
    Points : 886
    Points
    886
    Par défaut
    Re,
    OK, je retourne à ma version précédente, et je change mon free_Tableau(Tableau *) en free_Tableau(Tableau **) ainsi que les autres fonctions afin de garder ma structure Tableau * t=alloc_Tableau(5,2.0);

    Merci encore de toute ta patience !!

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo