Home   Archives    Hardware   Programmation   Challenges   Forum   Le Mag    Faq   La Communauté   L'Equipe
 
L'équipe progG de Ti-Fr

Voici les nicks de vos serviteurs ;-)

chickensaver_john
Kevin Kofler
Thibaut
janjan2
TiMad
Iceman89
fréka
Zewoo
Squale92
Verstand
ZdRUbAl
UtOpIaH

et nEUrOne ...

Une idée ?
Une idée pour améliorez cette partie? ou tout simplement vous souhaitez participer à l'élaborations des tutos.
Mailez-nous ici

Les raccourcis
 

Chapitre XXV


Les pointeurs sont une des caractéristiques principales du langage C. Dans ce chapitre, nous essayerons de voir comment les utiliser dans nos programmes...

 

I:\ Un pointeur ? Mais qu'est-ce que c'est que ça ?

    "Pointeur" ? Mais à ce mot barbare correspond t'il ? C'est presque la question que je me suis posé quand j'en ai entendu parler dans la documentation de TIGCC pour la première fois...
    N'ayez crainte, même si les pointeurs font parti des chose assez complexes du langage C en général, on se rend vite compte qu'ils ne sont pas aussi impressionnant qu'on pourrait le penser au premier abord :-).

    Un pointeur n'est rien de plus qu'une variable qui contient une adresse. Cependant, on ne peut pas parler d'une "variable de type pointeur" de la même façon que nous parlons d'une "variable de type short" ou d'une "variable de type float"... En effet, il existe en C plusieurs de type de pointeurs, qui correspondent aux types de données que l'on pourra trouvé à l'adresse indiquée par ceux-ci...
    On pourra ainsi avoir dans un code un "pointeur sur une variable de type short", ou un "pointeur sur une variable de type float", ou un "pointeur sur une variable de type char", et ainsi de suite.... Cependant, pour des raisons de rapidité (et d'habitude, peut-être mauvaise), j'utiliserai généralement dans ce tutorial des termes tels "pointeur de type short", ou "pointeur de type char", etc..., même si ce n'est pas tout à fait l'appellation correcte.

        A: Déclaration d'un pointeur :

    Pour déclarer une variable comme étant un pointeur dans un programme, il convient d'utiliser ce type de syntaxe :
        type *nom_du_pointeur;
    type devra correspondre au type de variable sur lesquelles le pointeur nommé nom_du_pointeur pourra pointer.
    Par exemple, pour déclarer un pointeur sur une variable de type short, il conviendra d'utiliser cette instruction :
        short *pointeur_sur_short;
    Pour un pointeur sur une variable de type SYM_ENTRY, il faudra utiliser ceci :
        SYM_ENTRY *pointeur_sur_sym_entry;
    Et ainsi de suite...

        B: Utilisation de l'opérateur & :

    L'opérateur unaire & permet d'obtenir l'adresse de la variable placée à  sa suite. Ainsi, utiliser une écriture de ce type :
        &nom_de_la_var
    permettra d'obtenir l'adresse de la variable nommé nom_de_la_var.

    On a dit précédemment qu'un pointeur était une variable capable de contenir une adresse. Il nous sera donc possible d'effectuer les opérations suivantes (à titre d'exemple, j'ai ici choisi de travailler avec des shorts, mais il est parfaitement possible d'utiliser n'importe quel autre type de variables !) :
        short var_de_type_short;
        short *pointeur_sur_un_short;        
        var_de_type_short = 15;
        pointeur_sur_un_short = &var_de_type_short;
    Ainsi, la variable de type short nommée "var_de_type_short" aura pour valeur 15, et le pointeur de type short nommé "pointeur_sur_un_short" contiendra l'adresse de cette variable.
    Nous dirons que le pointeur pointeur_sur_un_short "pointe sur" la variable var_de_type_short.

        C: Utilisation de l'opérateur * :

    L'opérateur unaire * joue exactement le rôle inverse de celui que nous venons d'étudier. En effet, en utilisant une écriture de ce type :
        *nom_du_pointeur
    on désigne la variable pointée par le pointeur nommé nom_du_pointeur.

    Ainsi, si l'on continue de travailler avec l'exemple que nous avons employé juste au-dessus, on pourra effectuer ces autres instructions :
        short var_de_type_short;
        short autre_var_de_type_short;        
        short
*pointeur_sur_un_short;        
        var_de_type_short = 15;
        pointeur_sur_un_short = &var_de_type_short;
        autre_var_de_type_short = *pointeur_sur_un_short;

    Ainsi, on affecte à la variable autre_var_de_type_short la valeur pointée par le pointeur pointeur_sur_un_short, c'est-à-dire celle de la variable var_de_type_short. Donc, une fois cette portion de code exécutée, la variable autre_var_de_type_short aura pour valeur 15.

    Réciproquement, effectuer cette instruction :
        *pointeur_sur_un_short = 67;
    affectera à la variable pointée par le pointeur pointeur_sur_un_short, c'est-à-dire var_de_type_short, la valeur 67.
    Cela revient strictement au même que d'écrire
        var_de_type_short = 67;
    mais cela nous montre une utilisation des pointeurs qu'il nous est possible de généraliser pour d'autres cas.

Remarque 1 : Il est possible de donner deux significations à une écriture du style "*pointeur"...
    En effet, dans une expression, comme, par exemple, dans ceci :
        var = *pointeur;
    l'écriture "*pointeur" désigne la valeur de la variable pointée par le pointeur pointeur.
    Par contre, à gauche d'une affectation, comme, par exemple, dans cette instruction :
        *pointeur = 15;
    l'écriture "*pointeur" désigne la variable pointée par le pointeur pointeur, et non plus la valeur de celle-ci.

Remarque 2 : Je vous conseille de ne jamais introduire d'espace entre le symbole "*" et le nom du pointeur. En effet, bien que ceci soit autorisé par le compilateur C, cela ne facilite pas la compréhension du code source, en particulier dans les cas où il faut multiplier la valeur de la variable pointée par le pointeur par un autre autre nombre. En effet, le symbole qui permet la multiplication est aussi "*"...
    Il vaut souvent mieux, pour raisons de clarté, écrire "15 * *pointeur" plutôt que "15**pointeur", ou encore "15** pointeur" !!!

        D: Quelques "dangers" liés à une mauvaise utilisation de base des pointeurs :

                1: Déclaration de plusieurs pointeurs :

    Vous avez sans doute déjà déclaré plusieurs variable d'un même type en utilisant une syntaxe du type :
        short var1, var1, var3;
    Il est naturellement possible d'agit de même lorsqu'on déclare des pointeurs, mais il ne faut pas oublier d'inclure avant chaque nom de pointeur le symbole "*". Dans le cas contraire, seules les variables précédées de ce symbole seront des pointeurs de type donné : les autres ne seront que des variables de type donné.
    Il convient de faire ceci :
        short *pointeur1, *pointeur2, *pointeur3;
    Et non cela :
        short *pointeur1, pointeur2, pointeur3;

                2: Pointeurs et mémoire :

Attention : déclarer des pointeurs ne réserve pas d'espace mémoire pour d'éventuelles données pointées !!! De plus, lorsque vous déclarez un pointeur, l'adresse qu'il contient est parfaitement imprévisible !
    Donc, si vous effectuez ce type de manipulation :
        short *pointeur;
        *pointeur = 156;
   c'est-à-dire que vous dites pas sur quoi le pointeur doit pointer avant d'envoyer des données vers l'adresse qu'il contient, la valeur envoyée (ici, 156), sera placé n'importe où dans la mémoire de la TI... Et il y a de fortes chances pour que cela efface des données importantes, entraînant ainsi un plantage à plus ou moins long terme... 

 

II:\ Opérations avec les pointeurs :

        A: Opérations possibles :

    Nous allons voir, dans cette sous-partie, de nombreux exemples de manipulations simples de pointeurs, qui pourront souvent vous être utiles...
    Nous travaillerons avec les variables et pointeurs suivants :

        short var_1, var_2;
        short *pointeur_1, *pointeur_2;

    Voici les différentes manipulations que nous effectuerons (nous considérerons qu'elles se suivent, et donc, que ce que nous avons obtenu lors d'une manipulation est encore valable au moment où nous commençons la manipulation suivante).

        var_1 = 111;    // affecte la valeur 111 à la variable var_1.
        var_2 = 222;    // affecte la valeur 222 à la variable var_2.

        pointeur_1 = &var_1;    // Le pointeur pointeur_1 pointe à présent sur la variable var_1.
        pointeur_2 = &var_2;    // Le pointeur pointeur_2 pointe à présent sur la variable var_2.

        *pointeur_1 = *pointeur2 + 56;    // La variable pointée par pointeur_1 prend pour valeur la somme de la valeur de la variable pointée par pointeur_2 et de 56. Cela revient à effectuer l'opération "var_1 = var_2 + 56;"... La variable var_1 a donc à présent pour valeur 222+56 = 278

        pointeur_2 = pointeur_1;    // pointeur_2 pointe à présent vers la même variable que pointeur_1. Ces deux pointeurs pointent donc à présent tous deux sur la variable var_1.

        *pointeur_1 = *pointeur_2 + 12;    // Ici, on met dans la variable pointée par pointeur_1 la somme de la valeur de la variable pointée par pointeur_2 (la valeur de var_1, soit 278) et de 12. var_1 vaut donc à présent 278+12 = 290.

        B: Opérations impossibles :

    Pendant tout ce chapitre, nous avons vu que lorsque nous déclarions des pointeurs, il nous fallait préciser le type des données vers lesquelles ils allaient pointer. Donc, il n'est naturellement pas possible de "mixer" les variables et pointeurs de types différents, même si, pour simplifier, les poineturs contiennent tous la même chose, c'est-à-dire une adresse...
    Par exemple, pour que vous voyiez précisément de quoi je veux parler, il n'est pas possible de faire ceci :
        float *P_float;
        char *P_char;
        P_float = P_char;     // Ceci n'est pas possible !!!

 

III:\ Pointeurs et fonctions :

    Dans certains cas, quand vous voulez passer en argument d'une fonction des grosses variables (par exemple, une longue chaîne de caractères), et que vous voulez gagner un peu de vitesse, il vous sera bien utile d'utiliser nom pas la chaîne de caractère elle-même, mais plutôt un pointeur vers celle-ci...

    Cependant, il existe un cas où il est indispensable (à ma connaissance !) d'utiliser des pointeurs lors de l'appel d'une fonction : il s'agit du cas où l'on veut que la fonction soit capable de modifier ses paramètres...
    Bon, je le reconnais, ce n'est pas très clair dit comme ça :-). Nous allons donc utiliser un exemple : imaginons le cas où nous voulons écrire une fonction qui soit à même de permuter les valeurs de deux variables.

    Voici le code du programme qui correspond à cette fonction ainsi qu'à la fonction _main permettant de l'appeler :

#define OPTIMIZE_ROM_CALLS
#define SAVE_SCREEN
#include <tigcclib.h>


short _ti92plus, _ti89;

void _main(void)
{
  void fonction_echange_valeurs(short *, short *);
  short valeur_1, valeur_2;
  valeur_1 = 10;
  valeur_2 = 30;
  clrscr();
  FontSetSys(F_6x8);
  printf("Valeur de départ : %d %d\n", valeur_1, valeur_2);
  fonction_echange_valeurs(&valeur_1, &valeur_2);
  printf("Valeur de fin : %d %d\n", valeur_1, valeur_2);
  ngetchx();
}

void fonction_echange_valeurs(short *pointeur_val_1, short *pointeur_val_2)
{
  short intermediaire;
  intermediaire = *pointeur_val_1;
  *pointeur_val_1 = *pointeur_val_2;
  *pointeur_val_2 = intermediaire;
}

    Comme vous pouvez le remarquer, il convient d'utiliser l'opérateur "*" dans le prototype de la fonction (ainsi que dans sa déclaration), mais il faut utiliser l'opérateur "&" lorsqu'on l'appelle...
    En effet, lorsqu'on appelle la fonction, on lui passe en argument l'adresse de la variable qu'elle doit utiliser, mais, ensuite, elle travaille avec les données contenues dans cette variable.

    A présent, vous comprenez peut-être mieux le fonctionnement de certaines fonctions incluses dans les librairies de TIGCC, qui nécessitent qu'on leur passe des pointeurs en argument...

 

    Nous voilà arrivé à la fin de ce chapitre... J'espère que, maintenant, vous aurez moins de difficultés et de réticences à les employer dans vos programmes (voire même plus du tout !)... Une fois encore, je ne peux que vous encourager à parcourir ce chapitre plusieurs fois, à écrire de petits programmes pour appliquer vos connaissances nouvellement acquises....
    Si vous avez compris la majeure partie de ce chapitre, vous pouvez vous dire que c'est déjà une bonne chose : vous vous améliorerez avec la pratique.

Retour au menu général

Chapitre XXVI


 


Copyright © Ti-Fr v2.0 1999-2002