next up previous contents index
Next: L'opération & et le Up: No Title Previous: Hachage par adressage ouvert

Pointeurs

    

Pascal et C offrent un type pointeur . Plus exactement, il s'agit d'un constructeur de type, noté *, qui s'applique à un type t quelconque pour construire le type des pointeurs de t , noté t* quand t est un type simple. Quel que soit le type t, une valeur de type pointeur de t est une adresse ou bien la constante NULL     (définie dans stdio.h).

On définit une variable de type int*, c'est-à-dire pointeur de int, par :

 

  int *ip;

Cette définition est incomplète car elle n'est pas initialisée. Il y a plusieurs façons d'initialiser un pointeur. La première est d'utiliser la valeur d'un autre pointeur de même type (qui aurait déjà été initialisé...) :

 

  int *iq = ...;
  int *ip = iq;

La seconde est d'utiliser l'opération &  appliquée à une variable de type t (figure 11) :

  int i;
  int *ip = &i;


  
Figure 11: Initialisation d'un pointeur par une adresse d'objet
\begin{figure}
 \begin{center}
 \leavevmode
 
\fbox {
 \epsfig{file=fig/pointeur.eps}
 }
 \end{center} \end{figure}

Signalons également le cas particulier des pointeurs de caractères, qui peuvent être initialisés par une chaîne littérale  :

  const char *cp = "Turing";

Cette définition a pour effet d'allouer quelque part la chaîne "Turing" et de donner pour valeur à cp l'adresse de cette chaîne, laquelle ne sera pas modifiable (même si const n'est pas spécifié).

La troisième est d'allouer de la mémoire explicitement (figure 12) :

  int *ip = malloc(sizeof(int));


  
Figure 12: Initialisation d'un pointeur par allocation dynamique
\begin{figure}
 \begin{center}
 \leavevmode
 
\fbox {
 \epsfig{file=fig/malloc.eps}
 }
 \end{center} \end{figure}

On reviendra sur ces deux dernières façons. Noter que int *ip = ... signifie en fait int* ip = ..., qui est une autre écriture permise et non *ip = ... ; d'ailleurs, si l'initialisation se fait ultérieurement par affectation, on écrirait respectivement :

  ip = iq;
  ip = &i;
  ip = malloc(sizeof(int));

et surtout pas

  *ip = iq;   /* faux */

ce qui serait incorrectement typé (*ip est un entier, iq est un pointeur).

Enfin, on peut initialiser un pointeur à NULL :

  int *ip = NULL;

Si E est une expression de type pointeur de t, alors *E est une expression correctement typée de type t, qui peut être placée à gauche d'une affectation, comme une variable, ce qui signifie qu'elle doit désigner un objet de type t. Mais l'utilisation de cette variable a de fortes chances de provoquer un << segmentation fault >>.

  

Que l'expression *E soit correctement typée ne garantit absolument pas qu'elle désigne un objet, autrement dit qu'elle pointe vers quelque chose ou réfère à quelque chose. L'expression arithmétique 1/(1-1) est aussi correctement typée, mais provoquera aussi une erreur à l'exécution.

  Le cas le plus usuel est celui où E est simplement une variable p de type pointeur de t ; c'est seulement quand p a été initialisée à une valeur non-nulle, que l'on peut dire que p << pointe >>, et donc que l'on peut utiliser *p en tant que variable de type t. Un pointeur initialisé à NULL ne pointe sur rien. D'où l'importance de l'initialisation pour les pointeurs.

La figure 11 représente symboliquement un pointeur qui ne pointe vers rien, et un pointeur qui pointe. Seul ce dernier peut être déréférencé.


  
Figure 13: Pointeurs
\begin{figure}
 \begin{center}
 \leavevmode
 
\fbox {
 \epsfig{file=fig/ptr.eps}
 }
 \end{center} \end{figure}

Tout programmeur C aura obtenu comme résultat de l'exécution d'un programme un << Segmentation fault >> inattendu. Cela est généralement dû à la déréférenciation d'un pointeur non-initialisé :

  int *p;
  *p = 4;

Il y a dans ce cas tentative d'affecter une valeur à une variable, *p, qui n'existe pas. On obtiendrait la même erreur si l'on tentait de lire *p dans les mêmes conditions.


next up previous contents index
Next: L'opération & et le Up: No Title Previous: Hachage par adressage ouvert
Jean-Philippe Chancelier
9/29/1998