« Langage C++/Pointeur, Tableaux et références » : différence entre les versions

Une page de Wikiversité, la communauté pédagogique libre.
Contenu supprimé Contenu ajouté
→‎Tableaux "Statiques" : selon discussion
Ligne 40 : Ligne 40 :
{{Définition
{{Définition
| contenu =
| contenu =
'''Syntaxe:''' <source lang="cpp"><Type>* <NomPointeur>[ = <Valeur>];</source>}}
'''Syntaxe:''' <syntaxhighlight lang="cpp"><Type>* <NomPointeur>[ = <Valeur>];</syntaxhighlight>}}


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.
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.
Ligne 52 : Ligne 52 :
| contenu =
| contenu =


<source lang="cpp">
<syntaxhighlight lang="cpp">
char x = 'A'; // création de la variable char en pile
char x = 'A'; // création de la variable char en pile
char* p = &x; // création de la variable pointeur sur char en pile et affectation de l'adresse de la variable en pile.
char* p = &x; // création de la variable pointeur sur char en pile et affectation de l'adresse de la variable en pile.
</syntaxhighlight>
</source>
}}
}}


Ligne 68 : Ligne 68 :
| contenu =
| contenu =


<source lang="cpp">
<syntaxhighlight lang="cpp">
char x = 'A'; // création de la variable char en pile
char x = 'A'; // création de la variable char en pile
char* p1 = &x; // création de la variable pointeur sur char en pile et affectation de l'adresse.
char* p1 = &x; // création de la variable pointeur sur char en pile et affectation de l'adresse.
char* p2 = p1; // copie la valeur de l'adresse pointée par p1 dans le pointeur p2. (p2 == p1), (p2 == &x)
char* p2 = p1; // copie la valeur de l'adresse pointée par p1 dans le pointeur p2. (p2 == p1), (p2 == &x)
</syntaxhighlight>
</source>
}}
}}


Ligne 85 : Ligne 85 :
| contenu =
| contenu =


<source lang="cpp">
<syntaxhighlight lang="cpp">
char x = 'A'; // création de la variable char en pile
char x = 'A'; // création de la variable char en pile
char* p = &x; // création de la variable pointeur sur char en pile et affectation de l'adresse.
char* p = &x; // création de la variable pointeur sur char en pile et affectation de l'adresse.
char y = *p; // Déréférencement du pointeur "p" pour obtenir la valeur pointée (y == 'A')
char y = *p; // Déréférencement du pointeur "p" pour obtenir la valeur pointée (y == 'A')
</syntaxhighlight>
</source>
}}
}}


Ligne 101 : Ligne 101 :
| contenu =
| contenu =


<source lang="cpp">
<syntaxhighlight lang="cpp">
int a; // création de la variable int en pile (sizeof(int) == 4)
int a; // création de la variable int en pile (sizeof(int) == 4)
int* p = &a; // création de la variable pointeur sur int et affectation de l'adresse de a.
int* p = &a; // création de la variable pointeur sur int et affectation de l'adresse de a.
Ligne 117 : Ligne 117 :
y = p - 1; // (y == &a + 4 octets)
y = p - 1; // (y == &a + 4 octets)
z = p - 1; // (z == &a)
z = p - 1; // (z == &a)
</syntaxhighlight>
</source>
}}
}}


Ligne 130 : Ligne 130 :
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. }}
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
Préférez donc la forme entre crochets
{{Exemple | contenu = <source lang="cpp">a = t[2][3];</source> }}
{{Exemple | contenu = <syntaxhighlight lang="cpp">a = t[2][3];</syntaxhighlight> }}
à la forme calculée
à la forme calculée
{{Attention|Avec_fond = oui|
{{Attention|Avec_fond = oui|
{{Exemple | contenu = <source lang="cpp"> a=*(t+2*3)); </source> }}
{{Exemple | contenu = <syntaxhighlight lang="cpp"> a=*(t+2*3)); </syntaxhighlight> }}
}}
}}


Ligne 159 : Ligne 159 :
{{Définition
{{Définition
| contenu =
| contenu =
'''Syntaxe:''' <source lang="cpp"><Type> <NomTableau> [<Constante1>](...)[<ConstanteN>];</source>
'''Syntaxe:''' <syntaxhighlight lang="cpp"><Type> <NomTableau> [<Constante1>](...)[<ConstanteN>];</syntaxhighlight>


ou
ou


<source lang="cpp"><Type> <NomTableau> [<Constante1>](...)[<ConstanteN>] = {{<Variable11,...,Variable1M>},(...),{<VariableN1,...,VariableNM>}};</source>
<syntaxhighlight lang="cpp"><Type> <NomTableau> [<Constante1>](...)[<ConstanteN>] = {{<Variable11,...,Variable1M>},(...),{<VariableN1,...,VariableNM>}};</syntaxhighlight>


ou
ou


<source lang="cpp"><Type> <NomTableau> [](...)[] = {{<Variable11,...,Variable1M>},(...),{<VariableN1,...,VariableNM>}};</source>
<syntaxhighlight lang="cpp"><Type> <NomTableau> [](...)[] = {{<Variable11,...,Variable1M>},(...),{<VariableN1,...,VariableNM>}};</syntaxhighlight>
}}
}}


