C_facile : Introduction au langage C
Cours

Paramètres formels, paramètres réels et variables locales

Fondamental

L'unique mécanisme qui permet de transmettre de l'information à une fonction est la copie de cette information dans le réceptacle d'un paramètre formel.

Méthode

A la déclaration, on définit une liste de paramètres formels entre "(" et ")" séparés par des ",", si la liste est vide implicitement le paramètre est void.

Exemple

int truc()

est identique à

int truc(void)

Conseil

Nous vous conseillons dans ce dernier cas d'utiliser int truc(void), car cette écriture est plus explicite.

A l'invocation, liste d'arguments entre "(" et ")" correspond aux paramètres réels, cela peut être des constantes, des variables ou des expressions, à condition que la concordance des types soit respectée. Chaque valeur est ensuite recopiée dans le paramètre formel correspondant.

En effet, la correspondance entre paramètres formels et paramètres réels se fait en suivant l'ordre dans la liste.

Remarque

La déclaration d'une variable locale d'une fonction est valable jusqu'à la fin du bloc de la fonction.

Puisque la fonction travaille sur des copies d'informations, toute modification apportée à un paramètre formel dans le bloc de la fonction n'a strictement AUCUNE influence sur la valeur du paramètre réel qui lui correspond.

ExempleExemple

int plus_un(int x) // ici l'identificateur x est celui du paramètre formel

{

      x ++;

      return x ;

}

void main( )

{

      int x, y ;      // x est ici une variable locale de la fonction main,

       x = 1 ;

      y = 0;

      y = plus(x) ;     // x est ici la variable locale de la fonction main,

                                   // la valeur de x variable locale vaut 1, elle est utilisée comme

                                   // paramètre réel , sa valeur est donc recopiée

                                   // dans le réceptacle de x paramètre formel.

                                   // ATTENTION : le nom de l'identificateur est le même mais ce sont deux choses

                                   // différentes, il y a un "x" défini dans la fonction "main"

                                   // et c'est une variable locale

                                   // et un "x" défini dans la fonction plus_un et c'est un paramètre formel.

                                   // La valeur de l'un est recopiée dans l'autre, c'est tout !

      printf("\n%d",x);

                                    // ici nous affichons la valeur de « x » qui vaut toujours 1, variable locale

                                    // de la fonction main qui n'a pas été modifiée

                                    // dans la fonction plus_un puisque la fonction a travaille

                                    // sur une COPIE de la valeur !

}

ExempleAutre exemple plus compliquer

void plus(int x, int y)

{

      y = x ++ ;

}

void main( )

{

      int x, y ;

      x = 1 ;

      y = 0;

      plus(x,y);

      printf("\n%d %d",x,y);

}

Ce code affiche 1 et 0 et ne modifie en rien les variables locales x et y de la fonction principale main.

Les paramètres formels contiennent des copies des valeurs des paramètres effectifs. On peut modifier les valeurs des paramètres formels au sein de la fonction cela n'aura aucun impact sur les valeurs transmises.

Si on VEUT que les modifications effectuées sur les paramètres formels soient effectives c'est IMPOSSIBLE.

AttentionQue faire si on désire modifier quand même ce qui est transmis ?

Dans ce cas, puisque l'unique mécanisme de transmission d'information est la copie, il suffit de transmettre la copie de l'adresse de ce que l'on VEUT modifier.

Ensuite dans le bloc de la fonction il suffit d'utiliser l'opérateur d'accès au contenu '*' pour modifier ce qui est pointé. On ne touche pas à la valeur du pointeur qui est une copie d'information mais on l'utilise pour modifier ce qui est pointé. Nous en avons le droit car nous utilisons le mécanisme d'indirection.

Exemple

Par exemple, la séquence d'instructions pour permuter le contenu de deux variables est :

void main( )

