Namespaces
Variants

Pointer declaration

From cppreference.net

Le pointeur est un type d'objet qui fait référence à une fonction ou à un objet d'un autre type, en ajoutant éventuellement des qualificateurs. Un pointeur peut également ne rien référencer, ce qui est indiqué par la valeur spéciale du pointeur nul.

Table des matières

Syntaxe

Dans la grammaire de déclaration d'une déclaration de pointeur, la séquence type-specifier désigne le type pointé (qui peut être un type fonction ou objet et peut être incomplet), et le declarator a la forme :

* attr-spec-seq  (optionnel) qualifiers  (optionnel) declarator

declarator peut être l'identifiant qui nomme le pointeur déclaré, incluant un autre déclarateur de pointeur (ce qui indiquerait un pointeur vers un pointeur) :

float *p, **pp; // p est un pointeur vers float
                // pp est un pointeur vers un pointeur vers float
int (*fp)(int); // fp est un pointeur vers fonction avec le type int(int)

Les qualificateurs qui apparaissent entre * et l'identificateur (ou autre déclarateur imbriqué) qualifient le type du pointeur qui est déclaré :

int n;
const int * pc = &n; // pc est un pointeur non-const vers un const int
// *pc = 2; // Erreur : n ne peut pas être modifié via pc sans cast
pc = NULL; // OK : pc lui-même peut être modifié
int * const cp = &n; // cp est un pointeur const vers un int non-const
*cp = 2; // OK pour modifier n via cp
// cp = NULL; // Erreur : cp lui-même ne peut pas être modifié
int * const * pcp = &cp; // pointeur non-const vers pointeur const vers int non-const

La attr-spec-seq (C23) est une liste facultative d' attributs , appliquée au pointeur déclaré.

Explication

Les pointeurs sont utilisés pour l'indirection, qui est une technique de programmation omniprésente ; ils peuvent être utilisés pour implémenter la sémantique de passage par référence, pour accéder aux objets avec une durée de stockage dynamique, pour implémenter des types "optionnels" (en utilisant la valeur de pointeur nul), les relations d'agrégation entre les structures, les rappels (en utilisant des pointeurs vers des fonctions), les interfaces génériques (en utilisant des pointeurs vers void), et bien plus encore.

Pointeurs vers des objets

Un pointeur vers un objet peut être initialisé avec le résultat de l' opérateur d'adresse appliqué à une expression de type objet (qui peut être incomplet) :

int n;
int *np = &n; // pointeur vers int
int *const *npp = &np; // pointeur non-constant vers pointeur constant vers int non-constant
int a[2];
int (*ap)[2] = &a; // pointeur vers tableau d'int
struct S { int n; } s = {1}
int* sp = &s.n; // pointeur vers l'int qui est un membre de s

Les pointeurs peuvent apparaître comme opérandes de l'opérateur d'indirection (opérateur unaire * ), qui retourne la lvalue identifiant l'objet pointé :

int n;
int* p = &n; // le pointeur p pointe vers n
*p = 7; // stocke 7 dans n
printf("%d\n", *p); // la conversion lvalue-en-rvalue lit la valeur depuis n

Les pointeurs vers des objets de type struct et union peuvent également apparaître comme opérandes gauche de l'opérateur accès membre via pointeur -> .

En raison de la conversion implicite array-to-pointer , un pointeur vers le premier élément d'un tableau peut être initialisé avec une expression de type tableau :

int a[2];
int *p = a; // pointeur vers a[0]
int b[3][3];
int (*row)[3] = b; // pointeur vers b[0]

Certains opérateurs d'addition et de soustraction , d'affectation composée , d'incrémentation et de décrémentation sont définis pour les pointeurs vers des éléments de tableaux.

Opérateurs de comparaison sont définis pour les pointeurs vers des objets dans certaines situations : deux pointeurs qui représentent la même adresse sont égaux, deux valeurs de pointeur nul sont égales, les pointeurs vers des éléments d'un même tableau se comparent de la même manière que les indices de tableau de ces éléments, et les pointeurs vers des membres de structure se comparent dans l'ordre de déclaration de ces membres.

De nombreuses implémentations fournissent également un ordre total strict des pointeurs de provenance aléatoire, par exemple s'ils sont implémentés comme des adresses dans un espace d'adressage virtuel continu (« plat »).

Pointeurs vers des fonctions

Un pointeur vers fonction peut être initialisé avec l'adresse d'une fonction. En raison de la conversion fonction-vers-pointeur , l'opérateur d'adresse est optionnel :

void f(int);
void (*pf1)(int) = &f;
void (*pf2)(int) = f; // identique à &f

Contrairement aux fonctions, les pointeurs vers des fonctions sont des objets et peuvent donc être stockés dans des tableaux, copiés, assignés, passés à d'autres fonctions comme arguments, etc.

Un pointeur vers une fonction peut être utilisé à gauche de l' opérateur d'appel de fonction ; ceci appelle la fonction pointée :

