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 :

Initiale allocation de mémoire


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Inscrit en
    Mai 2007
    Messages
    52
    Détails du profil
    Informations personnelles :
    Âge : 46

    Informations forums :
    Inscription : Mai 2007
    Messages : 52
    Par défaut Initiale allocation de mémoire
    Bonsoir à toutes et à tous,

    Me voici une fois de plus confronté à un problème dont j'ignore encore la raison. Tout d'abord, le code simplifié:

    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
     
    typedef struct
    {
    	float x;
    	float y;
    	float z;
    } coordinates;
    unsigned short coord_size  = sizeof(coordinates);
     
    char PDBFileName[250];
    unsigned int maxNbPDBFiles = 60;
    unsigned int nbResidues = 59;
    unsigned int nbPDBFiles = 0;
    coordinates **atomCoords = malloc (maxNbPDBFiles * sizeof(coordinates *));
     
    FILE *PDBListFile, *PDBFile;  // PDBListFile contient une liste de fichiers qui seront ouvert grâce à PDBFile
     
    if ((PDBListFile = fopen(argv[PDBListFileNb], "r")) != NULL)
    {
        fgets(PDBFileName, 250, PDBListFile);
        while (!feof(PDBListFile))
        {
            if (PDBFileName[strlen(PDBFileName)-1] == '\n') PDBFileName[strlen(PDBFileName)-1] = '\0';
            if ((PDBFile = fopen(PDBFileName, "rt")) != NULL)
            {
                if (nbPDBFiles == maxNbPDBFiles)
                {
                    printf ("\n\n\n\n\nREALLOCATION OF atomCoords\n\n\n\n\n");
                    maxNbPDBFiles += 100;
                    if ((atomCoords = realloc (atomCoords, maxNbPDBFiles * sizeof(coordinates *))) == NULL) fatal_error("MEMORY", "extend the size of atomCoords variable");
                }
                printf("\n\nnbPDBFiles = %u\t\tnbResidues = %u (%u)\n", nbPDBFiles, nbResidues, coord_size);
                atomCoords[nbPDBFiles] = malloc(nbResidues * coord_size);
     
                fgets(PDBFileLine, 79, PDBFile);
                while (!feof(PDBFile))
                {
                    /* Là, nous lisons le fichier PDBFileName.
                       Ce dernier contient 59 lignes (d'où la valeur de la variable nbResidues),
                       chacune des lignes contenant 3 valeurs (float): x, y et z.
                       Chacune de ces valeurs est enregistrée dans la variable atomCoords[nbPDBFiles].*/
                    [...]
                    fgets(PDBFileLine, 79, PDBFile);
                }
                fclose(PDBFile);
            }
            fgets(PDBFileName, 250, PDBListFile);
        }
    }
    Maintenant, le problème que j'ai découvert en utilisant Valgrind.
    Quand j'utilise pour la variable maxNbPDBFiles une valeur d'initialisation strictement inférieure à 60, aucun problème n'est rencontré. J'ai les lignes suivantes qui s'affiche:

    nbPDBFiles = 1 nbResidues = 59 (12)
    nbPDBFiles = 2 nbResidues = 59 (12)
    nbPDBFiles = 3 nbResidues = 59 (12)
    nbPDBFiles = 4 nbResidues = 59 (12)
    [Je passe là le superflu...]
    nbPDBFiles = 57 nbResidues = 59 (12)
    nbPDBFiles = 58 nbResidues = 59 (12)
    nbPDBFiles = 59 nbResidues = 59 (12)
    nbPDBFiles = 60 nbResidues = 59 (12)
    nbPDBFiles = 61 nbResidues = 59 (12)
    nbPDBFiles = 62 nbResidues = 59 (12)
    [Le reste se déroule de la même façon, sans souci...]
    Maintenant, si j'utilise une valeur d'initialisation d'au moins 60, et ce, SANS NE RIEN TOUCHER D'AUTRE AU PROGRAMME, Valgrind me sort:
    nbPDBFiles = 1 nbResidues = 59 (12)
    nbPDBFiles = 2 nbResidues = 59 (12)
    nbPDBFiles = 3 nbResidues = 59 (12)
    [Je passe là le superflu...]
    nbPDBFiles = 57 nbResidues = 59 (12)
    nbPDBFiles = 58 nbResidues = 59 (12)
    nbPDBFiles = 59 nbResidues = 59 (12)
    ==6323== Invalid write of size 4
    ==6323== at 0x8048EB6: main (contact_map.c:101)
    ==6323== Address 0x40282D4 is 0 bytes after a block of size 236 alloc'd
    ==6323== at 0x4005622: realloc (vg_replace_malloc.c:306)
    ==6323== by 0x80496A0: main (contact_map.c:202)
    ==6323==
    ==6323== Invalid read of size 4
    ==6323== at 0x8049060: main (contact_map.c:140)
    ==6323== Address 0x40282D4 is 0 bytes after a block of size 236 alloc'd
    ==6323== at 0x4005622: realloc (vg_replace_malloc.c:306)
    ==6323== by 0x80496A0: main (contact_map.c:202)
    ==6323==
    ==6323== Invalid read of size 4
    ==6323== at 0x8049091: main (contact_map.c:142)
    ==6323== Address 0x40282D4 is 0 bytes after a block of size 236 alloc'd
    ==6323== at 0x4005622: realloc (vg_replace_malloc.c:306)
    ==6323== by 0x80496A0: main (contact_map.c:202)
    ==6323==
    ==6323== Invalid read of size 4
    ==6323== at 0x80490C3: main (contact_map.c:144)
    ==6323== Address 0x40282D4 is 0 bytes after a block of size 236 alloc'd
    ==6323== at 0x4005622: realloc (vg_replace_malloc.c:306)
    ==6323== by 0x80496A0: main (contact_map.c:202)
    --6323-- REDIR: 0xC81400 (mempcpy) redirected to 0x4006B70 (mempcpy)
    nbPDBFiles = 60 nbResidues = 59 (12)
    nbPDBFiles = 61 nbResidues = 59 (12)
    nbPDBFiles = 62 nbResidues = 59 (12)
    Le pire, c'est que, dans ce cas, ça aboutit à une erreur de segmentation lors de la lecture de ma variable atomCoords tout à la fin de mon programme, une fois que toutes les valeurs ont été enregistrées!

    Si quelqu'un a la moindre idée de ce qui se passe là, je suis preneur.

    Merci par avance,
    Mickaël

  2. #2
    Membre Expert
    Profil pro
    Inscrit en
    Août 2006
    Messages
    1 104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 1 104
    Par défaut
    Salut

    Je n'ai pas analysé le code en détail. J'ai simplement remarqué deux choses qui sont pas terribles. Je ne dis pas que ça a un rapport avec ton problème, mais c'est important.

    Premièrement, c'est l'utilisation de feof. Cette fonction ne fait pas ce qu'on croit généralement. On peut utiliser cette fonction uniquement lorsqu'une fonction de lecture a échoué, afin de s'assurer que l'échec de lecture de la fonction est bien lié à une fin de fichier et non à un autre problème.
    Lors de la lecture d'un fichier, pour s'assurer que la fonction a bien lu quelque chose (i.e. que la fin du fichier n'est pas encore arrivée), il faut donc utiliser sa valeur retour et non la fonction feof. Si sa lecture échoue, là on peut utiliser feof pour vérifier l'origine du problème.

    Deuxième chose :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if ((atomCoords = realloc (atomCoords, maxNbPDBFiles * sizeof(coordinates *))) == NULL) fatal_error("MEMORY", "extend the size of atomCoords variable");
    Si la fonction échoue, tu provoques une fuite de mémoire. Deux options, au choix :
    1) Le programme crashe 3 lignes plus loin. Pas top.
    2) Admettons que fatal_error termine lui-même le programme (je ne fais que supposer, je ne sais pas ce que fait cette fonction ), ce n'est pas propre, car le programme doit libérer toute la mémoire qu'il a lui même allouée. Pas top non plus.
    Dans les deux cas, il y a donc un soucis.

  3. #3
    Membre averti
    Inscrit en
    Mai 2007
    Messages
    52
    Détails du profil
    Informations personnelles :
    Âge : 46

    Informations forums :
    Inscription : Mai 2007
    Messages : 52
    Par défaut
    Salut Jeroman,

    Merci pour ton intervention et tes remarques pertinentes!

    Pour la macro feof, je suis d'accord avec toi. J'aurais du implémenter un truc du genre: while(fgets( ... ) != NULL) et après seulement cette boucle tester que la fin du fichier a bien été atteinte.

    Par contre, pour la seconde remarque, je ne vois pas trop où est le problème. En fait, ma fonction fatal_error stoppe en effet le programme, mais en même temps libère, grâce à la fonction free, TOUTES les variables dynamiques qui ont été créées avec malloc ou realloc jusque là (Chose facile à faire quand une variable globale contient l'adresse mémoire de toutes les variables dynamiques).

    Euh... Sinon, des idées géniales pour mon problème pour le moins "prise de tête" ? :p

    Mickaël

  4. #4
    Modérateur
    Avatar de gangsoleil
    Homme Profil pro
    Manager / Cyber Sécurité
    Inscrit en
    Mai 2004
    Messages
    10 150
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Manager / Cyber Sécurité

    Informations forums :
    Inscription : Mai 2004
    Messages : 10 150
    Par défaut
    Bonjour,

    Citation Envoyé par mkrzemin Voir le message
    Par contre, pour la seconde remarque, je ne vois pas trop où est le problème. En fait, ma fonction fatal_error stoppe en effet le programme, mais en même temps libère, grâce à la fonction free, TOUTES les variables dynamiques qui ont été créées avec malloc ou realloc jusque là
    Si realloc echoue, elle retourne NULL. Donc ton atomCoords sera affecte a NULL, et la memoire precedemment allouee est perdue. Tu ne peux plus la liberer, a moins d'avoir garde un pointeur dessus.

    Deux solutions :
    soit tu gardes un pointeur dessus, et en cas d'echec, tu liberes ce pointeur.
    Soit tu realloues la memoire vers un autre pointeur (temporaire), et en cas de succes, tu fais pointer atomCoords vers la nouvelle zone memoire (le pointeur temporaire etant automatiquement supprime a la fin du bloc).
    "La route est longue, mais le chemin est libre" -- https://framasoft.org/
    Les règles du forum

  5. #5
    Modérateur
    Avatar de gangsoleil
    Homme Profil pro
    Manager / Cyber Sécurité
    Inscrit en
    Mai 2004
    Messages
    10 150
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Manager / Cyber Sécurité

    Informations forums :
    Inscription : Mai 2004
    Messages : 10 150
    Par défaut
    Bonjour,

    Comme explique, tu ne lis pas vraiment les donnees

    Sinon, tu as probablement un probleme ici :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
                atomCoords[nbPDBFiles] = malloc(nbResidues * coord_size);
    Tu fais une unique allocation, de la cellule numero nbPDBFiles. Ne souhaiterais-tu pas faire nbPDBFiles allocations ? Et il serait aussi bon de tester que chacune s'est bien deroulee, sous peine de plantage.
    "La route est longue, mais le chemin est libre" -- https://framasoft.org/
    Les règles du forum

  6. #6
    Expert confirmé
    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
    Par défaut
    Tout d'abord, le code simplifié:
    Le code simplifié montre t-il effectivement ce défaut ? L'as-tu testé ?

    Ce qui est bizarre, c'est que Valgrind met en cause un bloc alloué de 236 bytes, pas du tout un bloc de maxNbPDBFiles pointeurs. Si tes pointeurs font 4 bytes, le bloc alloué fait 236 = 4*59 bytes soit une allocation de 59 pointeurs (nbResidues pointeurs ???).

    Le code fautif n'est-il pas en fait par erreur
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    coordinates **atomCoords = malloc (nbResidues * sizeof(coordinates *));

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

Discussions similaires

  1. [debutant] : Allocation de mémoire dynamique
    Par sam.fet dans le forum Langage
    Réponses: 5
    Dernier message: 15/02/2006, 14h58
  2. Problème d'allocation de mémoire dans la pile
    Par prophet666 dans le forum x86 32-bits / 64-bits
    Réponses: 6
    Dernier message: 19/01/2006, 02h22
  3. [Debutant]Allocation de mémoire
    Par gwendal84 dans le forum C
    Réponses: 6
    Dernier message: 07/12/2005, 19h04
  4. Double allocation de mémoire
    Par hunter001 dans le forum C++
    Réponses: 16
    Dernier message: 25/08/2005, 13h53
  5. pb d'allocation de mémoire
    Par shura dans le forum C
    Réponses: 7
    Dernier message: 17/04/2005, 21h10

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