Affichage des articles dont le libellé est variable. Afficher tous les articles
Affichage des articles dont le libellé est variable. Afficher tous les articles

vendredi 10 août 2012

Les Pointeurs

Définition d'un pointeur
Un pointeur est une variable contenant l'adresse d'une autre variable d'un type donné. La notion de pointeur fait souvent peur car il s'agit d'une technique de programmation très puissante, permettant de définir des structures dynamiques, c'est-à-dire qui évoluent au cours du temps .
Comprendre la notion d'adresse
Comme nous l'avons vu, un pointeur est une variable qui permet de stocker une adresse, il est donc nécessaire de comprendre ce qu'est une adresse.  Lorsque l'on exécute un programme, celui-ci est stocké en mémoire, cela signifie que d'une part le code à exécuter est stocké, mais aussi que chaque variable que l'on a défini a une zone de mémoire qui lui est réservée, et la taille de cette zone correspond au type de variable que l'on a déclaré.
En réalité la mémoire est constituée de plein de petites cases de 8 bits (un octet). Une variable, selon son type (donc sa taille), va ainsi occuper une ou plusieurs de ces cases (une variable de type char occupera une seule case, tandis qu'une variable de type long occupera 4 cases consécutives). Chacune de ces « cases » (appelées blocs) est identifiée par un numéro. Ce numéro s'appelle adresse. On peut donc accéder à une variable de 2 façons :
grâce à son nom
grâce à l'adresse du premier bloc alloué à la variable
Il suffit donc de stocker l'adresse de la variable dans un pointeur (il est prévu pour cela) afin de pouvoir accéder à celle-ci (on dit que l'on « pointe vers la variable »).
Comment connaît-on l'adresse d'une variable ?
En réalité vous n'aurez jamais à écrire l'adresse d'une variable, d'autant plus qu'elle change à chaque lancement de programme étant donné que le système d'exploitation alloue les blocs de mémoire qui sont libres, et ceux-ci ne sont pas les mêmes à chaque exécution.
Ainsi, il existe une syntaxe permettant de connaître l'adresse d'une variable, connaissant son nom :  il suffit de faire précéder le nom de la variable par le caractère & (« ET commercial ») pour désigner l'adresse de cette variable :
&Nom_de_la_variableIntérêt des pointeurs
Déclaration d'un pointeur
Un pointeur est une variable qui doit être définie en précisant le type de variable pointée, de la façon suivante :
type * Nom_du_pointeur
Le type de variable pointée peut être aussi bien un type primaire (tel que int, char...) qu'un type complexe (tel que struct...).

Un pointeur doit préférentiellement être typé !
Il est toutefois possible de définir un pointeur sur 'void', c'est-à-dire sur quelque chose qui n'a pas de type prédéfini (void * toto). Ce genre de pointeur sert généralement de pointeur de transition, dans une fonction générique, avant un transtypage permettant d'accéder effectivement aux données pointées.
Grâce au symbole '*' le compilateur sait qu'il s'agit d'une variable de type pointeur et non d'une variable ordinaire, de plus, étant donné que vous précisez (obligatoirement) le type de variable, le compilateur saura combien de blocs suivent le bloc situé à l'adresse pointée.
Initialisation d'un pointeur
Après avoir déclaré un pointeur il faut l'initialiser. Cette démarche est très importante car lorsque vous déclarez un pointeur, celui-ci contient ce que la case où il est stocké contenait avant, c'est-à-dire n'importe quel nombre. Autrement dit, si vous n'initialisez pas votre pointeur, celui-ci risque de pointer vers une zone hasardeuse de votre mémoire, ce qui peut être un morceau de votre programme ou... de votre système d'exploitation !
Un pointeur non initialisé représente un danger !
Pour initialiser un pointeur, il faut utiliser l'opérateur d'affectation '=' suivi de l'opérateur d'adresse '&' auquel est accollé un nom de variable (celle-ci doit bien sûr avoir été définie avant...) :
Nom_du_pointeur = &nom_de_la_variable_pointee;
Par exemple :
int a = 2;
char b;
int *p1;
char *p2;
p1 = &a;
p2 = &b;
Accéder à une variable pointée
Après (et seulement après) avoir déclaré et initialisé un pointeur, il est possible d'accéder au contenu de l'adresse mémoire pointée par le pointeur grâce à l'opérateur '*'. La syntaxe est la suivante :
Par exemple :
int a = 2;
*p1 = 10;
*p2 = 'a';
Après ces deux instructions, le contenu des variables a et b sera respectivement 10 et 97 (61 en hexadécimal, le code ASCII associé au caractère 'a').
Si vous désirez utiliser cette notation dans une expression plus complexe, il sera nécessaire d'employer des parenthèses :   Par exemple :    a = (*p)++;

