Les pointeurs en C

Après les deux articles précédents, la compréhension de ce qu’est un pointeur devrait être plus facile. En effet, qu’avons nous vu? Un ordinateur comprend un microprocesseur, de la mémoire et des cartes d’entrée/sorties. Lorsque l’on effectue une opération, il va chercher les informations dans la mémoire, il les traite et les restocke dans la mémoire. Ceci implique qu’il sache s’y retrouver dans la mémoire. En gros on peut dire que ce qui se passe revient à ceci : tous les octets de la mémoire sont numérotés. Chacun de ces numéros est appelé l’adresse de l’octet. Les adresses sont stockées sur 32 bits, soit sur 8 chiffres en hexadécimal. Chaque case mémoire a donc une adresse propre, et le microprocesseur a sous la main un fichier dans lequel sont indiquées les adresses de toutes les variables qu’il a besoin de manipuler. Par ailleurs le microprocesseur à sous le coude un autre fichier qui contient toutes les instructions qu’il doit exécuter. Encore une fois je précise que ce n’est pas tout à fait ça. Mais du point de vue du programmeur C qui découvre les pointeurs, ça suffira.

a) Les adresses :

Donc lorsque l’on déclare une nouvelle valeur, par exemple un tableau T de 15 entiers, le microprocesseur sait que la mémoire requise va être 15x « le nombre d’octets nécessaire pour le stockage d’un entier ». Soit 60 octets si on est sur un ordinateur où chaque int est stocké sur 4 octets. Le microprocesseur va donc reserver quelque part dans la mémoire (où il veut, c’est son problème du moment que la place est libre) 60 octets consécutifs. Puis il va noter quelques part que ces octets ne sont plus libres, et il va noter dans son fichier de variables l’adrese du premier octet du tableau. Vous avez peut être déjà essayé de faire printf(« %d »,T); T étant un tableau, et obtenu un curieux résultat du style 0x8ab45fe5, eh bien c’est précisément ça : vous avez affiché l’adresse du premier octet du tableau T. De même si vous tapez printf(« %d »,&a); dans un programme, a étant un entier quelconque, vous allez afficher l’adresse du premier des octets dans lesquels a est stocké. Et quand vous écrivez scanf(« %d »,&a); vous demandez au microprocesseur de stocker la valeur saisie au clavier à l’adresse de a, tout simplement. Attention tout de même, car si dans le cadre du tableau, vous tapez printf(« %d »,T+1); vous n’allez pas obtenir 0x8ab45fe6, adresse du deuxième octet sur lequel est stocké le premier entier de T, mais plutôt 0x8ab45fea9 correspondant au premier octet sur lequel est stocké l’entier suivant. En effet le compilateur sachant que T est un tableau d’entiers sait qu’il faut sauter 4 octets pour se placer sur l’entier suivant. C’est pour ça que &T[i] et (T+i) reviennent au même, tous deux désignant l’adresse du ième entier de T. A partir de maintenant nous allons donc pouvoir distinguer deux types de variables : celles qui contiennent des données et celles qui contiennent des adresses. Vous l’aurez deviné, les variables qui contiennent des adresses sont appelées des pointeurs. En effet depuis la case mémoire où elles sont stockées, elles pointent vers les cases mémoires dont elles contiennent l’adresse.

b) Les pointeurs :

Bon maintenant qu’ils ont si bien été introduits, il ne reste plus grand chose à dire sinon peut être qu’ils sont l’essence du C. Jusqu’à maintenant on ne vous en avait pas parlé car ce n’était pas nécéssaire, mais en fait ils sont omniprésents même si cela ne saute pas aux yeux. C’est notamment grâce aux pointeurs qu’une fonction peut modifier plusieurs variable : on lui passe en argument les adresses des cases mémoires qu’il va falloir lire et modifier, et elles peut ainsi modifier les variables même si elle ne retourne rien. Les pointeurs sont également très utiles dés lors que l’on veut utiliser des structures complexes, créer des listes, files, ensembles, graphes, etc, et optimiser la place mémoire requise. Un exemple typique est la liste linéaire chainée : chaque cellule contient l’adresse de la suivante. On se sert aussi de pointeurs pour tout ce qui est tableau : int *t; est typiquement la manière de déclarer un pointeur vers un ou des entiers. Et si on fait un tableau à deux dimensions, la déclaration devient int **t, qui se décompose en (int *) *t pour un pointeur vers des pointeurs vers des entiers. La structure typique est la suivante : dans la n-ièmecase du tableau de pointeurs est stocké le pointeur de la n-ième ligne du tableau.

Publicités

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s