Mémoire dynamique et gestion d'erreur

Résolu
Polack77 Messages postés 1098 Date d'inscription mercredi 22 mars 2006 Statut Membre Dernière intervention 22 octobre 2019 - 31 août 2006 à 11:56
Polack77 Messages postés 1098 Date d'inscription mercredi 22 mars 2006 Statut Membre Dernière intervention 22 octobre 2019 - 4 sept. 2006 à 09:00
Bonjours, ma question serais que se passe t'il si je fais un
free sur un pointeur non défini (ou défini à 0).

    Je posse cette question (qui peut paraitre bizarre) car :


J'ai fais un programme pour une
veille machine qui n'à que peut de mémoire donc j'ai fais le choix d'allouer
dynamiquement ma mémoire uniquement quand j'en ai besoin et de la libérer dé
que le besoin ne s'en fais plus sentir. Problème je gère des erreurs, en faite
mon programme lit des fichiers qui ne sont pas forcement juste, et en cas
d'erreur mon programme dois se terminer (apprêt avoir écris un log, mais ce
n'est pas la question) je dois donc libérer toute la mémoire allouer avant de quitter (tout du moins
d'apprêt ce que je me rappel de mes cours). J'aurais voulut faire une procédure
globale en cas d'erreur et vue que je ne sais pas quand cette erreur vas ce
produire je ne sais pas quel vont être mes variable où j'ai alloué de la
mémoire ou non (à moins de crée un flag pour chaque’une mais si je peux
l'éviter ca m'arrange). Donc j'ai en idée de faire un "truc" du genre
:
#define MCR_TEST_ERREUR  if
(ErreurCode != 0) {EcritLog(ErreurCode);free(Var1);free(Var2);free(Var3);...;
return ErreurCode;}



Sachant que ma variable ou les erreurs sont stocker se nome toujours ErreurCode.



Admettons qu’à chaque fois que je fais un free je passe l'adrs contenu par mon
pointeur à 0. Que se passe-t-il si je fais un free dessus? Je pense que "free(0);"
cas ne fais rien mais en vrais je ne sais pas!


Pour le moment je considére que "free(0);" ne fais rien.



Sous UNIX (je précise mais je ne sais pas si cas change grand chose) que se
passe t'il quand je quitte mon appli sans faire tout les "free"? La
mémoire est rendue au system ou non? Et sous Windows?


Merci

Ce soir dans "triste monde tragique" :

Des vers qui mangent les programmeurs !
Des virus sorte des ordinateurs et attaque des gents !

13 réponses

luhtor Messages postés 2023 Date d'inscription mardi 24 septembre 2002 Statut Membre Dernière intervention 28 juillet 2008 6
31 août 2006 à 12:45
Avec Xp, il rattrape les conneries et libèrent (en principe) toute la
mémoire alloué dynamiquement. Je suppose que sous unix, ca doit etre
pareil.


Mais pour etre sur que ton programme libère toute la mémoire. Tu peux par exemple crééer de nouvelles fonctions d'allocations:

my_malloc(...) et my_free(...) qui en plus de faire appel a malloc et
free, stocke dans une liste l'ensemble des variables dynamiques. Comme
ca a tout moment, tu sais ce qu'à alloué ton programme et s'il reste
des variables non libérées. Et en cas d'erreur, suffit de détruire tous
les pointeurs contenu dans la liste.
3
luhtor Messages postés 2023 Date d'inscription mardi 24 septembre 2002 Statut Membre Dernière intervention 28 juillet 2008 6
31 août 2006 à 13:59
Mais avec ma méthode, tu fais une fonction:

FreeAll();

qui libère tous les pointeurs de la liste. Car avec ta macro, a chaque
fois que tu rajoutes une variable, faut aller modifier ta macro, alors
que si tu utilises une liste. Ya plus de soucis.
3
Polack77 Messages postés 1098 Date d'inscription mercredi 22 mars 2006 Statut Membre Dernière intervention 22 octobre 2019 1
31 août 2006 à 16:48
Ca à été un peut long j'ai hu autre chose à faire entre
temps, désolé si quelqu'un attendais apprêt ces fonction.