Ligne 179 : Ligne 179 :
| contenu =
| contenu =


<source lang="cpp">
<syntaxhighlight lang="cpp">
// Valeurs constantes
// Valeurs constantes
const int Grilles = 4;
const int Grilles = 4;
Ligne 234 : Ligne 234 :
}
}
};
};
</syntaxhighlight>
</source>
}}
}}


Ligne 378 : Ligne 378 :
| contenu =
| contenu =


<source lang="cpp">
<syntaxhighlight lang="cpp">
// Valeur variable
// Valeur variable
int trois = 3;
int trois = 3;
Ligne 391 : Ligne 391 :
int c = pInt1[2]; // c == 3
int c = pInt1[2]; // c == 3


</syntaxhighlight>
</source>
}}
}}


Ligne 406 : Ligne 406 :
{{Définition
{{Définition
| contenu =
| contenu =
'''Syntaxe:''' <source lang="cpp"><Type>* <NomVariable>[<Constante1>](...)[<ConstanteN>] = new <Type>[<Variable>][<Constante1>](...)[<ConstanteN>];</source>}}
'''Syntaxe:''' <syntaxhighlight lang="cpp"><Type>* <NomVariable>[<Constante1>](...)[<ConstanteN>] = new <Type>[<Variable>][<Constante1>](...)[<ConstanteN>];</syntaxhighlight>}}


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.
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.
Ligne 415 : Ligne 415 :
| contenu =
| contenu =


<source lang="cpp">
<syntaxhighlight lang="cpp">
// Valeurs constantes
// Valeurs constantes
const int vColonnes = 2;
const int vColonnes = 2;
Ligne 427 : Ligne 427 :


delete [] vTableau;
delete [] vTableau;
</syntaxhighlight>
</source>
}}
}}


Ligne 446 : Ligne 446 :
{{Définition
{{Définition
| contenu =
| contenu =
'''Syntaxe:''' <source lang="cpp"><Type> <NomTableau> = new <Type>[<Variable>];</source>}}
'''Syntaxe:''' <syntaxhighlight lang="cpp"><Type> <NomTableau> = new <Type>[<Variable>];</syntaxhighlight>}}


Où <Type> est le type du tableau, <NomTableau> est le nom du tableau et <Variable> une variable entière non signée.
Où <Type> est le type du tableau, <NomTableau> est le nom du tableau et <Variable> une variable entière non signée.
Ligne 458 : Ligne 458 :
| contenu =
| contenu =


<source lang="cpp">
<syntaxhighlight lang="cpp">
#include <iostream>
#include <iostream>


Ligne 615 : Ligne 615 :
}
}


</syntaxhighlight>
</source>
}}
}}


Ligne 624 : Ligne 624 :
{{Définition
{{Définition
| contenu =
| contenu =
'''Syntaxe:''' <source lang="cpp"><TypeRetour> (*<NomPointeur>)(<TypeParametre><NomParametres>);</source>}}
'''Syntaxe:''' <syntaxhighlight lang="cpp"><TypeRetour> (*<NomPointeur>)(<TypeParametre><NomParametres>);</syntaxhighlight>}}


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
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
Ligne 631 : Ligne 631 :
| contenu =
| contenu =


<source lang="cpp">
<syntaxhighlight lang="cpp">
// Méthode
// Méthode
bool MaMethode(int MonParametre)
bool MaMethode(int MonParametre)
Ligne 642 : Ligne 642 :
// Appel de la méthode via le pointeur
// Appel de la méthode via le pointeur
bool a = LaMethode(8);
bool a = LaMethode(8);
</syntaxhighlight>
</source>
}}
}}
Remarquez bien les parenthèses autour de "*LaMethode". Si on ne les avait pas mis comme dans cet exemple :
Remarquez bien les parenthèses autour de "*LaMethode". Si on ne les avait pas mis comme dans cet exemple :
Ligne 649 : Ligne 649 :
| contenu =
| contenu =


<source lang="cpp">
<syntaxhighlight lang="cpp">
// Méthode
// Méthode
bool MaMethode(int MonParametre)
bool MaMethode(int MonParametre)
Ligne 660 : Ligne 660 :
// Appel de la méthode via le pointeur
// Appel de la méthode via le pointeur
bool a = LaMethode(8);
bool a = LaMethode(8);
</syntaxhighlight>
</source>
}}
}}


Ligne 676 : Ligne 676 :
| contenu =
| contenu =


<source lang="cpp">
<syntaxhighlight lang="cpp">
//Classe
//Classe
class MaClasse
class MaClasse
Ligne 691 : Ligne 691 :
// Appel de la méthode via le pointeur
// Appel de la méthode via le pointeur
bool a = LaMethode(8);
bool a = LaMethode(8);
</syntaxhighlight>
</source>
}}
}}


