Comprendre les pointeur

Signaler
Messages postés
11
Date d'inscription
mardi 16 juillet 2002
Statut
Membre
Dernière intervention
29 juin 2003
-
Messages postés
64
Date d'inscription
dimanche 9 février 2003
Statut
Membre
Dernière intervention
7 mars 2003
-
Je vien de commencer a programmer en c++ et j'aimerai savoir se qu'est les pointeurs et à quoi ils servent. @+
Inc@nus

4 réponses

Messages postés
455
Date d'inscription
samedi 26 octobre 2002
Statut
Membre
Dernière intervention
6 avril 2004
8
bonjour,
la question est un peu vague!
Voici quand même un essai pour débutant

on sait que les ordinateurs ne comprennent finalement que les 0 et les 1... qui sont quand même regroupés par huit en octets.
Les programmeurs humains (enfin la pluspart) préfèrent utiliser des noms : on appelle cela des variables.
Cela suffit bien souvent :
on fait
int i=0;
i++;
cout << "i=" << i<< endl;

Mais parfois, il faut pouvoir accéder à la partie "ordinateur" (on parle alors de partie "systeme")
On a besoin de savoir où sont rangées nos variables.
Où ? c'est le pointeur qui nous le dit
dans notre exemple, la variable "i" est rangée à l'adresse "&i"
Cette adresse est un POINTEUR vers la zone qui détient la VALEUR "i".
Ceci dit, l'utilisation des pointeurs - facultative pour la plupart des variables - devient très souvent obligatoire lorsque l'on travaille avec des données de type "chaine de caractères".
En voici un exemple :
char * pNom = "vieuxLion";
la variable pNom est un pointeur qui référence le premier caractère de la chaine (soit le 'v')

Il faut donc savoir travailler avec, et en particulier maîtriser l'utilisation du symbole *
Si l'on veut afficher le CONTENU situé derrière le pointeur, on utilise:
cout << *pNom ;

... et cela affiche la lettre 'v'
on utilise aussi ce que l'on appelle l'arithmétique des pointeurs, par exemple :
pNom++; cout << *pNom;

affiche cette fois ci la lettre 'i' (la suivante)
etc...
Messages postés
64
Date d'inscription
dimanche 9 février 2003
Statut
Membre
Dernière intervention
7 mars 2003

Et oui, c'est encore moi.

> > Je vien de commencer a programmer en c++ et j'aimerai savoir se qu'est les pointeurs et à quoi ils servent. @+
> > Inc@nus
>

> Cette adresse est un POINTEUR vers la zone qui détient la
>VALEUR "i".

Pas vraiment, &i représente l'adresse de i. 'int* pi = &i' sera un pointeur qui pointe vers l'adresse de i.

> Ceci dit, l'utilisation des pointeurs - facultative pour la
>plupart des variables - devient très souvent obligatoire
>lorsque l'on travaille avec des données de type "chaine de
>caractères".
> En voici un exemple :
> char * pNom = "vieuxLion";

Préférer 'const char *pNom'.

> la variable pNom est un pointeur qui référence le premier caractère de la chaine (soit le 'v')

Oui et non. Oui dans le sens que 'pNom' pointe vers l'adresse de "vieuxLion" et non dans le sens que les compilateur travaille d'une façon particulère avec les char*.

Pour bien comprendre les pointeurs, Inc@nus, considère ceci

# include
using std::cout;

int main()
{
int variable = 10;

cout << variable;
cout << &variable;
}

Ici, le premier cout est assez simple : il affiche 10. Mais le
deuxième est beaucoup plus intéressant. L'opérateur &
devant un nom retourne son *adresse* dans la mémoire (car
chaque valeur a son espace mémoire). L'affichage est
différent dans le temps, mais disons qu'il affiche 0x0005.
Cela voudrait dire que 'variable' est à la 'case' mémoire
numéro 0x0005 et que cette 'case' contient la valeur '10'.

À quoi ça sert? À beaucoup de choses, mais en même temps à pas grand choses. L'exemple classique est celui-ci :