En final j'ai fais une liste chainer pour stocker les ards allouer (je trouvais
ca plus pratique)

Désolé si il y à des faute d'orthographe je n'ai pas pris le temps de les corriger.



struct StrcutMemoireAllouer
{
    void * AdresseAlouer;
    struct StrcutMemoireAllouer * Suivant;
};

struct StrcutMemoireAllouer * MemoireAllouer = 0;

void * MyMalloc (size_t QuantiteMemoire)
{
void * Tempon;
struct StrcutMemoireAllouer * EnCours;
    Tempon = malloc(QuantiteMemoire);
    if (MemoireAllouer == 0) //Si 1ér allocation
    {
        MemoireAllouer = (struct StrcutMemoireAllouer*)malloc(sizeof(struct StrcutMemoireAllouer)); //crée le 1ér maillon
        (*MemoireAllouer).Suivant = 0; //initialise le pointeur vers suivant
        (*MemoireAllouer).AdresseAlouer = Tempon; //sauvgarde l'adrs retourner
    }
    else //si déja des alocation présante
    {
        EnCours = MemoireAllouer; //pointe le 1ér maillon de la chaine
        while ((*EnCours).Suivant != 0) //temps que l'on est pas à au dernier maillon
        {
            EnCours = (*EnCours).Suivant; //passe au maillon suivant
        }
        (*EnCours).Suivant = (struct StrcutMemoireAllouer*)malloc(sizeof(struct StrcutMemoireAllouer)); //aloue un nouveau maillon
        (*(*EnCours).Suivant).AdresseAlouer = Tempon; //Sauvgarde l'adrs allouer à la variable
        (*(*EnCours).Suivant).Suivant = 0; //marque le maillon comme étant le dernier
    }
    return Tempon; //renvoie l'adrs de la variable alouer
}

ErreurCode MyFree (void * AdresseALiberer)
{
struct StrcutMemoireAllouer * EnCours;
struct StrcutMemoireAllouer * Tempon;
    if (MemoireAllouer == 0) //Si la chaine n'existe pas
    {
        free(AdresseALiberer); //Libére le mémoire passée en paramétre
        return 999; //retourne un code d'erreur
    }    Tempon EnCours MemoireAllouer; //Initialise les variable

    while (AdresseALiberer != (*EnCours).AdresseAlouer) //temps que l'ards n'est pas celle du maillon en cours
    {
        if ((*EnCours).Suivant == 0) //si on est dans le dernier maillon
        {
            free(AdresseALiberer); //Libére le mémoire passée en paramétre
            return 999; //retourne un code d'erreur
        }
        Tempon = EnCours; //on sauvgarde l'adresse de ce maillon
        EnCours = (*EnCours).Suivant; //on passe au suivant
    }

    if (EnCours == MemoireAllouer) //si 1ér maillon de la chaine
    {
        if ((*MemoireAllouer).Suivant == 0) //si pas d'autre maillon
        {
            free(MemoireAllouer); //libére la mémoire du 1ér maillon
            MemoireAllouer = 0; //marque le pointeur commme chaine inexistante
        }
        else //si dautre mallon
        {
            free(MemoireAllouer); //on libére le maillon en cours
            MemoireAllouer = (*EnCours).Suivant; //Le pointeur global pointe le suivant
        }
    }
    else //si au moin un autre maillon
    {        (*Tempon).Suivant (*EnCours).Suivant; //on ne pointe plus vers ce maillon et si le maillon en cours est le dernier alors la donnée Suivant 0
        free(EnCours); //On libére le maillon en cours
    }
    free(AdresseALiberer); //Libére le mémoire passée en paramétre
    return 0;
}

void MyFeeeAll (void)
{
struct StrcutMemoireAllouer * EnCours;
struct StrcutMemoireAllouer * Tempon;
    if (MemoireAllouer != 0) //Si la chaine existe
    {        Tempon EnCours MemoireAllouer; //Pointe le 1ér maillon
        do
        {
            free((*EnCours).AdresseAlouer); //Libére la mémoire alouer à une variable
            EnCours = (*EnCours).Suivant; //Passe au maillon suivant
            free (Tempon); //Libére le maillon présedant
            Tempon = EnCours; //Passe le tempon au maillon suiant
        }while ((*EnCours).Suivant != 0); //Temps que le dernier maillon n'a pas été libérer
    }
}

