# Langage C++/Pointeur, Tableaux et références
## Les Pointeurs

Les pointeurs servent à accéder aux données en mémoire par le biais de leur adresse. Le type pointeur est un entier non signé dont la taille dépend du type de processeur et du mode en cours. En gros, et pour simplifier, il utilise le format du "unsigned long int" actuellement en cours, où il enregistre l'adresse mémoire de la donnée à pointer.
| Adresse | Valeur | Nom de variable |
| 0x635 | 'P' | x |
| 0x7B8 | 0x00000635 | p |
Voici la syntaxe :
Où <Type> est le type de la donnée en mémoire, "*" signifie que l’on a affaire à un pointeur, <NomPointeur> est l'identifiant du pointeur et <Valeur> l'adresse mémoire (unsigned long int) où le pointeur doit aller chercher la donnée.

### Affectation d'adresse

En C++, il est utile de récupérer l'adresse d'une variable ou d'une constante en utilisant l'opérateur "&" qui signifie "adresse de" et se place à gauche de l'identifiant.
Comprendre : création d'une variable nommée "p" de type pointeur sur char "char*" prenant pour valeur "=" l'adresse de "&" la variable "x"

### Mécanique d'Adressage

En C++, il peut être utile de copier l'adresse d'une variable pointée par un pointeur sur un autre pointeur. Cela se fait ainsi :
On n'utilise pas l'opérateur "adresse de" dans ce cas là car "p1" renvoie l'adresse de "x"

### Déréférencement

En C++, il peut être utile de récupérer la valeur d'une variable pointée par un pointeur. Cela se fait ainsi :

### Arithmétique des pointeurs

En C++, les pointeurs ont leur propre algorithmique. L'incrémentation et la décrémentation est particulière pour ce type. En fait, l'incrémentation (ainsi que la décrémentation) se fait en multipliant la taille du type du pointeur (obtenue avec sizeof) par la valeur que l’on veut lui ajouter/retrancher.
L'arithmétique de pointeur est un concept particulier qu’il est possible d’éviter avec les notations liées au tableau. En particulier en C++, il est intéressant de s'interdire de recourir à l’arithmétique de pointeurs.
Ce comportement permet la création et l’utilisation des tableaux. Nous verrons cela un peu plus bas.
Lorsque les pointeurs sont créés, ils prennent la valeur d'adresse qu’il y avait à l'emplacement qu’ils occupent. C'est pour cela qu’il faut impérativement les initialiser avant de s'en servir. Dans le cas contraire on peut assister, parfois, à des comportements des plus étranges.
Le pire des cas est celui du pointeur non initialisé à qui l’on affecte une valeur. Dans certains cas rares, l’application fonctionne sur l'ordinateur de développement car la donnée que le pointeur va prendre comme adresse, correspond à une adresse valide et donc le programme se déroule normalement.
Mais après installation sur le poste client, l’application plante car la donnée en mémoire n'est plus la même et ne correspond plus à une adresse valide.
* Il est inacceptable d’utiliser la forme calculée des pointeurs pour accéder à des tableaux. Seule la forme entre crochets est valide. Le jour où un développeur instanciera un tableau dynamique sur un pointeur utilisé sous forme calculée, le programme plantera car le compilateur sera incapable de faire les déréférencements.
Préférez donc la forme entre crochets
à la forme calculée
* Début de l'exemple
* Exemple
* a=*(t+2*3));
* Fin de l'exemple

### Les Tableaux

En C++, les tableaux permettent de mémoriser des ensembles de données de même type. Il en existe 2 sortes, les tableaux statiques et les tableaux dynamiques.
La différence entre tableaux statiques et dynamiques est que les tableaux statiques sont dans tous les cas des groupes d'octets contigus monolithiques dans la pile alors que les tableaux dynamiques multidimensionnels sont, le plus souvent, des groupes d'octets contigus disséminés en plusieurs paquets dans le tas.

#### Tableaux "Statiques"

