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 :

free échoue incompréhensiblement


Sujet :

C

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Lycéen
    Inscrit en
    Décembre 2012
    Messages
    46
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 27
    Localisation : Ile Maurice

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Décembre 2012
    Messages : 46
    Points : 31
    Points
    31
    Par défaut free échoue incompréhensiblement
    Bonjour, je souhaite libérer une allocation dynamique toute simple avec free, mais celle-ci échoue de manière incompréhensible, la valeur 3 est retournée par le programme.

    Mon code :

    main.h:

    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
    #ifndef MAIN_H_INCLUDED
    #define MAIN_H_INCLUDED
     
    #include <SDL.h>
     
    typedef unsigned char Sequence;
     
    typedef struct
    {
        char quit;
        char key[SDLK_LAST];
        int mousex, mousey;
        int mousexrel, mouseyrel;
        char mousebuttons[8];
    }Input;
     
    typedef struct
    {
        int nbFrames, curentFrame;
        Sequence *SequenceTable;
    }AnimationList;
     
    typedef struct
    {
        SDL_Rect *R;
        int interval, nbAnimations;
        AnimationList *List;
    }Animation;
     
    typedef struct
    {
        SDL_Surface *charset;
        int width, height;
        int nbFramesCharsetX, nbFramesCharsetY;
        Animation Animations;
    }Player;
     
    #endif // MAIN_H_INCLUDED
    main.c:

    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
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    #include <string.h>
    #include <SDL_image.h>
    #include "main.h"
     
    SDL_Surface *InitSDL(int width, int height, const char WindowTitle[], const char IconFileName[])
    {
        SDL_Surface *screen = NULL;
     
        if(SDL_Init(SDL_INIT_VIDEO) == -1)
        {
            fprintf(stderr, "%s", SDL_GetError());
            exit(-1);
        }
     
        if((screen = SDL_SetVideoMode(width, height, 32, SDL_HWSURFACE | SDL_DOUBLEBUF)) == NULL)
        {
            fprintf(stderr, "%s", SDL_GetError());
            exit(-1);
        }
     
        SDL_WM_SetCaption(WindowTitle, IconFileName);
     
        return screen;
    }
     
    void UpdateEvents(Input *in)
    {
        SDL_Event event;
     
        in->mousebuttons[SDL_BUTTON_WHEELUP] = 0;
        in->mousebuttons[SDL_BUTTON_WHEELDOWN] = 0;
     
        while(SDL_PollEvent(&event))
        {
            switch(event.type)
            {
                case SDL_QUIT:
                    in->quit = 1;
                    break;
                case SDL_KEYDOWN:
                    in->key[event.key.keysym.sym] = 1;
                    break;
                case SDL_KEYUP:
                    in->key[event.key.keysym.sym] = 0;
                    break;
                case SDL_MOUSEMOTION:
                    in->mousex = event.motion.x;
                    in->mousey = event.motion.y;
                    in->mousexrel = event.motion.xrel;
                    in->mouseyrel = event.motion.yrel;
                    break;
                case SDL_MOUSEBUTTONDOWN:
                    in->mousebuttons[event.button.button] = 0;
                    break;
                case SDL_MOUSEBUTTONUP:
                    if(event.button.button != SDL_BUTTON_WHEELUP && event.button.button != SDL_BUTTON_WHEELDOWN)
                        in->mousebuttons[event.button.button] = 0;
                    break;
                default:
                    break;
            }
        }
    }
     
    SDL_Surface *LoadAdaptedIMG(const char IMG_FileName[])
    {
        SDL_Surface *IMG = NULL;
        SDL_Surface *IMG_Result = NULL;
     
        if((IMG = IMG_Load(IMG_FileName)) == NULL)
        {
            fprintf(stderr, "%s", IMG_GetError());
            exit(-1);
        }
     
        IMG_Result = SDL_DisplayFormat(IMG);
        SDL_FreeSurface(IMG);
     
        return IMG_Result;
    }
     
    void LoadCharset(Player *P, FILE *F)
    {
        int i, j, nbFrame;
        char charsetName[32] = {0};
     
        fscanf(F, "%s", charsetName);
        P->charset = LoadAdaptedIMG(charsetName);
        fscanf(F, "%d %d", &P->nbFramesCharsetX, &P->nbFramesCharsetY);
        P->Animations.R = malloc(P->nbFramesCharsetX*P->nbFramesCharsetY*sizeof(SDL_Rect));
     
        P->width = P->charset->w / P->nbFramesCharsetX;
        P->height = P->charset->h / P->nbFramesCharsetY;
     
        for(j = 0, nbFrame = 0; j < P->nbFramesCharsetY; j++)
        {
            for(i = 0; i < P->nbFramesCharsetX; i++, nbFrame++)
            {
                P->Animations.R[nbFrame].x = i*P->width;
                P->Animations.R[nbFrame].y = j*P->height;
                P->Animations.R[nbFrame].w = P->width;
                P->Animations.R[nbFrame].h = P->height;
            }
        }
    }
     
    void GetAnimationInfo(Player *P, FILE *F)
    {
        int i;
     
        fscanf(F, "%d %d", &P->Animations.nbAnimations, &P->Animations.interval);
        P->Animations.List = malloc(P->Animations.nbAnimations*sizeof(AnimationList));
        for(i = 0; i <= P->Animations.nbAnimations; i++)
            P->Animations.List[i].SequenceTable = malloc(P->Animations.nbAnimations*sizeof(Sequence));
    }
     
    void GetAnimationSequences(Player *P, FILE *F)
    {
        int i, j;
        int curentAnim;
     
        for(j = 0; j < P->nbFramesCharsetY; j++)
        {
            for(i = 0; i < P->nbFramesCharsetX; i++)
            {
                fscanf(F, "%d", &curentAnim);
                if(curentAnim >= P->nbFramesCharsetX*P->nbFramesCharsetY)
                {
                    fprintf(stderr, "Error animation number is out of limit : %d", curentAnim);
                    exit(-1);
                }
                P->Animations.List[j].SequenceTable[i] = curentAnim;
     
                fprintf(stderr, "%d ", curentAnim);
            }
     
            fprintf(stderr, "\n");
        }
    }
     
    Player LoadPlayer(const char PlayerFileName[])
    {
        FILE *F = NULL;
        Player P;
        char tag[32] = {0};
     
        if((F = fopen(PlayerFileName, "r")) == NULL)
        {
            fprintf(stderr, "Failled to open %s", PlayerFileName);
            exit(-1);
        }
     
        do
        {
            fscanf(F, "%s", tag);
            if(strstr(tag, "#charset_info"))
                LoadCharset(&P, F);
            if(strstr(tag, "#animation_info"))
                GetAnimationInfo(&P, F);
            if(strstr(tag, "#animation_sequences"))
                GetAnimationSequences(&P, F);
        }while(strstr(tag, "#end") != NULL);
     
        fclose(F);
     
        return P;
    }
     
    int main(int argc, char* argv[])
    {
        int i;
        Input in;
        SDL_Surface *screen = InitSDL(640, 480, "Animation", NULL);
        Player P;
     
        P = LoadPlayer("anim.txt");
        memset(&in, 0, sizeof(in));
     
        SDL_SetColorKey(P.charset, SDL_SRCCOLORKEY, SDL_MapRGB(P.charset->format, 255, 0, 255));
     
        while(!in.quit && !in.key[SDLK_ESCAPE])
        {
            UpdateEvents(&in);
     
            SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 255, 255, 255));
            SDL_BlitSurface(P.charset, &P.Animations.R[0], screen, NULL);
     
            SDL_Flip(screen);
            SDL_Delay(5);
        }
     
        free(P.Animations.R);
        for(i = 0; i < P.Animations.nbAnimations; i++)
            free(P.Animations.List[i].SequenceTable);
        free(P.Animations.List);
     
        SDL_FreeSurface(P.charset);
        SDL_Quit();
     
        return 0;
    }
    L'erreur est à la ligne 195. L'allocation quand à elle se situe à la ligne 112. Je ne comprend vraiment pourquoi ça échoue. Sinon lorsque je fait free(&P.Animations.List), j'ai un warning : warning : attempt to free a non-heap object 'P'

    Merci de votre aide

  2. #2
    Membre expérimenté Avatar de edgarjacobs
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2011
    Messages
    649
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2011
    Messages : 649
    Points : 1 663
    Points
    1 663
    Par défaut
    Bonjour,

    Dans la fonction LoadPlayer(....), la variable P est locale. Lorsque on quitte cette fonction, la variable P est détruite.... ainsi que son contenu.

    Un solution est de déclarer Player *LoadPlayer(...), et Player *P. Il faut alors allouer P, et le renvoyer. Ce qui sous-entend de modifier également le type de la variable dans le main(...)

  3. #3
    Nouveau membre du Club
    Homme Profil pro
    Lycéen
    Inscrit en
    Décembre 2012
    Messages
    46
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 27
    Localisation : Ile Maurice

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Décembre 2012
    Messages : 46
    Points : 31
    Points
    31
    Par défaut
    Dans la fonction LoadPlayer(....), la variable P est locale

    Certes, mais elle est retournée à la fin de la fonction.

  4. #4
    Membre expérimenté Avatar de edgarjacobs
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2011
    Messages
    649
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2011
    Messages : 649
    Points : 1 663
    Points
    1 663
    Par défaut
    Envoyé par Halarp27

    Certes, mais elle est retournée à la fin de la fonction.
    Lorsque on quitte la fonction LoadPlayer(...), la variable P est détruite.... ainsi que son contenu, c'est-à-dire que les valeurs données aux variables de P (à savoir charset, width, height, nbFramesCharsetX, nbFramesCharsetY, et Animations) sont perdues également.

  5. #5
    Rédacteur
    Avatar de Franck.H
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Janvier 2004
    Messages
    6 951
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Service public

    Informations forums :
    Inscription : Janvier 2004
    Messages : 6 951
    Points : 12 462
    Points
    12 462
    Par défaut
    Citation Envoyé par edgarjacobs Voir le message
    Lorsque on quitte la fonction LoadPlayer(...), la variable P est détruite.... ainsi que son contenu, c'est-à-dire que les valeurs données aux variables de P (à savoir charset, width, height, nbFramesCharsetX, nbFramesCharsetY, et Animations) sont perdues également.
    Tu vois, je ne serais pas si sûr, si tu test ce banal 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
    21
    22
    23
    24
    25
    26
    27
    28
    29
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
     
    typedef struct
    {
       int nb;
       int lifes;
    }Player;
     
    Player init_player (void)
    {
       Player P;
     
       P.nb = 3;
       P.lifes = 5;
     
       return P;
    }
     
    int main (void)
    {
       Player P = init_player ();
       printf ("Nombre de joueurs : %d\nNombre de vies : %d\n",
               P.nb, P.lifes);
     
       return EXIT_SUCCESS;
    }
    tu remarqueras qu'à l'exécution on à bien nos données affichées sur la console, le C procède par copie donc il n'y a pas de problème.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Nombre de joueurs : 3
    Nombre de vies : 5
    hecht@franhec679904:~/Documents/test2/bin/Debug$
    Ou bien le comportement diffère d'un système à l'autre ? Après je suis d'accord, ce n'est pas trop dans les pratiques habituelles, surtout les miennes, en générale je procède également par malloc pour les sturcutres

    Et d'ailleurs, si cela était le cas et que le problème viens effectivement de là, je pense qu'il aurait eu des segfault bien avant d'arriver aux libérations, surtout sur l'utilisation des images

  6. #6
    Membre expérimenté Avatar de edgarjacobs
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2011
    Messages
    649
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2011
    Messages : 649
    Points : 1 663
    Points
    1 663
    Par défaut
    Hello,

    Lorsqu'une variable locale est créée dans une fonction, elle est créée sur le stack (j'ai toujours confondu les termes 'pile' et 'stack', pour moi le stack est ce qui, lors de l'éxecution du programme, contient les variables créées dynamiquement). Donc, lorsqu'on l'on quitte la fonction, l'adresse de P est retournée, et son contenu peut rester valide un moment (mais le stack, lui est modifié). Mais, pour moi, le contenu de P finira par se faire écraser à un moment ou un autre, lors de nouvelles allocations / créations de variables.

    Et si je me trompe (termes ou compréhension), merci de m'éclairer.

    Edgar.

  7. #7
    Rédacteur
    Avatar de Franck.H
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Janvier 2004
    Messages
    6 951
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Service public

    Informations forums :
    Inscription : Janvier 2004
    Messages : 6 951
    Points : 12 462
    Points
    12 462
    Par défaut
    Oui tu y es presque:
    • Stack ou Pile : pour les variables déclarées dans un bloc comme ici
    • Heap ou Tas : Pour les allocations dynamique
    • Static : Mémoire statique pour les variables déclarées avec le mot-clé static


    Après tu as peut-être raison quant à la durée de vie des variables mais étant donné qu'elle n'est pas perdue car retournée par la fonction peut-être que cela change quelque chose, ça je n'en sais pas plus faut avouer

    Sinon Halarp27 essaye une autre version de ton code en allouant dynamiquement ta structure principale et en renvoyant un pointeur sur cet espace par le biais de ta fonction d'initialisation, les autres fonctions vu que tu passes un pointeur, tu n'as pas besoin de les modifier à priori. En tout cas c'est de cette manière que j'aurais également fait.

  8. #8
    Membre expert
    Avatar de kwariz
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Octobre 2011
    Messages
    898
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet en SSII
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2011
    Messages : 898
    Points : 3 352
    Points
    3 352
    Par défaut
    Bonzour,

    tu pourrais être clair plus quant à l'erreur (juste un segfault je suppose ? mais peut-être reçois-tu un message plus complet).
    as-tu essayé d'utiliser un outil comme valgrind pour cerner l'erreur (enfin si tu travailles sous linux) ?
    Ce serait bien de vérifier les retours des allocations.

    Sinon concernant la remarque de EdgarJacobs, oui la variable est «détruite» à la fin de la fonction. Je mets détruite entre guillemet car elle l'est dans le sens «la place est invalide par la suite et sera certainement réutilisée». C'est pourquoi il ne faut jamais retourner l'adresse d'une variable locale. Mais on peut tout à fait retourner la valeur de la variable locale, ici en l'occurrence c'est la valeur d'une structure est copiée ce qui est tout à fait légal.

  9. #9
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 677
    Points
    13 677
    Billets dans le blog
    1
    Par défaut
    Je rejoins kwariz et edgarjacobs : on ne doit jamais utiliser une variable créée localement dans une fonction en dehors de cette fonction. Franck H., ce n'est pas faux que la valeur de la variable peut-être accessible et même encore correct juste après le retour de la fonction. Cela n'est que du au hasard des écritures sur la pile et on ne doit jamais le prendre pour acquis.

    Ce problème est plus général que la simple question de la sortie d'une fonction : il s'agit d'un problème de scope des variables. On pourra consulter la norme C99 et les sections suivantes à ce sujet :
    • 6.2.1 Scopes of identifiers 1
    • 6.2.4 Storage durations of objects

    PLus globalement, la norme utilise à gogo le terme de scope ^^

  10. #10
    Nouveau membre du Club
    Homme Profil pro
    Lycéen
    Inscrit en
    Décembre 2012
    Messages
    46
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 27
    Localisation : Ile Maurice

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Décembre 2012
    Messages : 46
    Points : 31
    Points
    31
    Par défaut
    Bonjour, j'ai recommencé mon code en déclarant la variable Player comme ça *P. En effet je n'ai plus aucune erreur, et tout marche pour le mieux (enfin presque).

    Le nouveau 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
    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
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    #include "main.h"
    #include <SDL_image.h>
    #include <string.h>
     
    void UpdateEvents(Input *in)
    {
        SDL_Event event;
     
        in->mousebuttons[SDL_BUTTON_WHEELUP] = 0;
        in->mousebuttons[SDL_BUTTON_WHEELDOWN] = 0;
     
        while(SDL_PollEvent(&event))
        {
            switch(event.type)
            {
                case SDL_QUIT:
                    in->quit = 1;
                    break;
                case SDL_KEYDOWN:
                    in->key[event.key.keysym.sym] = 1;
                    break;
                case SDL_KEYUP:
                    in->key[event.key.keysym.sym] = 0;
                    break;
                case SDL_MOUSEMOTION:
                    in->mousex = event.motion.x;
                    in->mousey = event.motion.y;
                    in->mousexrel = event.motion.xrel;
                    in->mouseyrel = event.motion.yrel;
                    break;
                case SDL_MOUSEBUTTONDOWN:
                    in->mousebuttons[event.button.button] = 1;
                    break;
                case SDL_MOUSEBUTTONUP:
                    if(event.button.button != SDL_BUTTON_WHEELUP && event.button.button != SDL_BUTTON_WHEELDOWN)
                        in->mousebuttons[event.button.button] = 0;
                    break;
                default:
                    break;
            }
        }
    }
     
    SDL_Surface *InitSDL(int width, int height)
    {
        SDL_Surface *screen = NULL;
     
        if(SDL_Init(SDL_INIT_VIDEO) == -1)
        {
            fprintf(stderr, "%s", SDL_GetError());
            exit(-1);
        }
     
        if((screen = SDL_SetVideoMode(width, height, 32, SDL_HWSURFACE | SDL_DOUBLEBUF)) == NULL)
        {
            fprintf(stderr, "%s", SDL_GetError());
            exit(-1);
        }
     
        return screen;
    }
     
    SDL_Surface *LoadAdaptedIMG(const char IMG_FileName[])
    {
        SDL_Surface *IMG = NULL;
        SDL_Surface *IMG_Result = NULL;
     
        if((IMG = IMG_Load(IMG_FileName)) == NULL)
        {
            fprintf(stderr, "%s", SDL_GetError());
            exit(-1);
        }
     
        IMG_Result = SDL_DisplayFormat(IMG);
        SDL_FreeSurface(IMG);
     
        return IMG_Result;
    }
     
    void LoadCharset(Player *P, FILE *F)
    {
        int i, j;
        int frameNum;
        char charsetFileName[32] = {0};
     
        fscanf(F, "%s", charsetFileName);
        P->charset = LoadAdaptedIMG(charsetFileName);
        fscanf(F, "%d %d", &P->nbFramesCharsetX, &P->nbFramesCharsetY);
        P->Animations.R = malloc(P->nbFramesCharsetX*P->nbFramesCharsetY*sizeof(SDL_Rect));
     
        P->width = P->charset->w / P->nbFramesCharsetX;
        P->height = P->charset->h / P->nbFramesCharsetY;
     
        for(j = 0, frameNum = 0; j < P->nbFramesCharsetY; j++)
        {
            for(i = 0; i < P->nbFramesCharsetX; i++, frameNum++)
            {
                P->Animations.R[frameNum].x = i*P->width;
                P->Animations.R[frameNum].y = j*P->height;
                P->Animations.R[frameNum].w = P->width;
                P->Animations.R[frameNum].h = P->height;
            }
        }
    }
     
    void GetAnimationsInfo(Player *P, FILE *F)
    {
        int i;
     
        fscanf(F, "%d %d", &P->Animations.nbAnimations, &P->Animations.interval);
        if(!(P->Animations.List = malloc(P->Animations.nbAnimations*sizeof(AnimationList))))
        {
            fprintf(stderr, "Error can't allocate memory for P->Animations.List");
            exit(-1);
        }
        for(i = 0; i < P->Animations.nbAnimations; i++)
        {
            fscanf(F, "%d", &P->Animations.List[i].nbFrames);
            if(!(P->Animations.List[i].SequenceTable = malloc(P->Animations.List[i].nbFrames*sizeof(Sequence))))
            {
                fprintf(stderr, "Error can't allocate memory for P->Animations.List[%d].SequenceTable", i);
                exit(-1);
            }
        }
     
    }
     
    void GetAnimationsSequences(Player *P, FILE *F)
    {
        int i, j;
     
        for(j = 0; j < P->Animations.nbAnimations; j++)
        {
            for(i = 0; i < P->Animations.List[j].nbFrames; i++)
            {
                fscanf(F, "%d", &P->Animations.List[j].curentFrame);
                if(P->Animations.List[j].curentFrame >= P->nbFramesCharsetX*P->nbFramesCharsetY)
                {
                    fprintf(stderr, "Error curent frame is out of limit : %d", P->Animations.List[j].curentFrame);
                    exit(-1);
                }
                P->Animations.List[j].SequenceTable[i] = P->Animations.List[j].curentFrame;
            }
        }
    }
     
    Player *LoadPlayer(const char PlayerFileName[])
    {
        Player *P;
        FILE *F = NULL;
        char tag[32] = {0};
     
        if((F = fopen(PlayerFileName, "r")) == NULL)
        {
            fprintf(stderr, "Error can't open %s", PlayerFileName);
            exit(-1);
        }
     
        P = malloc(sizeof(Player));
     
        do
        {
            fscanf(F, "%s", tag);
            if(strstr(tag, "#charset_info"))
                LoadCharset(P, F);
            if(strstr(tag, "#animation_info"))
                GetAnimationsInfo(P, F);
            if(strstr(tag, "#animation_sequences"))
                GetAnimationsSequences(P, F);
        }while(strstr(tag, "#end") != NULL);
     
        fclose(F);
     
        return P;
    }
     
    int main(int argc, char* argv[])
    {
        SDL_Surface *screen = InitSDL(640, 480);
        Player *P = LoadPlayer("anim.txt");
        Input in;
        int i;
     
        memset(&in, 0, sizeof(in));
     
        SDL_SetColorKey(P->charset, SDL_SRCCOLORKEY, SDL_MapRGB(P->charset->format, 255, 0, 255));
     
        while(!in.quit && !in.key[SDLK_ESCAPE])
        {
            UpdateEvents(&in);
     
            SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 255, 255, 255));
            SDL_BlitSurface(P->charset, &P->Animations.R[0], screen, NULL);
     
            SDL_Flip(screen);
            SDL_Delay(5);
        }
     
        for(i = 0; i < P->Animations.nbAnimations; i++)
            free(P->Animations.List[i].SequenceTable);
        free(P->Animations.List);
        free(P->Animations.R);
        free(P);
     
        SDL_FreeSurface(P->charset);
        SDL_Quit();
     
        return 0;
    }
    Juste une dernière chose, dans ma boucle principale j'ai :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SDL_BlitSurface(P->charset, &P->Animations.R[0], screen, NULL);
    J'ai essayé de changer le second paramètre, comme ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SDL_BlitSurface(P->charset, &P->Animations.R[P ->Animations.List[0].SequenceTable[0]], screen, NULL);
    Le programme s'arrête à cette ligne, et j'ai encore un segmentation fault. C'est normal ? Je pensais que je pourrais récupérer la bonne valeur du tableau comme ça, mais pourtant non

    Edit :

    J'ai vérifié, et il semblerais que mes fonctions : GetAnimationsInfo(P, F); et GetAnimationsSequences(P, F); ne soient pas appelés. Pourquoi ? Pourtant j'ai pas fait d'erreurs pour mes balises.

    Mon fichier anim.txt:

    #charset_info
    charset_link.png
    7 4
    #animation_info
    4 100
    7 7 7 7
    #animation_sequences
    3 4 5 6 0 1 2
    10 11 12 13 7 8 9
    17 18 19 20 14 15 16
    24 25 26 27 21 22 23
    #end

    Edit encore une fois :

    Désolé, c'est de ma faute
    Dans la boucle qui se doit de charger, j'ai fait à la fin :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    while(strstr(tag, "#end") != NULL);
    Alors que c'est :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    while(strstr(tag, "#end") == NULL);

  11. #11
    Membre averti
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Juin 2012
    Messages
    257
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2012
    Messages : 257
    Points : 321
    Points
    321
    Par défaut
    Bonjour à tous,

    Je me permets d'ajouter un message pour une confirmation :

    Je suis tout à fait conscient que :
    il ne faut jamais retourner l'adresse d'une variable locale
    Cependant cette discussion m'a inquiété et je voudrais une confirmation pour :
    Mais on peut tout à fait retourner la valeur de la variable locale, ici en l'occurrence c'est la valeur d'une structure est copiée ce qui est tout à fait légal.
    Bktero, j'ai regardé la norme et je ne sais pas vraiment conclure, tu dis que tu rejoins kwariz et edgarjacobs mais il me semble qu'il ne disent pas exactement la même chose ?

    SVP rassurez-moi

    Est-ce que le problème initial de Halarp27 n'est pas lié au malloc et à "AnimationList *List" dans la structure retournée ?

  12. #12
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 389
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 389
    Points : 23 712
    Points
    23 712
    Par défaut
    Bonsoir à tous,

    Citation Envoyé par Halarp27 Voir le message
    L'erreur est à la ligne 195. L'allocation quand à elle se situe à la ligne 112. Je ne comprend vraiment pourquoi ça échoue. Sinon lorsque je fait free(&P.Animations.List), j'ai un warning : warning : attempt to free a non-heap object 'P'
    Il y a quand même une chose qui me chagrine : dans LoadPlayer(), tu n'initialises à aucun moment ta variable P avant de l'utiliser et les données membres de celles-ci peuvent prendre n'importe quelles valeurs en fonction de l'état de la mémoire où elles sont déclarées (il faudrait que P soit globale ou statique pour se retrouver dans le .bss et être automatiquement initialisée à zéro).

    Donc, si pour une raison ou une autre, ton fichier joueur omet de spécifier un des champs que tu attends, ton programme tournera normalement mais ce champ ne sera jamais initialisé, et tu n'auras aucun moyen de t'en rendre compte.

    Il faut donc mettre au préalable tous tes champs à NULL ou à zéro avant de commencer à remplir ta structure. En outre, tu devrais aussi vérifier leur valeur au moment de les libérer. La norme te garantit que free() acceptera silencieusement un NULL sans rien faire, mais rien ne te dit que ce sera aussi le cas avec SDL_FreeSurface().

    Bon courage.

  13. #13
    Membre expert
    Avatar de kwariz
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Octobre 2011
    Messages
    898
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet en SSII
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2011
    Messages : 898
    Points : 3 352
    Points
    3 352
    Par défaut
    @nanosoft
    même si c'est un poil hs
    En simplifiant : une struct c'est comme un type de base mais c'est plus gros.
    Par exemple sur un code comme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    int f(int a)
    {
      int local=a;
      local=local+1
      return b;
    }
     
    int main(void)
    {
      int x=10;
      int y=f(x);
      printf("x=%d\ny=%d\n", x, y);
      return 0;
    }
    la ligne y=f(x); provoquera d'abord la création d'une copie de x (sur la pile, dans un registre, ailleurs ... c'est ce qui est définit par l'ABI). Ensuite la fonction f va pouvoir manipuler cette copie. À la fin, la valeur de l'expression donnée au return est copiée quelque part (toujours dépendant de l'ABI) où l'appelant sait qu'il va pouvoir récupérer cette valeur. Cela fait pas mal de copies (parfois) mais comme souvent en C ce sont des type de base qui sont utilisés c'est extrêmement rapide.

    Voici le même code avec une structure :
    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
    struct s_int {
      int value;
    };
     
    struct s_int f(struct s_int a)
    {
      struct s_int local=a;
      local.value=local.value+1;
      return local;
    }
     
    int main(void)
    {
      struct s_int x={10};
      struct s_int y=f(x);
      printf("x=%d\ny=%d\n", x.value, y.value);
      return 0;
    }
    Et tout se passe de la même manière avec les mêmes copies ... Évidemment ça va prendre plus de temps pour copier une grande structure qu'un entier par exemple ou qu'un pointeur ... c'est une des principales raisons avancée pour éviter le passage par valeur de structure.

  14. #14
    Membre averti
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Juin 2012
    Messages
    257
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2012
    Messages : 257
    Points : 321
    Points
    321
    Par défaut
    Merci kwariz,

    Cela veut donc dire que le code donné en exemple par Franck est définitivement correct ?

    Pour tous : désolé d'insister en limite HS mais j'ai des fonctions qui retournent des structures et je voudrais absolument éclaircir :

    Tu vois, je ne serais pas si sûr
    Après tu as peut-être raison quant à la durée de vie des variables mais étant donné qu'elle n'est pas perdue car retournée par la fonction peut-être que cela change quelque chose, ça je n'en sais pas plus faut avouer

  15. #15
    Membre expert
    Avatar de kwariz
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Octobre 2011
    Messages
    898
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet en SSII
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2011
    Messages : 898
    Points : 3 352
    Points
    3 352
    Par défaut
    Oui il est correct.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 16
    Dernier message: 27/05/2017, 10h14
  2. malloc et free
    Par barthelv dans le forum C
    Réponses: 3
    Dernier message: 22/07/2003, 18h34
  3. mysqldump sur free
    Par bouba64 dans le forum Administration
    Réponses: 4
    Dernier message: 15/07/2003, 17h10
  4. tbitmap.free dans une function
    Par portu dans le forum Langage
    Réponses: 7
    Dernier message: 19/06/2003, 22h08

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