Ce soir dans "triste monde tragique" :

Des vers qui mangent les programmeurs !
Des virus sorte des ordinateurs et attaque des gents !
3
Polack77 Messages postés 1098 Date d'inscription mercredi 22 mars 2006 Statut Membre Dernière intervention 22 octobre 2019 1
31 août 2006 à 16:57
Heeeeeeeeee, oups. J'ai fais une faute dans la déclaration de MyFreeAll!!!
Voila la version corigé (en même temps c'est pas grand chose)

void MyFreeAll
(void)
{
struct StrcutMemoireAllouer * EnCours;
struct StrcutMemoireAllouer * Tempon;
    if (MemoireAllouer != 0) //Si la chaine existe
    {        Tempon EnCours MemoireAllouer; //Pointe le 1ér maillon
        do
        {
            free((*EnCours).AdresseAlouer); //Libére la mémoire alouer à une variable
            EnCours = (*EnCours).Suivant; //Passe au maillon suivant
            free (Tempon); //Libére le maillon présedant
            Tempon = EnCours; //Passe le tempon au maillon suiant
        }while ((*EnCours).Suivant != 0); //Temps que le dernier maillon n'a pas été libérer
    }
}

Ce soir dans "triste monde tragique" :

Des vers qui mangent les programmeu
3

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Polack77 Messages postés 1098 Date d'inscription mercredi 22 mars 2006 Statut Membre Dernière intervention 22 octobre 2019 1
31 août 2006 à 13:39
OUI!!! C'est une bonne idée!

Je vais peut être faire comme ca.


Si non j'y est repensé en mangeant et je me
suis dit que je peut aussi faire comme ca :

#define MCR_TEST_ERREUR  if (ErreurCode != 0) {EcritLog(ErreurCode);
if(Var1!=0){free(Var1);} if(Var2!=0){free(Var2);} if(Var3!=0){free(Var3);} ...;
return ErreurCode;}

Mais je ne trouvais pas cas claire à la lecture. A moins de faire cas :

#define MCR_TEST_ERREUR \

    if (ErreurCode != 0)\

    {\

        EcritLog(ErreurCode);\

        if(Var1!=0)\

        {\

            free(Var1);\

        }\

        if(Var2!=0)\

        {\

            free(Var2);\

        }\

        if(Var3!=0)\

        {\

            free(Var3);\

        }\

        ...;\

        return ErreurCode;\

    }

Mais là je trouve cas lourd (oui je sais je suis chiant) donc je ne sais pas encor vraiment comment je vais
faire cas!


La question : que fais "free(0);" reste ouverte, je trouve que si cas
ne fais rien c'est le mieux (la définition n'est pas illisible ni lourde, tout
du moins comme je le vois)









Ce soir dans "triste monde tragique" :


Des vers qui mangent les programmeurs !
Des virus sorte des ordinateurs et attaque des gents !
0
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
31 août 2006 à 13:52
Faut remettre à ZERO tes pointeurs si tu veux les tester:

void *pmem = 0;
....
....
pmem = malloc(...);
...
...
if(pmem) {free(pmem); pmem = 0;}

ciao...
BruNews, MVP VC++
0
Polack77 Messages postés 1098 Date d'inscription mercredi 22 mars 2006 Statut Membre Dernière intervention 22 octobre 2019 1
31 août 2006 à 14:05
Bà oui c'est noté dans le 1ér post. En faite pour le moment après
chaque free je fais passée le pointeur à 0.

Pour le moment je considère que free(0) ne fais rien mais je veux savoir si ca
ne fais vraiment rien pour éviter d'avoir à le tester car je ne trouve pas ca
propre (voir mon 2ém post).

Merci quand même BruNews


Effectivement luhtor je commence à moi aussi pensé que ta solution est la mieux.