int main()
{
int variable = 10;
int *pointeur = &variable;

cout << pointeur;
cout << *pointeur;
}

Ici, 'variable' est un int et contient 10. Tu seras probablement tenté de dire que 'pointeur' est un int aussi, mais non. 'pointeur' est, justement, un *pointeur* vers un int. Et comme de fait, on ne stocke pas une valeur quelconque dans ce pointeur, on y stocke *l'adresse* de 'variable' en utilisant l'opérateur & qu'on a vu plus haut.

Le premier cout affiche donc ce qu'on a mis dans 'pointeur' et ce qu'on y a mis, c'est l'adresse de 'variable', donc quelque chose comme 0x0005. Le deuxième cout fait quelque chose d'encore mieux : il va chercher la valeur qui est à l'adresse contenue dans 'pointeur'.

Confus? Très bien, c'est ça qu'il faut (faut bien filtrer les programmeurs, sinon y'en aurait trop :) ).

Je récapitule. La variable 'pointeur' n'est pas une variable ordinaire. Elle ne sert *pas* à contenir des valeurs comme n'importe qu'elle autre variable. Elle ne sert qu'à stocker une adresse. L'adresse d'une autre variable. J'ai dis plus haut que

&variable

retourne l'adresse, dans la mémoire, de 'variable'. On stocke donc cette adresse dans le pointeur. Maintenant,

variable == 10

et

pointeur == 0x0005

(en supposant toujours que l'adresse de 'variable' est 0x0005). Maintenant, si on affiche le pointeur, ça ne servira pas à grand chose. Mais on a la possibilité d'aller voir ce qu'il y a à cette adresse et on le fait en (ré)utilisant l'opérateur * :

cout << *pointeur;

Ici, on dit "je veux la valeur qui est à l'adresse contenue dans 'pointeur'", donc, en fait, la valeur de 'variable'.

Les étoiles t'en font voir? L'astérisque sert à deux choses ici :
1) à la définition d'un pointeur :

int *p;

Ici, p est un pointeur vers un int.

2) à chercher la valeur qu'il y a à l'adresse contenue dans le pointeur :

cout << *p;

Ici, on va chercher la valeur qui est à l'adresse contenue dans 'p'. Le vrai mot est 'déréférencement'. Décortiquons ce mot : "référencer" veut dire que 'pointeur' est comme une référence de 'variable'. "Référencement" est l'action de mettre une addresse dans 'pointeur' et déréférencement est l'action d'aller chercher la valeur à cette adresse.

Ouf. Mais ça ne te dis toujours rien sur l'utilité.

