FAQ CConsultez toutes les FAQ

Nombre d'auteurs : 27, nombre de questions : 175, dernière mise à jour : 17 décembre 2010  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.


SommairePointeurs, tableaux et chaînes de caractèresLes pointeurs (10)
précédent sommaire suivant
 

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 ».

Mis à jour le 29 janvier 2003 Bob

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 !).

Mis à jour le 29 janvier 2003 Bob

Comment passer "une variable" à une fonction ?

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.

Mis à jour le 1er février 2003 gl LFE

Un pointeur sur une structure se déclare comme tout autre pointeur :

Code C :
1
2
3
4
5
6
7
struct base { 
   int    a; 
   double b; 
}; 
  
struct base  Elem; 
struct base * p = &Elem;
Pour accéder au membre de la structure via le pointeur il est nécessaire de déréférencer ce pointeur :

Code C :
(*p).a = 5;
Cette écriture pouvant se simplifier en :

Code C :
p->a = 5;
(*p).a n'est cependant pas strictement équivalent à p->a car la première déréférence p (lit sizeof(struct base) octets à partir de cette adresse) avant d'entrer dans le champ a alors que p->a accède directement à la mémoire utile. (*p).a est donc non seulement plus long a écrire que p->a mais également moins performant.

Mis à jour le 11 septembre 2006 fearyourself gl Melem

sizeof(struct data) fournit la taille de la structure alors que sizeof(struct data *) fournit celle d'un pointeur.

Mis à jour le 11 septembre 2006 Bob gl

Le plus simple est de définir dans un premier temps le type de la fonction sur laquelle on veut pointer :

Code C :
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; 
}
Un pointeur sur f se déclare donc ainsi :

Code C :
F * p = &f;
En fait, le nom d'une fonction (f), lorsqu'il n'est pas utilisé dans sizeof ou avec l'opérateur & (« adresse de »), est toujours converti par le compilateur en &f. Cela signifie qu'on aurait pu également écrire tout simplement :

Code C :
F * p = f;
Et enfin, pour appeler f, les deux écritures suivantes sont toutes valides :

Code C :
1
2
y = p(); 
y = (*p)();
Sans typedef, p devrait avoir été déclaré ainsi :

Code C :
int (*p)(void) = f;
En effet, on veut un pointeur p vers une fonction qui ne prend aucun argument et qui retourne un int. (*p) vaut donc « une fonction » (même si une telle expression, sauf si elle est utilisée comme argument de sizeof, sera toujours automatiquement convertie en l'adresse de la fonction…). Cette fonction prend void comme argument retourne un int. Autrement dit, (*p)(void) vaut un int d'où int (*p)(void) !

Mis à jour le 27 juillet 2008 Melem

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 :
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) */

Mis à jour le 15 mai 2003 LFE Melem

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.

Mis à jour le 31 janvier 2003 LFE

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 :
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 :
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) */
Il est bien entendu possible de combiner les deux pour créer un pointeur constant sur des constantes :

Code C :
1
2
3
4
5
char buf[] = "bonjour"; 
char const * const p = buf; 
  
p++;    /* Incorrect */ 
p[4]++; /* Incorrect */

Mis à jour le 20 septembre 2004 gl

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 :
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);

Mis à jour le 20 septembre 2004 gl LFE

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 ça


Réponse à la question

Liens sous la question
précédent sommaire suivant
 

Les 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 © 2014 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.

 
 
 
 
Partenaires

PlanetHoster
Ikoula