ProgrammationDéveloppeur C

Décrivez les caractéristiques et les pièges de l'arithmétique des pointeurs en C. Sur quoi est basée cette arithmétique, quelles surprises peuvent survenir et comment les éviter correctement ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse.

Historique de la question :

L'arithmétique des pointeurs est apparue dans le langage C pour assurer un fonctionnement efficace de la mémoire, des tableaux et des structures. Elle est étroitement liée à l'adressage mémoire et à la façon dont C fonctionne au plus bas niveau : l'addition ou la soustraction d'un pointeur permet d'accéder à des éléments consécutifs d'un tableau.

Problème :

La principale difficulté réside dans le fait que l'arithmétique des pointeurs n'est pas équivalente à l'arithmétique des nombres : ajouter 1 à un pointeur augmente son adresse de la taille du type auquel il fait référence. Les erreurs classiques incluent le dépassement des limites d'un tableau alloué, le travail avec des pointeurs de types incompatibles et les tentatives de calculs avec void *.

Solution :

Toujours tenir compte de la taille des types lors de l'utilisation des pointeurs, éviter les calculs algébriques avec void*, contrôler les limites du tableau. Pour accéder à un élément du tableau, utiliser l'indexation ou des pointeurs calculés, après avoir vérifié les limites.

Exemple de code :

#include <stdio.h> int main() { int arr[5] = {1, 2, 3, 4, 5}; int *p = arr; printf("%d\n", *(p + 2)); // 3 // Non valide : p + 10 dépasse les limites du tableau return 0; }

Caractéristiques clés :

  • L'addition à un pointeur augmente l'adresse de sizeof(type) et non d'un octet
  • On ne peut comparer que des pointeurs pointant vers des éléments d'un même tableau
  • L'arithmétique avec void* n'est pas permise (sauf certaines extensions GNU)

Questions pièges.

Peut-on ajouter à un pointeur une valeur de type float ou d'autres types ?

Non, on ne peut ajouter ou soustraire qu'une seule valeur de type entier aux pointeurs. L'utilisation de flottants entraînera une erreur de compilation.

*Renverra (arr + i) et arr[i] toujours la même chose, même si i sort des limites du tableau ?

Non. Sémantiquement, ils sont équivalents, mais si l'indice dépasse les limites du tableau, les deux expressions entraînent un comportement indéfini (undefined behavior).

Que se passe-t-il lors de la soustraction de pointeurs qui pointent vers différents tableaux ?

Le résultat n'est pas défini par la norme et est considéré comme une erreur. On peut soustraire uniquement des pointeurs qui se trouvent dans le même tableau (ou dans une mémoire allouée par un seul bloc).

Erreurs typiques et anti-patterns

  • Dépassement des limites du tableau lors de l'utilisation des pointeurs (buffer overrun)
  • Réalisation d'arithmétique avec void* sans conversion explicite
  • Utilisation de pointeurs pour accéder à une mémoire déjà libérée

Exemple de la vie réelle

Dans le code, le développeur utilise l'arithmétique des pointeurs pour parcourir un tableau :

Avantages :

  • Plus rapide que l'indexation sur certaines architectures.

Inconvénients :

  • A oublié de vérifier les limites — un dommage de mémoire s'est produit (segmentation fault).

Dans la version refactorisée, des vérifications explicites des limites sont utilisées à chaque étape :

Avantages :

  • Garantie de ne pas dépasser les limites du tableau

Inconvénients :

  • Le code est devenu légèrement plus long et a nécessité le développement de fonctions auxiliaires