Eh bien sache qu'il n'y en a plus beaucoup. Le C++ à introduit la notion de 'référence' qui ressemble à un pointeur toujours déréférencé. Lis à propos de ça dans ton livre (si tu n'en as pas, honte à toi. Cours vite en acheter un, je recommande "Programmer en langage C++" de Claude Delannoy").

Mais encore, l'usage le plus fréquent est l'allocation dynamique à l'aide de 'new'. Le reste peut pas mal se faire avec les références.

Mais pour satisfaire ta curiosité insatiable, voici quand même un exemple :

# include
using std::cout;

void ajouter_un(int maCopie)
{
maCopie = maCopie + 1;
}

int main()
{
int monChiffre = 10;

ajouter_un(monChiffre);

cout << monChiffre;
}

Ici, il n'y a pas de pointeurs. On a un int qui s'apelle 'monChiffre' qui contient 10. On passe cette variable à ajouter_un() qui lui rajoute 1 et on revient au main() pour afficher 'monChiffre'. Résultat? 10, évidemment.

La raison est que 'monChiffre' est passé *par valeur*, c'est-à-dire que ajouter_un() ne joue pas avec 'monChiffre', mais bien avec une *copie* de 'monChiffre'. Le compilateur a pris ce qu'il y avait dans 'monChiffre' et l'a copié dans 'maCopie'. ajouter_un() a ensuite incrémenté 'maCopie' et est retourné au main() où 'monChiffre' n'a jamais été modifié.

Ce qui nous cause problème. Nous, on voulait ajouter 1 à cette variable. La solution? Les pointeurs (ça tombe bien).

La solution n'est donc plus de passer la *valeur* de 'monChiffre', mais bien son *adresse*. Ainsi, ajouter_un() pourra ajouter 1 non pas à une variable copiée, mais bien à 'monChiffre'.

# include
using std::cout;

void ajouter_un(int* monPointeur)
{
*monPointeur = *monPointeur + 1;
}

int main()
{
int monChiffre = 10;

ajouter_un(&monChiffre);

cout << monChiffre;
}

Beaucoup d'étoiles, non? Maintenant, ajouter_un() prend une adresse comme argument, non plus une valeur. Et c'est ce qu'on fait : en appelant ajouter_un(), on passe *l'adresse* de 'monChiffre' en utilisant le &. À l'intérieur de ajouter_un(), 'monPointeur' pointe vers 'monChiffre'. Voyons maintenant

*monPointeur = *monPointeur + 1;

Partons de la droite. On prend la *valeur* qui est à l'adresse stockée dans 'monPointeur', donc en fait on prend la valeur de 'monChiffre'. On lui additionne 1 et on le stocke à l'endroit où pointe 'monPointeur', donc, dans 'monChiffre'.

Et voilà, 'monChiffre' est incrémenté et nous sommes heureux.

Mais voyons ce qui se serait passé sans étoiles :

monPointeur = monPointeur + 1;

Qu'y a-t-il dans 'monPointeur'? L'adresse de 'monchiffre'. Alors tout ce qu'on fait est de prendre cette adresse (0x0005), de lui ajouter 1 (0x0006) et de la mettre dans monPointeur. (En fait, on ajoute pas 1, mais bien sizeof(int), mais c'est pas grave). Qu'est-ce que ça nous donne? Eh bien on a maintenant un pointeur qui pointe vers un espace qui n'existe pas (il n'y a rien à 0x0006). Donc, mauvais. Voyons ceci :

monPointeur = *monPointeur + 1;

Ici, toujours en partant de la droite, on prend la valeur qui est à l'adresse stockée dans 'monPointeur', c'est-à-dire la valeur de 'monChiffre' et on lui ajoute un. Ça fait 11 (il y avait déjà 10 dans 'monChiffre'). Et maintenant, on ajoute 11 à... quoi? À l'adresse contenue dans 'monPointeur'! Ce qui nous donne maintenant un pointeur qui pointe vers un autre espace (0x0010, c'est du hexadécimal, rappele toi) qui n'existe toujours pas. Donc mauvais aussi. La solution est donc bel et bien

*monPointeur = *monPointeur + 1;

Ouf encore. Quelques petites choses en terminant, lorsque je disais que 'pointeur' est un pointeur vers un int, c'est que 'pointeur' ne peut contenir que l'adresse d'un int :

double monDouble = 10.5;
int *pointeur = &monDouble;

ne compile même pas (a value of type "double *" cannot be used to initialize an entity of type "int *"), ce qui est bien normal.

Et voilà. La morale est 1) achète un bon livre et 2) va voir mon site web où t'auras plus d'aide encore (oui oui, je fais de la pub).

Bonne soirée!
Messages postés
455
Date d'inscription
samedi 26 octobre 2002
Statut
Membre
Dernière intervention
6 avril 2004
8
désolé, ce n'est pas comme cela que l'on s'adresse à un débutant
Messages postés
64
Date d'inscription
dimanche 9 février 2003
Statut
Membre
Dernière intervention
7 mars 2003

> désolé, ce n'est pas comme cela que l'on s'adresse à un
>débutant

<snip>

Je tiens un site web depuis plus d'un an avec des tutoriaux sur le basic et le C++, la compréhension des gens est donc importante pour moi.

Si tu pouvais (et Incanus aussi) m'en dire plus, ça m'aiderait beaucoup.

Merci,