Ligne 701 : Ligne 701 :
{{Définition
{{Définition
| contenu =
| contenu =
'''Syntaxe:''' <source lang="cpp"><Type>& <NomRéférence> = <NomVariable>;</source>}}
'''Syntaxe:''' <syntaxhighlight lang="cpp"><Type>& <NomRéférence> = <NomVariable>;</syntaxhighlight>}}


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.
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.
Ligne 710 : Ligne 710 :
| contenu =
| contenu =


<source lang="cpp">
<syntaxhighlight lang="cpp">
//Variable à référencer
//Variable à référencer
int MaVariable = 5;
int MaVariable = 5;
Ligne 717 : Ligne 717 :
// Modification de la variable via la référence.
// Modification de la variable via la référence.
LaVariable = 8;
LaVariable = 8;
</syntaxhighlight>
</source>
}}
}}


Ligne 727 : Ligne 727 :
{{Définition
{{Définition
| contenu =
| contenu =
'''Syntaxe:''' <source lang="cpp"><Type> (&<NomRéférence>)(<TypeParam> <NomParam>) = <NomMéthode>;</source>}}
'''Syntaxe:''' <syntaxhighlight lang="cpp"><Type> (&<NomRéférence>)(<TypeParam> <NomParam>) = <NomMéthode>;</syntaxhighlight>}}


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.
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.
Ligne 734 : Ligne 734 :
| contenu =
| contenu =


<source lang="cpp">
<syntaxhighlight lang="cpp">
bool MaMethode(int MonParametre)
bool MaMethode(int MonParametre)
{
{
Ligne 743 : Ligne 743 :
// Appel de la méthode via la référence.
// Appel de la méthode via la référence.
bool a = LaMethode(8);
bool a = LaMethode(8);
</syntaxhighlight>
</source>
}}
}}


Ligne 773 : Ligne 773 :
| contenu =
| contenu =


<source lang="cpp">
<syntaxhighlight lang="cpp">
// Création d'une variable "c" de type "char" non initialisée.
// Création d'une variable "c" de type "char" non initialisée.
char c;
char c;
Ligne 779 : Ligne 779 :
// cast de la valeur constante 0x43 (0x43 = 'C') en char.
// cast de la valeur constante 0x43 (0x43 = 'C') en char.
c = (char)0x43;
c = (char)0x43;
</syntaxhighlight>
</source>
}}
}}


Ligne 787 : Ligne 787 :
| contenu =
| contenu =


<source lang="cpp">
<syntaxhighlight lang="cpp">
// Création d'une variable "c" de type "char" non initialisée.
// Création d'une variable "c" de type "char" non initialisée.
char c;
char c;
Ligne 797 : Ligne 797 :
// cast de la valeur de la variable ('A' = 0x41 = 65) en int.
// cast de la valeur de la variable ('A' = 0x41 = 65) en int.
i = (int)c;
i = (int)c;
</syntaxhighlight>
</source>
}}
}}



Version du 27 juin 2020 à 16:24

Début de la boite de navigation du chapitre
Pointeur, Tableaux et références
Icône de la faculté
Chapitre no 9
Leçon : Langage C++
Chap. préc. :Méthodes
Chap. suiv. :Portée du code
fin de la boite de navigation du chapitre
En raison de limitations techniques, la typographie souhaitable du titre, « Langage C++ : Pointeur, Tableaux et références
Langage C++/Pointeur, Tableaux et références
 », n'a pu être restituée correctement ci-dessus.

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.

Début de l'exemple
Fin de l'exemple


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 :

Début de l'exemple
Fin de l'exemple


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 :

Début de l'exemple
Fin de l'exemple


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.

Début de l'exemple
Fin de l'exemple


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.

Panneau d’avertissement

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

Début de l'exemple
Fin de l'exemple

à la forme calculée

Panneau d’avertissement
Début de l'exemple
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(éléments du type int) = 24(éléments)* 4(Octets du type int) = 96 Octets contigus en pile.


Voici la syntaxe :


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 :

Début de l'exemple
Fin de l'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 no É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 :

Début de l'exemple
Fin de l'exemple


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.

Début de l'exemple
Fin de l'exemple


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.

Début de l'exemple
Fin de l'exemple


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

Début de l'exemple
Fin de l'exemple

Remarquez bien les parenthèses autour de "*LaMethode". Si on ne les avait pas mis comme dans cet exemple :

Début de l'exemple
Fin de l'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.
Début de l'exemple
Fin de l'exemple


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 :

Début de l'exemple
Fin de l'exemple


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.

Début de l'exemple
Fin de l'exemple


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).
Panneau d’avertissement 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

Début de l'exemple
Fin de l'exemple


Autre exemple pour une variable :

Début de l'exemple
Fin de l'exemple