Programmation bas niveau (BNV) Help

Cours : Les pointeurs

Qu'est-ce qu'un pointeur ?

Un pointeur, c'est une forme de variable un peu particulière. Au lieu de contenir une valeur comme "Hello World!" ou 42, un pointeur contient l'adresse dans la mémoire vive (la RAM) d'une valeur.

Comment ça s'écrit ?

Pour écrire une variable simple qui comprend une valeur, vous savez déjà faire :

int answer = 42;

La variable answer est un integer dont la valeur est 42.

Quand vous avez utilisé scanf avec des int, vous avez dû passer à scanf l'adresse de la variable pour qu'il puisse la remplir. Vous aviez du placer le symbole & devant le nom de la variable.

Testez le code suivant dans un fichier .c:

#include <stdlib.h> #include <stdio.h> int main() { int answer = 42; printf("answer est un entier qui vaut %d\n", answer); printf("et son adresse est %p\n", &answer); exit(0); }

Cela devrait vous afficher quelque chose du genre :

answer est un entier qui vaut 42. et son adresse est 0x0023FF74.

Sauf que 0x0023FF74 va changer à chaque exécution, puisque l'ordinateur va nous donner un bout de mémoire différent à chaque fois.

Mais c'est quoi comme type &variable ?

Si on reprend notre exemple précédent :

int answer = 42; // answer est un int int * answer_address = &answer;

Pour stocker l'adresse d'un int, on va devoir déclarer un pointeur sur int : un int *.

Exemple

À priori dans l'exemple précédent ça ne parait pas extrêmement utile d'utiliser un pointeur, mais en vérité, c'est puissant et très utile.

Rappelez-vous de scanf: le fait de lui passer un pointeur sur votre variable lui permettait de la remplir pour vous avec ce qui était écrit sur le terminal par l'utilisateur.

Maintenant imaginons que vous avez besoin d'une fonction qui vous renvoie deux valeurs. Impossible à priori puisque qu'on ne peut return qu'une seule valeur par fonction.

On va faire le test, vous avez un nombre de minutes, et vous avez besoin de savoir combien d'heures et de minutes cela représente :

Sans pointeurs

#include <stdlib.h> #include <stdio.h> int getMinutes(int totalMinutes) { int minutes = totalMinutes % 60; return(minutes); } int getHours(int totalMinutes) { int hours = totalMinutes / 60; return(hours); } int main() { int totalMinutes; int minutes = 0; int hours = 0; printf("Nombre total de minutes ?\n"); scanf("%d", &totalMinutes); minutes = getMinutes(totalMinutes); hours = getHours(totalMinutes); printf("Cela fait une durée de %d heures et %d minutes\n", hours, minutes); }

Avec pointeurs

#include <stdlib.h> #include <stdio.h> void getHoursAndMinutes(int totalMinutes, int *hours, int *minutes) { *hours = totalMinutes / 60; *minutes = totalMinutes % 60; } int main() { int totalMinutes; int minutes = 0; int hours = 0; printf("Nombre total de minutes ?\n"); scanf("%d", &totalMinutes); getHoursAndMinutes(totalMinutes, &hours, &minutes); printf("Cela fait une durée de %d heures et %d minutes\n", hours, minutes); }

Dans l'exemple avec pointeur, en utilisant des pointeurs sur mes deux valeurs j'ai pu les modifier sans avoir besoin de les return puisqu'on m'avait donné directement leurs adresses.

Je n'ai donc pas modifié directement minutes et hours, j'ai modifié les valeurs qui se trouvaient aux addresses de minutes et hours.

À retenir

C'est toujours fouillis et vous n'êtes pas forcément convaincu-e-s de l'intérêt de la chose ?

C'est normal, cela viendra à force de complexifier les choses, retenez simplement ceci :

int age = 36; // la variable age int * age_ptr = &age; // un pointeur qui contient l'adresse de age int copy_age = *age_ptr; // un int qui va contenir la variable à l'adresse contenue par age_ptr

int * ptr => C'est un pointeur, ça contient une adresse. *ptr => C'est un pointeur "déréférencé" ça contient une variable.

La vérité sur les char *

Mais du coup si un int * c'est un pointeur sur l'adresse d'un int, un char * c'est un pointeur sur l'adresse d'un char?

Mais si c'est l'adresse d'un seul char, pourquoi j'en ai toute une série ? 🤯

Testez ce code :

#include <stdlib.h> #include <stdio.h> int main() { char *str = "Hello World!\n"; printf("L'adresse de str c'est %p\n", str); printf("L'adresse de la première case de str c'est %p\n", &str[0]); exit(0); }

Vous verrez que les deux adresses sont identiques.

Un char * est donc un pointeur, sur l'adresse de la première case de la chaine de caractère.

Mais malgré tout si vous essayez d'afficher str en modifiant un peu le code :

#include <stdlib.h> #include <stdio.h> int main() { char *str = "Hello World!\n"; printf("str c'est la phrase suivante : %s", str); printf("L'adresse de str c'est %p\n", str); printf("L'adresse de la première case de str c'est %p\n", &str[0]); exit(0); }

Vous allez bien avoir la phrase "Hello World!\n" qui va s'afficher dans le terminal.

Magie noire ? 🧙‍♂️ Pacte avec un démon ? 😈

Pas tout à fait.

En fait quand vous créez un char * en dur en lui donnant directement la valeur, l'ordinateur va travaillez pour vous.

Il va vérifier la taille de la chaîne que vous voulez créer et en mémoire il va lui réserver la place demandée.

La chaîne de caractères "Hello World!\n" prend 13 caractères. L'ordinateur va donc vous attribuer une place de 14 caractères en mémoire (13 caractères + le \0 qu'il ajoute automatiquement).

La fonction printf ne connait pas en avance la taille de la chaîne que vous allez lui envoyer, elle affiche donc tout ce qu'elle peut jusqu'à tomber sur un \0.

Dans la suite du cours, nous allons voir comment nous pouvons nous même réserver et libérer de la place dans la mémoire.

13 October 2025