#include <stdio.h>
int f(int n)
{
    printf("%d\n", n);
    return n * n;
}
int main(void)
{
    int (*p)(int) = f;
    int x = p(7);
}
*Note : Le code source C++ n'a pas été traduit conformément aux instructions, car il se trouve dans des balises `
` et contient des termes spécifiques au C++. Seul le texte environnant aurait été traduit si présent.*

Le déréférencement d'un pointeur de fonction donne le désignateur de fonction pour la fonction pointée :

int f();
int (*p)() = f;    // le pointeur p pointe vers f
(*p)(); // fonction f invoquée via le désignateur de fonction
p();    // fonction f invoquée directement via le pointeur

Opérateurs de comparaison d'égalité sont définis pour les pointeurs vers des fonctions (ils comparent égaux s'ils pointent vers la même fonction).

Parce que la compatibilité des types de fonctions ignore les qualificateurs de plus haut niveau des paramètres de fonction, les pointeurs vers des fonctions dont les paramètres ne diffèrent que par leurs qualificateurs de plus haut niveau sont interchangeables :

int f(int), fc(const int);
int (*pc)(const int) = f; // Correct
int (*p)(int) = fc;       // Correct
pc = p;                   // Correct

Pointeurs vers void

Un pointeur vers un objet de n'importe quel type peut être implicitement converti en pointeur vers void (optionnellement qualifié const ou volatile ), et vice versa :

int n=1, *p=&n;
void* pv = p; // conversion de int* vers void*
int* p2 = pv; // conversion de void* vers int*
printf("%d\n", *p2); // affiche 1

Les pointeurs vers void sont utilisés pour passer des objets de type inconnu, ce qui est courant dans les interfaces génériques : malloc retourne void * , qsort attend une fonction de rappel fournie par l'utilisateur qui accepte deux arguments const void * . pthread_create attend une fonction de rappel fournie par l'utilisateur qui accepte et retourne void * . Dans tous les cas, il est de la responsabilité de l'appelant de convertir le pointeur vers le type correct avant utilisation.

Pointeurs nuls

Les pointeurs de chaque type ont une valeur spéciale connue sous le nom de null pointer value de ce type. Un pointeur dont la valeur est null ne pointe vers aucun objet ni fonction (le déréférencement d'un pointeur null est un comportement indéfini), et se compare comme égal à tous les pointeurs du même type dont la valeur est également null .

Pour initialiser un pointeur à null ou assigner la valeur null à un pointeur existant, une constante de pointeur null ( NULL , ou toute autre constante entière de valeur zéro) peut être utilisée. l'initialisation statique initialise également les pointeurs à leurs valeurs null.

Les pointeurs nuls peuvent indiquer l'absence d'un objet ou peuvent être utilisés pour signaler d'autres types de conditions d'erreur. En général, une fonction qui reçoit un argument pointeur doit presque toujours vérifier si la valeur est nulle et traiter ce cas différemment (par exemple, free ne fait rien lorsqu'un pointeur nul est passé).

Notes

Bien que tout pointeur vers un objet puisse être converti en pointeur vers un objet d'un type différent, le déréférencement d'un pointeur vers un type différent du type déclaré de l'objet est presque toujours un comportement indéfini. Voir strict aliasing pour plus de détails.

Il est possible d'indiquer à une fonction qui accède à des objets via des pointeurs que ces pointeurs ne sont pas des alias. Voir restrict pour plus de détails.

(depuis C99)

Les expressions lvalue de type tableau, lorsqu'utilisées dans la plupart des contextes, subissent une conversion implicite vers le pointeur vers le premier élément du tableau. Voir tableau pour plus de détails.

char *str = "abc"; // "abc" est un tableau char[4], str est un pointeur vers 'a'

Les pointeurs vers char sont souvent utilisés pour représenter des chaînes . Pour représenter une chaîne de bytes valide, un pointeur doit pointer vers un char qui est un élément d'un tableau de char, et il doit y avoir un char avec la valeur zéro à un certain index supérieur ou égal à l'index de l'élément référencé par le pointeur.

Références

  • Norme C23 (ISO/CEI 9899:2024) :
  • 6.7.6.1 Déclarateurs de pointeur (p: TBD)
  • Norme C17 (ISO/CEI 9899:2018) :
  • 6.7.6.1 Déclarateurs de pointeur (p: 93-94)
  • Norme C11 (ISO/IEC 9899:2011) :
  • 6.7.6.1 Déclarateurs de pointeur (p: 130)
  • Norme C99 (ISO/IEC 9899:1999) :
  • 6.7.5.1 Déclarateurs de pointeur (p: 115-116)
  • Norme C89/C90 (ISO/IEC 9899:1990) :
  • 3.5.4.1 Déclarateurs de pointeur

Voir aussi

Documentation C++ pour Déclaration de pointeur