J'aimerais savoir quand même que fais free(0); je n'aime pas rester sur ma faim
(et puis si free(0) ne fais rien tout est déjà fais alors...).







Ce soir dans "triste monde tragique" :


Des vers qui mangent les programmeu
0
Polack77 Messages postés 1098 Date d'inscription mercredi 22 mars 2006 Statut Membre Dernière intervention 22 octobre 2019 1
31 août 2006 à 14:26
Je viens de relire mon code et je vais choisir la solution
de luhtor (merci) en fessant 3 fonction :

- MyMalloc : qui alloue de la mémoire en fonction du nombre d'octet demandé,
retourne l'adrs de cette mémoire et la stocke dans un tableau global dynamique
(vois pas comment faire autrement) l'ensemble des adrs allouer par lui.

- MyFree : qui libère la mémoire passée en argument et supprime la 'case' du
tableau (elle retournera également un code d'erreur si la mémoire libérer n'appartiens
pas au tableau, heeeeeeeee je réalise que ce point vas être chiant si ca
arrive, cas ne dois pas arriver et pi c'est tout!!!)

- MyFreeAll : qui libère l'ensemble de la mémoire d'ont les adrs sont stocker
dans mon tableau


Comme ca je peux ajouter/supprimer des variables sans me prendre la tête (comme
le disais luhtor).


Merci à tous!







Ce soir dans "triste monde tragique" :


Des vers qui mangent les programmeurs !
Des virus sorte des ordinateurs et attaque des gents !
0
luhtor Messages postés 2023 Date d'inscription mardi 24 septembre 2002 Statut Membre Dernière intervention 28 juillet 2008 6
31 août 2006 à 15:32
"un tableau global dynamique" => oue c'est pas terrible. En C++, on
pourrait faire mieux, mais bon. D'autant plus qu'en C++, tu pourrais
utiliser les conteneurs de la stl. Décidemment, je comprends pas pk on
programme encore en C :)
0
Polack77 Messages postés 1098 Date d'inscription mercredi 22 mars 2006 Statut Membre Dernière intervention 22 octobre 2019 1
31 août 2006 à 15:37
Moi non plus (je ne comprends pas pourquoi on programme
encore en C) mais c'est hélas pas moi qui choisi. Je mettrais (ici dans un
post) mes fonctions dé que je les ais fini et tester.







Ce soir dans "triste monde tragique" :


Des vers qui mangent les programmeurs !
Des virus sorte des ordinateurs et attaque des gents !
0
cs_JCDjcd Messages postés 1138 Date d'inscription mardi 10 juin 2003 Statut Membre Dernière intervention 25 janvier 2009 4
1 sept. 2006 à 17:43
je m'excuse de m'introduire dans cette passionnante conversation mais
je ne suis pas d'accord sur l'utilisation : je m'explique :
moi j'ai mes fonctions my_malloc et my_free
cependant a la fin du programme si il y a une bloc memoire
non desalloue, alors j'affiche une erreur, car je considere
que c'est un BUG du programme, et je pense que c'est pas
une bonne solution de faire un freeAll, car ca ne resoudera pas le probleme
Avec un code bien ecrit, on sait tres bien quand il faut le libere, et
si a la fin il en reste, c'est que le code est mal concu, et que donc
un vrai bug se cache.
Par exemple, dans ma source ou j'ai compare les huffmans de ce site,
j'ai fliquer toutes les allocations, et la plus part du temps, ca cachait
une autres bugs.
Donc je pense que c'est vicieux de dire, il faut faire un freeAll, c'est
contourner le probleme, mais s'il est resolu, à savoir que le programme
libere tous le monde. Il ne faut pas avoir peur de se dire que son code
est mal concu, et qu'il faut ameliorer l'organisation pour liberer
QUAND IL LE FAUT la memoire.
Donc je voulais vous faire part de mon desaccord de point de vu
(c'est pour cela qu'il y a plein de "Je" ...)

Pour reprendre les termes de luthor :
il ne faut surtout pas "RATTRAPER" les betises, mais les CORRIGER,
et je pense que programmer, c'est DEBUGGER son code,
ce qui releve plutot de la correction plutot que du rattrapage

