Les pointeurs en C

a marqué ce sujet comme résolu.

Bonjour,

J’étudie actuellement les pointeurs et je n’arrive pas à saisir ce qu’il se passe dans ce code à la ligne 15 :

#include <stdio.h>
#include <stdlib.h>

void my_print(int* p)
{
    printf("p contient l'adresse %p et à cette adresse se trouve la valeur %i\n", p, *p);
}

int main()
{
    int* p = malloc(sizeof(int));
    *p = 12;

    my_print(p);  // Valeur de *p : 12
    free(p);
    my_print(p);  // Valeur de *p : 0
    
    return 0;
}

La ligne 15 est-elle équivalente de l’instruction *p = 0; ? Dans les deux cas, le programme renvoie les mêmes messages.

+0 -0

Es-tu sous Linux (ou Unix-like) ou sous Windows ? Quel est ton niveau en anglais ?

Sinon,

2 - The free function causes the space pointed to by ptr to be deallocated, that is, made available for further allocation. If ptr is a null pointer, no action occurs. Otherwise, if the argument does not match a pointer earlier returned by the calloc, malloc, or realloc function, or if the space has been deallocated by a call to free or realloc, the behavior is undefined.

Là, ton code présente une erreur importante, tu lis une addresse qui ne t’appartient plus. Dans un programme, c’est une faille de sécurité importante (use after free). Au niveau de la norme c’est un comportement indéterminé.

Ce n’est pas spécifié dans la norme mais oui, certain compilo modifie la valeur avant de libérer l’espace aloué.

Une bonne pratique est de mettre à NULL tout pointeur libéré. 1 malloc = 1 free = 1 = NULL.

   free(p);
   p = NULL;
+2 -0

Salut,

La fonction free() ne modifie pas le pointeur que tu lui passes en argument ni l’objet qu’il référence (en tous les cas ce n’est pas précisé par la norme). En revanche, lors de ton deuxième appel à la fonction my_print(), tu déréférences un pointeur vers une zone de mémoire qui a été libérée ce qui est un comportement indéfini, il n’y a donc aucune garantie quant à la valeur que tu obtiendras (ni sur le fait que ton programme ne plantera pas).

Sinon, juste pour dire, le format %p de printf() attend un pointeur sur void, il est donc nécessaire d’opérer une conversion explicite. ;)

printf("p contient l'adresse %p et à cette adresse se trouve la valeur %i\n", (void *)p, *p);

Édit : semi-grilled.

+2 -0

Merci pour les réponses, je retiendrai vos conseils.

Mon niveau d’anglais est plutôt bon.

Sinon, juste pour dire, le format %p de printf() attend un pointeur sur void, il est donc nécessaire d’opérer une conversion explicite.

Étrange, en es-tu bien sûr ? Je compile avec l’option -Wall et je n’ai aucun avertissement à ce sujet.
Mais la doc te donne raison :

%p : void * (pointer to void) in an implementation-defined format.
https://en.wikipedia.org/wiki/Printf_format_string

Par curiosité, que représente void* ? Un pointeur vers l’adresse 'zéro' ou NULL ?

Mon niveau d’anglais est plutôt bon.

Alors, si tu es sous Linux, tu peux utiliser le manuel pour avoir plus d’information sur une fonction. En C, c’est la section 3 du manuel (sauf pour les appels système qui sont généralement dans la section 2).

Donc par exemple la commande man 3 free te renseignera correctement sur la fonction free. ^^

Ça marche également pour la fonction printf.

Prend l’habitude d’utiliser l’option -pedantic pour compiler.

+0 -0

Alors, si tu es sous Linux, tu peux utiliser le manuel pour avoir plus d’information sur une fonction. En C, c’est la section 3 du manuel (sauf pour les appels système qui sont généralement dans la section 2).

Je n’ai pas tout suivi, en fait j’ai Linux sur une virtual box installée sur mon windows pour mon cours de programmation car le prof l’a dit de l’installer et donc j’ai pas trop l’habitude. :/

De quel manuel parles-tu ? Mon niveau en linux se résume à ouvrir l’invite de commande et à compiler mon programme avec gcc -o -Wall prog prog.c.

ça fait quoi l’option -pedantic ?

