Les pointeurs
Objectifs du chapitre
Développer des applications utilisant des pointeurs.
Développer des applications utilisant l’allocation dynamique de mémoire.
Définition
Un pointeur est une variable destinée à contenir une adresse. Une adresse étant un entier, un pointeur est une variable de type entier.
Exemples
1. Pointeur sur un entier
La déclaration int* p réserve un entier en mémoire destiné à contenir l’adresse d’une variable de type entier.
L’écriture int* p (l’étoile collée à int) suggère que la variable p est du type pointeur sur un entier. On pourrait aussi écrire int *p (l’étoile collée au p), qui suggère que la variable *p est du type entier, ce qui est aussi vrai.
-
La déclaration int n réserve un entier en mémoire.
int main()
{
int* p;
int n;
n = 17;
printf("n = %d\n\n", n);
L’instruction suivante met l’adresse de la variable n dans p (l’opérateur & retourne l’adresse de n). On dit que p pointe sur n.
p = &n;
printf("p = %p\n\n", p);
Le format %p du printf permet d’afficher l’entier p en hexadécimal.
Affichage de la valeur pointée par p :
printf("*p = %d\n\n", *p);
Incrémentation de la valeur pointée par p, c’est-à-dire n :
(*p)++;
printf("n = %d\n\n", n);
return 0;
}
Voici le résultat de l’exécution de ce programme :
L’opérateur & retourne...
Pointeurs : une erreur classique
L’utilisation directe d’adresses mémoire peut être dangereuse et demande de l’attention au programmeur. L’exemple suivant illustre ce danger.
int main()
{
int* p;
L’instruction suivante met l’adresse 0 dans le pointeur. Cette adresse est en général réservée à des programmes du système.
p = 0;
L’instruction suivante essaie de mettre la valeur 10 à l’adresse 0, donc d’écraser un morceau de programme système (ici, Windows) :
*p = 10;
return 0;
}
Windows se défend et affiche une belle petite fenêtre d’information :
Cette erreur est qualifiée d’Access Violation.
Allocation dynamique d’un tableau
L’allocation dynamique de mémoire consiste à réserver de l’espace mémoire pour des variables au cours de l’exécution du programme. Par exemple, l’allocation dynamique d’un tableau peut être utile si sa dimension n’est pas connue en début de programme.
1. Tableau à une dimension
Les déclarations suivantes réservent deux zones mémoires pouvant contenir un entier.
int main()
{
double* tableau;
int i;
La fonction calloc() réserve en mémoire un nombre d’octets égal au produit de ses paramètres.
tableau = (double*) calloc(3, sizeof(double));
printf("tableau = %p\n\n", tableau);
Ici : 3 * sizeof(double), c’est-à-dire 3 * 8 = 24 octets, c’est-à-dire l’espace correspondant à trois variables de type double.
La fonction calloc() retourne une adresse non typée (void*). Le « cast » en double* assure une cohérence avec la déclaration du pointeur tableau. L’adresse retournée par calloc() est stockée dans tableau, qui pointe sur la zone de mémoire allouée :
Le tableau s’utilise désormais comme un tableau normal :
tableau[0] = 5.1;
tableau[1]...
Travail pratique : triangle de Pascal
1. Objectif
Constituer un tableau contenant le triangle de Pascal, en utilisant l’allocation dynamique de tableaux.
2. Sujet
La correction du travail pratique : triangle de Pascal (cf. chapitre Les tableaux), propose une solution utilisant deux tableaux à une dimension. Reprendre ce programme en allouant dynamiquement les deux tableaux.
3. Triangle de Pascal : proposition de correction
Cette solution reprend la solution avec deux tableaux d’une ligne. Les tableaux sont alloués dynamiquement. Les variables l1 et l2 sont déclarées en pointeurs :
int main()
{
int* l1;
int* l2;
int* permut;
int lig,col;
int nbl;
printf("Entrez le nombre de ligne(s) du tableau : ");
scanf("%d", &nbl);
Allocation dynamique des deux tableaux :
l1 = (int*) calloc(nbl, sizeof(int));
l2 = (int*) calloc(nbl, sizeof(int));
Le nombre de lignes du triangle de Pascal n’est plus limité à 16.
l1[0] = 1;
printf("%-5d\n", l1[0]);
for (lig = 1; lig < nbl; lig++)
{
l2[0] = 1;
printf("%-5d", l2[0]);
for (col = 1; col < lig; col++)
{
l2[col] = l1[col] + l1[col - 1];
printf("%-5d", l2[col]); ...