Pourquoi faire simple quand on peut faire compliqué ?
0
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
1 sept. 2006 à 18:00
Fort exact tout cela.
Un code 'rattrapé' n'est qu'un brouillon qu'il faut retravailler pour arriver à un code correct.

ciao...
BruNews, MVP VC++
0
Polack77 Messages postés 1098 Date d'inscription mercredi 22 mars 2006 Statut Membre Dernière intervention 22 octobre 2019 1
4 sept. 2006 à 09:00
<!--[if gte vml 1]><v:shapetype
id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t"
path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f">
<v:stroke joinstyle="miter"/>
<v:formulas>
<v:f eqn="if lineDrawn pixelLineWidth 0"/>
<v:f eqn="sum @0 1 0"/>
<v:f eqn="sum 0 0 @1"/>
<v:f eqn="prod @2 1 2"/>
<v:f eqn="prod @3 21600 pixelWidth"/>
<v:f eqn="prod @3 21600 pixelHeight"/>
<v:f eqn="sum @0 0 1"/>
<v:f eqn="prod @6 1 2"/>
<v:f eqn="prod @7 21600 pixelWidth"/>
<v:f eqn="sum @8 21600 0"/>
<v:f eqn="prod @7 21600 pixelHeight"/>
<v:f eqn="sum @10 21600 0"/>
</v:formulas>
<v:path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect"/>
<o:lock v:ext="edit" aspectratio="t"/>
</v:shapetype><v:shape id="_x0000_i1025" type="#_x0000_t75" alt="" style='width:11.25pt;
height:11.25pt'>
<v:imagedata src="file:///C:\DOCUME~1\VIW\LOCALS~1\Temp\msohtml1\01\clip_image001.gif"
o:href="/imgs2/smile_cool.gif"/>
</v:shape><![endif]-->
<!--[if !vml]-->
<!--[endif]-->
<!--[if gte vml 1]><v:shape id="_x0000_i1026"
type="#_x0000_t75" alt="" style='width:11.25pt;height:11.25pt'>
<v:imagedata src="file:///C:\DOCUME~1\VIW\LOCALS~1\Temp\msohtml1\01\clip_image001.gif"
o:href="/imgs2/smile_cool.gif"/>
</v:shape><![endif]-->
<!--[if !vml]-->
<!--[endif]-->
<!--[if gte vml 1]><v:shape id="_x0000_i1027"
type="#_x0000_t75" alt="" style='width:11.25pt;height:11.25pt'>
<v:imagedata src="file:///C:\DOCUME~1\VIW\LOCALS~1\Temp\msohtml1\01\clip_image001.gif"
o:href="/imgs2/smile_cool.gif"/>
</v:shape><![endif]-->
<!--[if !vml]-->
<!--[endif]-->Je suis tout à fais d'accord sur ce qu'à dit JCDjcd mais je
n'ai pas fais ce code pour faire un FreeAll en fin de programme mais en cas
d'erreur (je fais de l'allocation dynamique dans tout les sens, des fonctions alloue d'autre libères, et même si je libère
bien ma mémoire dans le cas ou le fichier que je traite est correct, ce n'est
pas forcément le cas si une erreur se glisse dans mon fichier, et à vrais dire
cas me fessais chi.. de faire une gestion d'erreur pour chaque cause d'erreur)
je l'ai utilisé c'est vrais pour vérifier que je ne laissais pas de variable en
mémoire à la fin de mon programme (ce qui été la cas ) mais maintenant ca m'évite d'avoir une
macro de gestion d'erreur qui fais 25/30 lignes (à la place elle en 3, c'est
quand même plus agréable).

Heeeeeee, si non une question reste en suspend : Que se passe t'il si je fais :
"free(0);".


PS : JCDjcd ne t'excuse pas d'apporté ton havie et tes idée à cette discutions
elle n'en sera qu'enrichi.







Ce soir dans "triste monde tragique" :


Des vers qui mangent les programmeurs !
Des virus sorte des ordinateurs et attaque des gents !
0
Rejoignez-nous