Les pointeurs

Un pointeur est une variable contenant l'adresse d'une autre variable d'un type donné. les pointeurs permettent de définir des structures dynamiques, c'est-à-dire qui évolue au cours du temps comme des tableaux dynamiques par exemple.


Principe

En préambule il est bon de repréciser que  chaque variable correspond à des cases (octets) dans la mémoire centrale de l'ordinateur.

Selon le type de la variable, le nombre de cases est plus ou moins important.

Une déclaration de variable dans un programme correspond à une réservation d'octets dans la mémoires.

Chaque case mémoire est caractérisée par son adresse.

Il est donc possible, dans un programme, d'accéder au contenu d'une variable

    • par le nom de la variable :

unsigned char maVar; //réserve l'emplacement d'un octet en mémoire pour maVar

maVar =4; //on accède à la donnée maVar par son nom et on peut la modifier

    • par l'adresse de la variable


Adresse d'une variable

Le plus souvent il n'est pas nécessaire de connaître l'adresse de la variable. Elle est transparente pour le programmeur mais on peut l'obtenir en utilisant le caractère "&"

Exemple : 

dans l'exemple précédent l'instruction :

cout<<&maVar;

donnerait 00882AD0

Pointeur

Un pointeur est donc une variable qui contient l'adresse d'une variable.

Un pointeur est toujours typé et doit être déclaré comme toute autre variable.

Déclaration :

forme :  type * nom_du_pointeur

exemple : int * mon_pointeur;


En reprenant l'exemple précédent :

unsigned char *pVar(0); //création d'un pointeur dont le type est identique à celui de maVar.On l'initialise à 0

unsigned char temp;

pVar = &maVar; //pVar prend la valeur de l'adresse de maVar

temp = *pVar;//après cette opération temp sera égal à maVar


Cas d'un tableau

int t[5]; //on créé un tableau de 5 cases

int * p; //on créé un pointeur

p=&t ;//on associe le pointeur au tableau

*p=15; //revient à faire t[0]=15 car *p pointe sur la première donnée du tableau

*(p+1)=10; //revient à faire t[1]=10;

Création manuelle d'un pointeur

Si le pointeur doit être créé de manière manuelle, ce qui signifie qu'il n'a pas été déclaré dans l'entête du programme, il est nécessaire de réserver de la place dans la mémoire avec l'instruction NEW.

pVar = new (unsigned char); //on demande au système de trouver de la place dans la mémoire

Pour libérer la mémoire, il faudra ensuite utiliser l'instruction DELETE

delete pVar; // on libère la mémoire

Remarque : lors de la fermeture normale d'un programme, les réservation sont automatiquement libérées par le système d'exploitation.

Pourquoi utiliser des pointeurs

  • Pour créer dynamiquement des données en mémoire :

Exemple de création de 100 boutons dans une fenêtre (this) :

mainwindow.cpp

    for(int i = 0; i < 100; i++)

        {

        mesBoutons[i] = new QPushButton("", this);

        mesBoutons[i]->setMinimumWidth(40);

        mesBoutons[i]->setMinimumHeight(40);

         }

  • Pour partager des données entre les fonctions ou dans plusieurs morceaux de code : c'est l'exemple ci-dessous.

Pointeurs et paramètres de fonctions

Il n'est pas possible en C de passer un tableau en paramètre de fonctions. Il faut donc passer par les pointeurs.

Exemple de fonction qui recherche le maximum dans un tableau :

#include <iostream>

#include <stdlib.h>

using namespace std; //précise que l'on utilise des bibliothèques standards

// =============== Fonction de recherche =================================================

int max(int *tab,unsigned taille)//le tableau tab passe en pointeur

{

  int maximum;

  maximum = tab[0];

  for(int i=0;i<taille;++i){

    if  (tab[i] > maximum) maximum=tab[i];

  }

   return maximum;

}

//============ Utilisation de la fonction ==================================

int main()

{

    const int taille = 5;

    int *tab = (int *) calloc(taille,sizeof(int));//réserve la mémoire pour le tableau et met à 0 les cases mémoires

//----------------- fixe les valeurs  : sans intérêts dans cette étude -------------------------  

 for(int i=0;i<taille;++i){

      tab[i] = (i-4)-i*i;

      cout<<"tab["<<i<<"] = "<<tab[i]<<endl;

    }

//------------------------------------------------------------------------------------------------------------------------

    cout<<"maximum :"<<max(tab,taille)<<endl;

}


Tableau dynamique

 Comme il est nécessaire de déclarer une variable avant de l'utiliser et comme la taille d'un tableau n'est pas forcément connue, on peut contourner cette contrainte en déclarant un pointeur vers un tableau dont on définira la taille ultérieurement.

Cette déclaration est possible avec la commande NEW : nom_du_pointeur= new type[taille]

Exemple

Dans l'initialisation (header par exemple) :

int *tableau;
int taille;


Dans le code :

cin >> taille;

tableau = new int[taille];

Autre exemple : Placement des données d'un fichier dans un tableau

Dans l'entête :

    unsigned char *filecontent;

Dans le code :

QFile orgBMPfile("image.bmp"); //on lie un type file à un fichier image

taillefichier=10000; //la taille totale du fichier fait 10000 octets

filecontent = new unsigned char[taillefichier]; //on créé le tableau

orgBMPfile.read((char *)filecontent, taillefichier);// on copie toutes les données (au nombre de taille fichier) dans le tableau

Remarque : (char *) permet ici d'adapter les types à la fonction read


Remarque : Une autre méthode consiste à utiliser les vecteurs