{

      int x, y, inter;

       x = 3 ;

       y = 0 ;

      inter = x;             // sauvegarde de la valeur de x

      x = y ;                   // x prend la valeur de y mais l'ancienne valeur de x a été sauvegardée

      y = inter;             // a ce stade les contenus de x et y ont été échanges.

}

Exemple

Si l'on désire construire une fonction pour faire cela et que l'on écrit :

void permute(int x, int y)

{

      int inter;

      inter = x;

     x = y ;

      y = inter;

}

void main( )

{

      int x, y, a, b ;

      x = 12 ;

      y = 24 ;

      a = 2 ;

      b = 4 ;

      permute(x,y) ;

      permute(a,b) ;

}

Remarque

Toutes les variables locales de main conservent leur valeur initiale, car nous avons transmis des copies.

Par contre si on écrit :

void permute(int * x, int * y)

            // x est un paramètre formel de type pointeur vers entier

            // y est un paramètre formel de type pointeur vers entier

{

       int inter;

       inter = *x; // on accede a ce qui est pointe par x

                               // la variable locale inter contient l'entier trouve.

                               // a l'adresse qui est dans x

       *x = *y ;     // de meme pour y

       *y = inter; // y est un pointeur vers entier, nous modifions ce

                               // qui pointe en y rangeant la valeur de inter

}

void main( )

{

      int x, y, a, b ; // x,y,a,b sont ici des variables locales de la

                                        // fonction main, ce sont des entiers.

      x = 12 ;

      y = 24 ;

      a = 2 ;

      b = 4 ;

      permute(&x,&y) ;// recopie de l'adresse de x et de l'adresse de y

                                      // tous deux entiers, ces valeurs d'adresses sont les

                                      // deux valeurs des paramètres réels recopies dans

                                      // les deux réceptacles des paramètres formels x et y

                                     // de la fonction permute

                                     // qui eux sont des réceptacles qui contiennent désormais

                                     // des valeurs de pointeur vers entiers !

      permute(&a,&b) ;

}

Les contenus des variables locales « x » et « y » de « main » et « a » et « b » ont été échangés. Nous avons transmis des copies des adresses de « x » et « y » et la fonction travaille avec l'opérateur « * » qui accède à ce qui est pointé.

De même pour « a » et « b ».

ComplémentConclusion
  • On peut modifier ce qui est transmis dans une fonction cela n'a aucun impact, car c'est une copie d'information

  • Mais si on transmet une adresse, on peut l'utiliser pour accéder à l'emplacement qui correspond.

Les mêmes règles s'appliquent dans le cas de paramètres de type « pointeur vers ». Nombre identique de paramètres réels/formels, concordance de type. Par exemple, si la fonction attend un « pointeur vers flottant » il faudra lui transmettre « un pointeur vers flottant ».

Vous remarquerez que la fonction "echange" attend deux pointeurs vers entier et qu'on l'utilise en lui fournissant deux « pointeurs vers entier », c'est cohérent, il y a concordance de type.

Attention

c'est le programmeur qui décide, s'il transmet ou non des pointeurs quand il conçoit sa fonction.

Si l'on VEUT modifier quelque chose transmis à une fonction, alors il FAUT impérativement passer les paramètres par adresse (pointeur).

Les modifications du contenu en utilisant leurs adresses transmises en paramètre sont effectives, quand la fonction est terminée ces modifications sont pérennes. Attention à ce que vous faites :

Exemple

int plus(int * x) // transmission d'un pointeur

{

      * x = * x + 1 ; // utilisation du pointeur pour modifier

      return ( * x) ; // ce qui est pointé par (mécanisme d'indirection)

}

void main( )

{

      int x, y;

      x = 7;

      y = plus(&x) ;

}

A la fin du programme x vaut 8 et y aussi.

Transmission d'un tableau en paramètres (page suivante)Invocation d'une fonction (page Précédente)
AccueilImprimer creativecommons : by-nc-ndRéalisé avec SCENARI