Comment créer des pointeurs en C?

Car les pointeurs «sauvages» pointent vers des adresses aléatoires
Initialisez toujours les pointeurs avant de les utiliser, car les pointeurs «sauvages» pointent vers des adresses aléatoires, et y accéder fera planter votre programme.

Les pointeurs sont le cauchemar de tout nouveau programmeur C. Cependant, ils sont également la caractéristique qui a fait de C le langage de programmation puissant et répandu qu'il est jusqu'à aujourd'hui. Comme beaucoup d'autres fonctionnalités et constructions de programmation, il existe une approche systématique pour créer et utiliser des pointeurs C. Cet article est un guide étape par étape pour créer et utiliser des pointeurs de manière claire et simple.

Informations préalables

  • Les pointeurs sont des variables qui contiennent l'adresse d'un emplacement mémoire en général (cet emplacement mémoire peut contenir les données de la variable ou ne pas encore être affecté).
  • Les références sont des variables qui contiennent l'adresse mémoire d'une autre variable.
  • La principale différence entre une référence et un pointeur est que les références pointent vers des emplacements mémoire alloués tandis que les pointeurs peuvent pointer vers des emplacements mémoire non alloués.
  • Il existe une différence entre l'opérateur d'adresse (utilisé sur les variables pour renvoyer leur adresse en mémoire), l'opérateur de déclaration de référence (utilisé dans une déclaration de référence pour indiquer que la variable déclarée est une référence) et l'opérateur "et" au niveau du bit, ayant tous le même symbole (&)
  • Les pointeurs peuvent être incrémentés et décrémentés (vous permettant de modifier l'emplacement vers lequel pointe le pointeur).
  • Les pointeurs peuvent être attribués à l'aide de l'une des méthodes suivantes:
    • Affectation d'une référence au pointeur en faisant pointer le pointeur sur le même emplacement en mémoire que la référence.
    • Affectation de tout autre pointeur du même type au pointeur faisant pointer les deux pointeurs vers le même emplacement.
    • L'affectation d'une valeur numérique au pointeur (au format hexadécimal) fait que le pointeur pointe vers l'emplacement mémoire spécifique adressé par ce chiffre.
    • Affectation de l'adresse d'une variable de type pointeur au pointeur faisant pointer le pointeur sur l'emplacement mémoire du premier octet de la représentation binaire de la variable en mémoire.
  • Les références peuvent être attribuées à l'aide de l'une des méthodes suivantes:
    • Affectation d'une autre référence à la référence.
    • L'affectation d'une variable du même type que la référence fera le point de référence de la variable.
  • Les pointeurs et les références ont des types de données, indiquant le type de données pointé par le pointeur/référence.
  • Le type d'une référence restreint l'affectation de cette référence aux variables/références du même type de données. Par exemple, si nous déclarons une référence entière (int & d;), nous ne pouvons affecter qu'une autre référence entière ou une variable entière à cette référence (int i=0; d = i;)
  • Le type d'un pointeur restreint l'affectation du pointeur aux références, adresses de variables/pointeurs de ce même type de données. Cela affecte également la récupération des données pointées afin qu'un pointeur entier récupère un nombre d'octets égal au nombre d'octets occupés par un entier sur le système. De plus, le choix du type de données affecte la façon dont les pointeurs sont incrémentés et décrémentés. Lorsqu'un pointeur est incrémenté, il pointe vers la valeur de type de données suivante à partir de l'emplacement actuel. Par exemple, si une valeur entière prend 4 octets en mémoire, incrémenter un pointeur entier le fera pointer vers l'entier suivant, qui est 4 octets après l'emplacement actuel et donc la valeur du pointeur lui-même est incrémentée par des multiples de 4.
  • Les noms de variables de tableau sont considérés comme des pointeurs statiques/constants pointant vers le premier octet du premier élément du tableau et ayant le même type que les éléments du tableau.
Comment les pointeurs de fonction sont-ils représentés en C
Comment les pointeurs de fonction sont-ils représentés en C?

Pas

  1. 1
    Décidez du type de pointeur (c'est-à-dire du type de données vers lequel le pointeur pointe). Les conseils suivants peuvent vous aider:
    • Si vous déclarez un tableau dynamique, utilisez le type de données des éléments du tableau.
    • Si vous déclarez le pointeur pour accéder aux données d'une variable, utilisez le même type de données que la variable.
    • Si vous déclarez que le pointeur traverse une structure de liste, utilisez le type de données du nœud de liste (généralement une structure créée par l'utilisateur).
    • Si vous déclarez que le pointeur traverse un arbre, utilisez le type de données du nœud d'arbre, ou un pointeur vers le type de nœud d'arbre comme type (pointeur vers un pointeur de type de nœud d'arbre!).
  2. 2
    Déclarez le pointeur en utilisant une syntaxe comme celle-ci: data-type * pointer-identifier; où
    • type de données est le type que vous avez décidé à l'étape 1
    • pointer-identifier est l'identifiant ou le nom de la variable pointeur
  3. 3
    Attribuez le pointeur à un emplacement de mémoire initial. Cela peut être fait en utilisant l'une des méthodes suivantes:
    1. Allouer de la mémoire et pointer dessus par le pointeur: int * i = malloc (sizeof(int)*n); où n est le nombre de blocs mémoire à affecter.
    2. Affectation de l'adresse d'une variable au pointeur: int * i = & x; où "x" est un entier et (&) signifie l'adresse de.
    3. Affectation d'un identifiant de tableau au pointeur: int * i = array1; où array1 est un tableau d'entiers (int[] array1;).
    4. Affectation d'une référence au pointeur: int * i = a; où "a" est une référence entière (int & a;).
    5. Affectation d'un autre pointeur au pointeur: int * i = z; où "z" est un autre pointeur entier (int * z;)
  4. 4
    Chaque fois que vous devez extraire l'élément de données actuellement pointé par le pointeur, utilisez l'opérateur de valeur à l'adresse (*): int x = *i; où i est un pointeur entier.
  5. 5
    Utilisez l'opérateur d'indexation sur le pointeur comme s'il s'agissait d'un tableau chaque fois que vous souhaitez obtenir un emplacement mémoire à côté du pointeur sans réellement faire avancer le pointeur. Par exemple, si vous avez un pointeur entier i, vous pouvez utiliser i[2] qui récupérera l'entier qui est après l'entier immédiatement après l'entier pointé par la référence (l'entier qui est 2 entiers après l'emplacement actuel). Le pointeur i pointera toujours vers le même emplacement mémoire. Une autre alternative consiste à obtenir la valeur au pointeur 2 étapes après ce pointeur: *(i + 2)
  6. 6
    Utilisez les opérateurs increment(++), decrement(-), += et -= chaque fois que vous devez modifier l'emplacement actuel. je += 5; fera avancer le pointeur entier i 5 entiers vers l'avant.
  7. 7
    Une fois que vous avez fini d' utiliser le pointeur, si vous la mémoire allouée à ce pointeur, assurez -vous de libérer la mémoire allouée à l' aide de la fonction libre (). (libre(i); où i est un pointeur)
Affectation de tout autre pointeur du même type au pointeur faisant pointer les deux pointeurs vers
Affectation de tout autre pointeur du même type au pointeur faisant pointer les deux pointeurs vers le même emplacement.

Conseils

  • Lorsque vous déclarez un pointeur en tant que membre d'une structure, vous accédez au pointeur lui-même à l'aide de l'opérateur point(.) et vous accédez à la valeur pointée par le pointeur à l'aide de l'opérateur (*). Par exemple, si vous avez une struct s1 qui a un membre pointeur entier c, et que vous avez déclaré une variable s (struct s1 s;), sc accédera au pointeur lui-même (sc = &i), *sc accédera aux données pointées par le membre c (j = *sc).
  • Si vous avez une structure que vous avez allouée à l'aide de malloc(), qui renvoie un pointeur vers la structure, les références aux membres de la structure allouée sont faites à l'aide de l'opérateur ->. En supposant à nouveau que la structure s1 et que s ait été déclaré comme un pointeur vers ce type de structure, ce qui suit affecterait l'adresse d'une variable et référencerait la variable respectivement: s->c = &j; k = *s->c. Certains programmeurs choisissent d'écrire *(s->c) pour plus de clarté, bien que ce ne soit pas nécessaire.
  • Regardez dans le ramasse-miettes Boehm. Une fois installé, vous pouvez l'utiliser en incluant gc.h et en remplaçant malloc() par gc_malloc(). L'utilisation d'un ramasse-miettes réduit les bogues de mémoire, mais selon le programme peut augmenter ou diminuer les performances.
  • Envisagez d'utiliser des outils de débogage tels que valgrind (Linux) qui peuvent aider à identifier les fuites de mémoire et à tracer l'utilisation de pointeurs vers des données "hors limites".
  • Il est généralement préférable de garder un pointeur pointant sur toute mémoire que vous allouez afin de pouvoir la libérer plus tard.
  • C'est une bonne pratique de programmation de vérifier si malloc () a réussi à allouer le morceau de mémoire approprié en vérifiant si le pointeur renvoyé n'est pas égal à NULL ou à 0.
Il existe une approche systématique pour créer
Comme beaucoup d'autres fonctionnalités et constructions de programmation, il existe une approche systématique pour créer et utiliser des pointeurs C.

Mises en garde

  • L'utilisation de l'opérateur d'indexation sur les pointeurs peut être dangereuse car vous pouvez essayer d'accéder à des emplacements en mémoire qui ne sont pas autorisés ou obtenir des valeurs d'emplacement mémoire non allouées.
  • N'oubliez pas de libérer la mémoire que vous avez allouée à l'aide de malloc (). Ne pas le faire peut entraîner des plantages, un débordement de mémoire et d'autres problèmes dans votre programme.
  • N'attribuez pas d'emplacement mémoire direct (par adresse) à un pointeur, sauf si vous y êtes vraiment obligé.
  • Initialisez toujours les pointeurs avant de les utiliser, car les pointeurs «sauvages» pointent vers des adresses aléatoires, et y accéder fera planter votre programme.

Questions et réponses

  • Comment les pointeurs de fonction sont-ils représentés en C?
    Ils sont représentés à l'aide d'une variable de type (return_type (*variable_name))(param1_type, param2_type) dans le code C. Ils se comportent comme n'importe quel autre pointeur, sauf qu'ils peuvent être appelés.

FacebookTwitterInstagramPinterestLinkedInGoogle+YoutubeRedditDribbbleBehanceGithubCodePenWhatsappEmail