Les Structures

Différence entre une structure et un tableau
Un tableau permet de regrouper des éléments de même type, c'est-à-dire codés sur le même nombre de bits et de la même façon. Toutefois, il est généralement utile de pouvoir rassembler des éléments de type différent tels que des entiers et des chaînes de caractères.
Les structures permettent de remédier à cette lacune des tableaux, en regroupant des objets (des variables) au sein d'une entité repérée par un seul nom de variable.
Les objets contenus dans la structure sont appelés champs de la structure.
Déclaration d'une structure
Lors de la déclaration de la structure, on indique les champs de la structure, c'est-à-dire le type et le nom des variables qui la composent :
struct Nom_Structure {
type_champ1 Nom_Champ1;
type_champ2 Nom_Champ2;
type_champ3 Nom_Champ3;
type_champ4 Nom_Champ4;
type_champ5 Nom_Champ5;
...
};La dernière accolade doit être suivie d'un point-virgule !

Le nom des champs répond aux critères des noms de variable
Deux champs ne peuvent avoir le même nom
Les données peuvent être de n'importe quel type hormis le type de la structure dans laquelle elles se trouvent
Ainsi, la structure suivante est correcte :
struct MaStructure {
int Age;
char Sexe;
char Nom[12];
float MoyenneScolaire;
struct AutreStructure StructBis;
/* en considérant que la structure AutreStructure est définie */
};
Par contre la structure suivante est incorrecte :
struct MaStructure {
int Age;
char Age;
struct MaStructure StructBis;
};
Il y a deux raisons à cela :
Le nom de variable Age n'est pas unique
Le type de donnée struct MaStructure n'est pas autorisé
La déclaration d'une structure ne fait que donner l'allure de la structure, c'est-à-dire en quelque sorte une définition d'un type de variable complexe. La déclaration ne réserve donc pas d'espace mémoire pour une variable structurée (variable de type structure), il faut donc définir une (ou plusieurs) variable(s) structurée(s) après avoir déclaré la structure...
Définition d'une variable structurée
La définition d'une variable structurée est une opération qui consiste à créer une variable ayant comme type celui d'une structure que l'on a précédemment déclarée, c'est-à-dire la nommer et lui réserver un emplacement en mémoire.
La définition d'une variable structurée se fait comme suit :
struct Nom_Structure Nom_Variable_Structuree;
Nom_Structure représente le nom d'une structure que l'on aura préalablement déclarée.
Nom_Variable_Structuree est le nom que l'on donne à la variable structurée.
Il va de soi que, comme dans le cas des variables on peut définir plusieurs variables structurées en les séparant avec des virgules :
struct Nom_Structure Nom1, Nom2, Nom3, ...;
Soit la structure Personne :
struct Personne{
int Age;
char Sexe;
};On peut définir plusieurs variables structurées :

struct Personne Pierre, Paul, Jacques;
Ou
struct Personne{
int Age;
char Sexe;
              } Pierre, Paul, Jacques;
Accès aux champs d'une variable structurée
Chaque variable de type structure possède des champs repérés avec des noms uniques. Toutefois le nom des champs ne suffit pas pour y accéder étant donné qu'ils n'ont de contexte qu'au sein de la variable structurée...
Pour accéder aux champs d'une structure on utilise l'opérateur de champ (un simple point) placé entre le nom de la variable structurée que l'on a défini et le nom du champ :
Nom_Variable.Nom_Champ;
Ainsi, pour affecter des valeurs à la variable Pierre (variable de type struct Personne définie précédemment), on pourra écrire : Pierre.Age = 18; Pierre.Sexe = 'M';
Tableaux de structures
Etant donné qu'une structure est composée d'éléments de taille fixe, il est possible de créer un tableau ne contenant que des éléments du type d'une structure donnée. Il suffit de créer un tableau dont le type est celui de la structure et de le repérer par un nom de variable :
struct Nom_Structure Nom_Tableau[Nb_Elements] ;
Chaque élément du tableau représente alors une structure du type que l'on a défini...
Le tableau suivant (nommé Repertoire) pourra par exemple contenir 8 variables structurées de type struct Personne :   struct Personne Repertoire[8];
De la même façon, il est possible de manipuler des structures dans les fonctions.