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

  1. #1
    Nouveau membre du Club
    Peut-on libérer la mémoire avec free quand on a pas défini un pointeur au départ?
    Bonjour

    Je cherche à savoir s'il est possible de libérer la mémoire occupée par une variable lorsqu'on a créé cette variable de manière «directe» (sans passer par un pointeur).
    Un code pour illustrer:

    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
    int main(int argc, char *argv[])
    {
            // Premier bloc d'instructions.
    	int *a; 
    	a = malloc (sizeof(int)); // En une seule ligne int *a = malloc (sizeof(int)); ça va aussi.
    	printf("L'adresse de a, c'est à dire l'adresse du pointeur sur *a  est %p. \n", &a);
    	printf("L'adresse de *a, c'est a dire a est %p. \n", a);
    	*a = 25;
    	printf("*a = %d. \n", *a);	
    	free(a); // Ca marche (pas de message d'erreur).	
     
     
    	// Deuxième bloc d'instructions.
    	int *b;
    	printf("L'adresse de b, c'est à dire l'adresse du pointeur sur *b  est %p. \n", &b);
    	printf("L'adresse de *b, c'est a dire b est %p. \n", b);
    	*b = 75;
    	printf("*b = %d. \n", *b);	
    	free(b); // Ca ne marche pas
    	// A l'exectuion -> Erreur de segmentation (core dumped)
     
     
    	/*// Troisième bloc d'instructions.
    	int c = 5;
    	free(&c); // Ca ne marche pas. 
    	//A la compilation ->  "warning: attempt to free a non-heap object ‘b’ [-Wfree-nonheap-object]"*/
    }


    Dans le troisième bloc d'instruction je crée la variable c de manière «directe» mais quand j'applique la fonction «free» à &c ça ne marche pas. Pourtant &c est un pointeur non? Savez vous comment je devrais faire ici?

    J'en profite pour vous demander ce que vous pensez du deuxième bloc d'instruction. J'ai oublié d'attribuer de la mémoire à b, et pourtant je peut attribuer une valeur à *b. Vous en pensez quoi? C'est normal?

    Merci à qui pourra répondre. :-)

  2. #2
    Expert éminent
    Citation Envoyé par Obofix le gaulois Voir le message
    Pourtant &c est un pointeur non? Savez vous comment je devrais faire ici?
    Oui mais la variable c est créée sur la pile ... non sur le tas

  3. #3
    Expert éminent sénior
    free ne libère pas un pointeur, mais le bloc mémoire issu du tas désigné par un pointeur.

    En fait, les pointeurs en eux même n'ont rien à voir avec free et malloc.

    Les pointeurs sont des variables contenant une adresse l'adresse d'un bloc mémoire à traiter comme d'un type donnée.
    Ainsi, int *p; déclare en gros "soit de type entier ce que désigne p". p peut contenir n'importe quelle adresse d'un entier.

    Une adresse s'obtient comme la valeur d'un autre pointeur, ou par l'application de l'opérateur & (unaire) sur quelque chose qui existe en mémoire (pas la valeur 2, par exemple) et du bon type.


    Les fonctions free et malloc utilisent un pointeur (en argument ou en valeur de retour, respectivement).

    malloc réclame au système un bloc mémoire venant du "tas" ("heap"), et free libère un tel bloc (le système est averti qu'il peut s'en servir pour autre chose).

    Ces transitions entre l'état "alloué" et l'état "libre" doivent être faite proprement: un même bloc ne doit jamais évoluer deux fois dans le même sens.

    Tout bloc alloué doit être libéré. Dans le cas contraire, on parle de fuite mémoire: certains blocs mémoires cessent d'être disponible, amenant à des crash de type "out of memory"
    Seul un bloc alloué peut être libéré. Dans le cas contraire, tu rencontres un message du type "double free or corruption".

    L'énorme problème des allocations dynamiques, c'est donc de proprement gérer les pointeurs.
    Pour ne pas perdre l'adresse des blocs à libérer, on devrait toujours libérer de manière symétrique: soit dans le même bloc, soit par une paire de fonctions symétriques (à la façon de fopen et fclose qui manipulent des pointeurs de fichiers).
    Pour ne pas les conserver trop longtemps, il convient de toujours remettre à NULL un pointeur qui est libéré (à moins qu'on sorte immédiatement de son bloc de définition)
    Le premier
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  4. #4
    Expert éminent sénior
    J'ai oublié de rappeler qu'en temps normal, une variable est uniquement définie dans le bloc contenant sa définition.
    Sa mémoire (issue de la pile) est automatiquement libérée à la sortie du bloc.
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  5. #5
    Nouveau membre du Club
    Merci beaucoup pour vos réponses. Je n'avais pas bien conscience qu'on faisait appel à deux mémoires différentes ici. J'en avais très brièvement entendu parlé en étudiant C++ il y a plusieurs années mais ce n'était pas clair pour moi à l'époque.

    Les choses sont plus claires, merci bien.

###raw>template_hook.ano_emploi###