Le fait qu’ils soient enregistrés en pile fait que leur taille doit être connue dès la compilation et donc être constante. En effet, pour le processeur, il serait mal vu de pouvoir redimensionner le tableau après la création d'autres variables en pile. Dans le cas de l'agrandissement, on écraserait les nouvelles variables et dans le cas de la diminution, on ferait des "TROUS" dans la pile, qui alors s'effondrerait.(Rappelez vous qu’il faut considérer la pile comme une pile d'assiettes)
On peut calculer le volume que le tableau statique occupe en mémoire, en multipliant la taille du type utilisé par le nombre d'éléments.
Ainsi un tableau tridimensionnel de 4 * 3 * 2 valeurs int, fera :
4(grilles) * 3(lignes) * 2(colonnes) * 4(Octets du type int) = 24(éléments)* 4(Octets du type int) = 96 Octets contigus en pile.
Voici la syntaxe :
ou
ou
Où <Type> est le type des éléments du tableau, <NomTableau> est le nom de la variable tableau,(...) indique que c’est un tableau à N dimensions, <ConstanteN> est le nombre d'éléments, constant, de la dimension N du tableau (facultatif si on a défini une liste de valeurs), = assigne des valeurs au tableau (facultatif si <ConstanteN> est présent), {,(...),} est une liste de valeurs des dimensions (il y en a autant que <ConstanteN>, facultatif si <ConstanteN> est présent), et <VariableN1,...VariableNM> sont les différentes valeurs que le tableau doit affecter aux éléments de la ligne N (il doit y en avoir autant que <ConstanteN>, facultatif si <ConstanteN> est présent).
Concrètement, voyons ce que ça donne si on reprend notre exemple :
Les tableaux statiques, sont organisés par lignes. Cela signifie que lorsque l’on incrémente l'indice du tableau, on change de colonne plus rapidement que ce que l’on change de ligne.
Pour reprendre notre exemple, cela donnerait (en supposant que l'adresse de base du tableau t1 soit 0x02C0) :
| Adresse | Index | n$^o$ Élément | Grille | Ligne | Colonne | Valeur |
| 0x02C0 | t1[0][0][0] | 0 | 0 | 0 | 0 | 1 |
| 0x02C4 | t1[0][0][1] | 1 | 0 | 0 | 1 | 2 |
| 0x02C8 | t1[0][1][0] | 2 | 0 | 1 | 0 | 3 |
| 0x02CC | t1[0][1][1] | 3 | 0 | 1 | 1 | 4 |
| 0x02D0 | t1[0][2][0] | 4 | 0 | 2 | 0 | 5 |
| 0x02D4 | t1[0][2][1] | 5 | 0 | 2 | 1 | 6 |
| 0x02D8 | t1[1][0][0] | 6 | 1 | 0 | 0 | 7 |
| 0x03A8 | t1[2][2][1] | 17 | 2 | 2 | 1 | 18 |
| 0x03AC | t1[3][0][0] | 18 | 3 | 0 | 0 | 19 |
| 0x03B0 | t1[3][0][1] | 19 | 3 | 0 | 1 | 20 |
| 0x03B4 | t1[3][1][0] | 20 | 3 | 1 | 0 | 21 |
| 0x03B8 | t1[3][1][1] | 21 | 3 | 1 | 1 | 22 |
| 0x03BC | t1[3][2][0] | 22 | 3 | 2 | 0 | 23 |
| 0x03C0 | t1[3][2][1] | 23 | 3 | 2 | 1 | 24 |

#### Pointeurs et Tableaux Statiques

Nous avons pu voir tout à l’heure que l'arithmétique des pointeurs permet de travailler sur plus d'une valeur voyons ce que cela donne :

#### Tableaux "Dynamiques"

Pour un tableau dynamique, il existe deux méthodes.

##### Tableaux Compacts

On peut utiliser le format des tableaux statiques multidimensionnels que l’on reproduit en tas.
Voici la syntaxe de déclaration :
Où <Type> est le type du tableau, <NomVariable> est le nom identifiant du tableau, <Variable> est une variable entière non signée définissant la première dimension du tableau, <ConstanteN> sont des constantes entières non signées définissant les autres dimensions du tableau.
Aucun tableau dynamique n'est assignable à la déclaration. On ne peut pas en C++ assigner des valeurs à un tableau dynamique lors de sa création.
Cela n’est pas très judicieux pour trois raisons :
* La première c’est que les tailles des dimensions du tableau sont fixées définitivement (à moins de recréer le tableau complet).
* La deuxième c’est que les différents éléments ne sont pas désolidarisables du tableau.
* La troisième pour redimensionner le tableau il faut le recopier intégralement.
Techniquement, on peut faire mieux.
La seule raison valable qui peut amener à utiliser ces types de tableaux dynamiques est leur forme compacte. Ceci dit ils ne font réellement gagner de l'espace que sur les tableaux dont on connaît à l'avance la longueur. En effet, la lourdeur du traitement pour ajouter ou soustraire des éléments est souvent rédhibitoire.
Il ne reste donc qu'une solution techniquement valable en environnement PC : L'indirection de pointeurs multiples.

##### Indirection de Pointeurs

Le but du jeu est de créer un tableau de pointeurs où chaque pointeur pointe vers un autre tableau de pointeurs... (ce récursivement pour chaque dimension)... où chaque pointeur pointe vers un élément.
Où <Type> est le type du tableau, <NomTableau> est le nom du tableau et <Variable> une variable entière non signée.
Voyons comment cela est représenté en mémoire :
Voici un exemple concret qui montre comment créer/détruire et manipuler un tableau utilisant l'indirection de pointeurs.

### Pointeurs sur Méthodes

En C++, il est possible de créer des pointeurs sur des méthodes. Cela est surtout utile pour lier les fonctions d'une bibliothèque de liens dynamiques ou, plus intéressant, pour appeler des méthodes que l’on ne connaît pas à l'avance mais qui auront un prototype que l’on a défini. Cela permet, par exemple, de créer une liste de tâches à accomplir suite à un évènement donné.
Où "<TypeRetour>" est le type de retour de la méthode à pointer, "<NomPointeur>" est le nom attribué au pointeur, "<TypeParametre>" et "<NomParametres>" sont respectivement les types et noms des paramètres de la méthode
Remarquez bien les parenthèses autour de "*LaMethode". Si on ne les avait pas mis comme dans cet exemple :
Le compilateur aurait compris "LaMethode" une méthode qui accepte un paramètre "Params" de type "int" et retourne un pointeur de type "bool";

#### Pointeurs sur Méthodes Encapsulées

Il est possible de créer des pointeurs sur des méthodes qui sont encapsulées dans des classes à deux conditions :
* la méthode doit être publique,
* la méthode doit être statique.

## Les Références

Devant la difficulté qu'avaient la plupart des programmeurs de l'époque, à gérer convenablement la mémoire avec les pointeurs, le C++ a introduit la notion de référence. Une référence est un ALIAS, un autre nom, pour une variable DÉJÀ EXISTANTE. À l'inverse du pointeur, une référence n'occupe pas de place en mémoire. Le compilateur la remplace par le nom de la variable actuellement assignée dans le code après avoir déroulé les traitements mais avant de traduire ce code en binaire.
Où "<Type>" est le type de la référence "<NomRéférence>" est l'identifiant de la référence et <NomVariable> est l'identifiant de la variable que la référence doit désigner. Contrairement aux pointeurs, la référence doit impérativement être assignée dès la déclaration et il n’est pas possible de réassigner la référence à une autre variable après initialisation.
Ou plus concrètement :

### Références sur Méthodes

À l'instar du pointeur, il est possible de référencer une méthode.
Où "<Type>" est le type de retour de la méthode à référencer, "<NomRéférence>" est l'identifiant de la référence, <TypeParam> et <NomParam> sont respectivement le type et le nom de l'image des paramètres de la méthode à référencer et <NomMéthode> est l'identifiant de la méthode que la référence doit désigner. Contrairement aux pointeurs, la référence doit impérativement être assignée dès la déclaration et il n’est pas possible de réassigner la référence à une autre méthode après initialisation.

## Le Casting :

L'une des fonctionnalités les plus appréciées dans la manipulation des variables est l'opérateur de casting, ou de refonte, que sont les parenthèses "".
* Syntaxe:
* (<Type>)[<Constante>|<Variable>]
Où <Type> est le type dans lequel la valeur <Constante> ou <Variable> doit être refondue.
En fait, on peut refondre des valeurs de types différents de manière sûre si au moins l'une de ces conditions est remplie :
* La valeur source peut être transcodée dans le type de destination.(ex. : (char)'A'; est équivalent à (char)41; "41" est un const int)
* Le type de la valeur source peut être approximée ou être un sous ensemble du type de la variable de destination (numérique, ex. : (double)int ou (int)double).
* Le type de la valeur source hérite du type de la variable de destination (upcasting).
* Le type de la valeur source est parente du type de la variable de destination (downcasting).
* Attention : L'utilisation de l'opérateur de refonte est à utiliser avec précautions. Le compilateur ne vous avertira pas si un dépassement de capacité a lieu ou si vous faites des downcasting (refontes descendantes) avec des types de nature différente

#### Exemples :

Exemple de cast pour une valeur constante
Autre exemple pour une variable :
| Méthodes | Portée du code |