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;
}
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