@Taurre j’arrive pas à citer ton message mais merci pour le lien, les infos expliquées sont utiles.

Je comprends pas trop l’intérêt de la ligne n°3 dans cette correction sachant que la fonction swap est déclarée avant main() ?

+0 -0

De quel manuel parles-tu ?

info-matique

Sous Linux, il y a par défaut de la documentation disponible et consultable via le terminal (entre autre) à l’aide de la commande man. Cette documentation est divisée en huit sections (parfois plus) : les commandes (section 1), les appels systèmes (section 2), les fonctions de bibliothèques, en général uniquement les bibliothèques C (section 3), Les périphériques et pilotes (section 4), les formats de fichiers (section 5), les jeux (section 6), divers (section 7) et les outils système (section 8).

La section 3 incluant les descriptions des fonctions des bibliothèques C installées, elle comporte également celles des fonctions de la bibliothèque standard C. Tu peux donc obtenir rapidement des informations sur l’une ou l’autre fonction à l’aide de la commande man comme te l’a montré @ache. ;)

ça fait quoi l’option -pedantic ?

Cela demande au compilateur de s’assurer que ton code respecte la norme, en l’occurrence la norme C89 si aucune n’est spécifiée via l’option -std.

+1 -0

Ahah ! :D

Pas d’inquiétude. Si tu n’as pas l’habitude de Linux pas de problème, tu peux également chercher sur internet. Si ton prof t’as demandé d’installer Linux, c’est que Linux est un environment plus agréable pour coder (en C surtout mais c’est valable pour beaucoup de langages !).

Le manuel, c’est un ensemble de fichiers qui est sur ton ordinateur. Ce n’est pas un vrai livre, d’ailleurs, il y en a plusieurs versions en fonction de ton système d’exploitation.

C’est une commande tout comme gcc, c’est la commande man. Elle permet d’avoir des informations sur d’autres commandes (pas exemple man gcc) ou encore sur les fonctions du langage C (c’est pour ça que je t’en parle :p). La commande man 3 printf te donne tout plein d’informations sur le fonctionnement de la fonction printf par exemple. :)

L’option -pedantic demande à gcc d’être le plus proche possible du standard. C’est demander à gcc de te signaler tout ce qui pourrait poser problème du point de vue de la norme. Si je compile le code que tu as initialement avec -pedantic j’obtiens :

$ gcc t.c -pedantic -Wall
t.c: Dans la fonction « my_print »:
t.c:6:35: attention: format « %p » attend un argument de type « void * » mais l'argument 2 a le type « int * » [-Wformat=]
    6 |     printf("p contient l'adresse %p et à cette adresse se trouve la valeur %i\n", p, *p);
      |                                  ~^                                                ~
      |                                   |                                                |
      |                                   void *                                           int *
      |                                  %ls

Exactement ce que @Taurre t’avais dis ! :D

Edit: Grilled x)

+2 -0

@Taurre j’arrive pas à citer ton message mais merci pour le lien, les infos expliquées sont utiles.

info-matique

J’espère bien, ces infos sont de moi. :p

Je comprends pas trop l’intérêt de la ligne n°3 dans cette correction sachant que la fonction swap est déclarée avant main() ?

info-matique

Foncièrement, dans ce cas ci, il n’y en a pas. Il s’agit d’un prototype de fonction, très utile lorsqu’il y a lieu de diviser ton projet en plusieurs fichiers ou lorsqu’il y a plusieurs fonctions différentes qui s’appellent entres-elles définies dans un même fichier source.

+2 -0

L’option -pedantic demande à gcc d’être le plus proche possible du standard. C’est demander à gcc de te signaler tout ce qui pourrait poser problème du point de vue de la norme.

ache

Salut, j’ai essayé aujourd’hui de compiler avec l’option -pedantic le code suivant :

compilation
compilation

Pourquoi le programme n’indique-t-il pas d’erreur aux lignes 11 et 4 ?

+0 -0

Le fait d’utiliser void pour indiquer que la fonction main() ne reçoit pas d’arguments n’est pas obligatoire, c’est pour cela que tu n’as pas d’avertissements ligne 4. Pour la ligne 11, édit : tu accèdes à une zone précédement libérée, mais le compilateur ne génèrera pas d’avertissement pour cela car il ne peut le détecter facilement. ;)

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte