FAQ CConsultez toutes les FAQ
Nombre d'auteurs : 35, nombre de questions : 194, dernière mise à jour : 18 février 2018 Ajouter une question
Cette FAQ a été réalisée à partir des questions fréquemment posées sur les forums de www.developpez.com et de l'expérience personnelle des auteurs.
Je tiens à souligner que cette FAQ ne garantit en aucun cas que les informations qu'elle propose sont correctes ; les auteurs font le maximum, mais l'erreur est humaine. Cette FAQ ne prétend pas non plus être complète. Si vous trouvez une erreur, ou que vous souhaitez devenir rédacteur, lisez ceci .
Sur ce, je vous souhaite une bonne lecture.
- Qu'est-ce qu'un pointeur ?
- Quand utiliser les pointeurs ?
- Qu'est-ce que NULL ?
- Comment utiliser un pointeur sur une structure ?
- Quelle est la différence entre sizeof(struct data) et sizeof(struct data *) ?
- Comment déclarer un pointeur sur une fonction ?
- p et q pointent sur deux objets identiques mais (p == q) renvoie toujours faux ! Pourquoi ?
- Qu'est-ce que *p++ incrémente ?
- Quelle est la différence entre pointeurs constants et pointeurs sur constante ?
- Comment connaître le type d'une variable adressée par un pointeur void * ?
Chaque donnée en mémoire a une « adresse ». Cette adresse permet au processeur de retrouver la donnée et de demander sa lecture ou son écriture. Un pointeur est une variable qui contient une adresse (ça peut être l'adresse d'une variable, celle d'une fonction ou encore celle d'un élément d'un tableau, etc.). Par abus de langage, on utilise aussi parfois le mot « pointeur » pour désigner une « adresse ».
Il est difficile de fournir une liste exhaustive des cas où on doit (on devrait) utiliser les pointeurs, mais voici quelques exemples.
- Chaque fois qu'on veut passer « une variable » à une fonction.
- Chaque fois qu'on veut passer un objet de taille trop importante à une fonction. En effet, il est moins coûteux (en termes temps d'exécution et de consommation de mémoire) de passer l'adresse de l'objet seulement que de passer une copie de l'objet lui-même (qui peut faire plusieurs octets contre 4 seulement pour une adresse sur un processeur Intel 32 bits par exemple) à la fonction.
- Chaque fois qu'on veut allouer dynamiquement de la mémoire.
- Chaque fois que le langage l'impose (par exemple, le nom d'un tableau, sauf lorsqu'il apparaît en argument de l'opérateur sizeof, est toujours converti par le compilateur en l'adresse de son premier élément !)
NULL est une macro définie dans <stddef.h> (qui est inclus par stdio.h, stdlib.h, etc.) et sert à représenter une adresse invalide. NULL est par exemple utilisé dans les fonctions retournant un pointeur pour indiquer que la fonction a échoué. Affecter NULL à un pointeur sert donc à indiquer que le pointeur est actuellement inutilisé (ou pointe « nulle part »). La norme stipule que n'importe quelle expression entière valant 0 ou une telle expression castée en void * représente une telle adresse.
Un pointeur sur une structure se déclare comme tout autre pointeur :
Code C : | Sélectionner tout |
1 2 3 4 5 6 7 | struct base { int a; double b; }; struct base Elem; struct base * p = &Elem; |
Code C : | Sélectionner tout |
(*p).a = 5;
Code C : | Sélectionner tout |
p->a = 5;
sizeof(struct data) fournit la taille de la structure alors que sizeof(struct data *) fournit celle d'un pointeur.
Le plus simple est de définir dans un premier temps le type de la fonction sur laquelle on veut pointer :
Code C : | Sélectionner tout |
1 2 3 4 5 6 7 8 | typedef int F(void); /* F : type de la fonction f. */ /* Voici la fonction f en question : */ int f(void) { return 1; } |
Code C : | Sélectionner tout |
F * p = &f;
Code C : | Sélectionner tout |
F * p = f;
Code C : | Sélectionner tout |
1 2 | y = p(); y = (*p)(); |
Code C : | Sélectionner tout |
int (*p)(void) = f;
C'est tout à fait normal, le test (p == q) compare les deux pointeurs et non le contenu des emplacements qu'ils pointent. Pour comparer le contenu, il faut comparer *p et *q ou utiliser la fonction memcmp.
Code C : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | int * p, * q, n = 10; /* On suppose ici que malloc ne peut pas échouer */ p = malloc(sizeof(int)); q = malloc(sizeof(int)); memcpy(p, amp;&n, sizeof(int)); /* Ou simplement *p = n; */ memcpy(q, amp;&n, sizeof(int)); /* Ou simplement *q = n; */ /* (*p == *q) mais (p != q) */ free(p); p = q; /* Maintenant (p == q) et donc naturellement (*p == *q) */ free(p); /* Ou free(q) */ |
Les opérateurs unaires (*, ++ et --) ont une priorité élevée et sont évalués de droite à gauche.
*p++; retourne la valeur de la zone mémoire désignée par p et incrémente ensuite p.
(*p)++; incrémente quant à lui la valeur de la zone mémoire désignée par *p.
Il convient de ne pas confondre les pointeurs constants (le pointeur ne pourra pas être modifié, mais la variable pointée si) et les pointeurs sur constantes (le pointeur pourra être modifié, mais pas la variable pointée).
Code C : | Sélectionner tout |
1 2 3 4 5 | char buf[] = "bonjour"; char * const p = buf; /* Le pointeur p est déclaré constant */ p++; /* Incorrect, car on ne peut pas modifier une constante */ p[4]++; /* Correct */ |
Code C : | Sélectionner tout |
1 2 3 4 5 | char buf[] = "bonjour"; char const * p = buf; /* Ou const char * p = buf; */ p++; /* Correct */ p[4]++; /* Incorrect, car les données pointées par p ont été déclarées constantes (const char) */ |
Code C : | Sélectionner tout |
1 2 3 4 5 | char buf[] = "bonjour"; char const * const p = buf; p++; /* Incorrect */ p[4]++; /* Incorrect */ |
La mémoire n'étant pas typée (le contenu de la mémoire dépend toujours de l'interprétation qu'on en fait), on ne peut pas connaître le type d'un objet pointé par un void *. Si le pointeur est utilisé pour créer une fonction générique, il est nécessaire de rajouter à la fonction un paramètre indiquant la taille ou le type de la variable utilisée :
Code C : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 | typedef enum { TYPES_char, TYPES_short, TYPES_int, TYPES_long, TYPES_float, TYPES_double } TypePtr; void MyFunction(void * Ptr, TypePtr Type); |
Proposer une nouvelle réponse sur la FAQ
Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour çaLes sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2024 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.