Sous-sections

8.1 Passage arguments-paramètres

Dans les langages de programmation il existe deux techniques de passage d'arguments :

Des langages comme Fortran ou PL/1 ont choisi la 1$^{ere}$ solution, tandis qu'un langage comme Pascal offre les deux possibilités au programmeur.

Le langage C a choisi la 2$^{e}$ solution.

Si un argument doit être passé par adresse, c'est le programmeur qui en prend l'initiative et ceci grâce à l'opérateur d'adressage (&).

Exemple

 
#include <stdio.h>
void main()
{
   int a, b, c;
   void somme(int a, int b, int *c);
   a = 3;
   b = 8;
   somme(a, b, c);
   printf("Somme de a et b : %d\n", c);
   return;
}
void somme(int a, int b, int *c)
{
   *c = a + b;
   return;
}

8.1.1 Fonction retournant un pointeur

Il convient d'être prudent lors de l'utilisation d'une fonction retournant un pointeur. Il faudra éviter l'erreur qui consiste à retourner l'adresse d'une variable temporaire.

Exemple

 
#include <stdio.h>
void main()
{
   char *p;
   char *ini_car(void);
   p = ini_car();
   printf("%c\n", *p);
}
char *ini_car(void)
{
   char c;
   c = '#';
   return(c);     <===  ERREUR
}

8.1.2 Passage d'un vecteur comme argument

Un vecteur est une constante symbolique dont la valeur est l'adresse de son 1$^{er}$ élément.

Lorsqu'un vecteur est passé en argument, c'est donc l'adresse de son 1$^{er}$ élément qui est transmise par valeur.

Exemple

 
#define NbElements(t) sizeof t / sizeof t[0]
#include <stdio.h>
main()
{
   int  tab[] = { 1, 9, 10, 14, 18};
   int  somme(int t[], int n);
   void impression(int *t, int n);
   printf("%d\n", somme(tab, NbElements(tab)));
   impression(tab, NbElements(tab));
}
int  somme(int t[], int n)
{
   int i, som=0;
   for (i=0; i < n; i++) som += t[i];
   return som;
}
void impression(int *t, int n)
{
   int i=0, *p;
   for (p=t; t-p < n; t++)
      printf("t[%d] = %d\n", i++, *t);
}

Exemple

 
#define NbElements(t) sizeof t / sizeof t[0]
#include <stdio.h>
main()
{
   int tab[][5] = {
                     { 4, 7, 1, 9, 6},
                     { 5, 9, 3, 4, 2},
                     { 2, 9, 5, 9, 13}
                  };
   int somme(int (*t)[5], int n);
   printf("Somme des elements de tab : %d\n",
           somme(tab, NbElements(tab)));
}
int somme(int (*t)[5], int n)
{
   int i, som = 0;
   int (*p)[5] = t;
   for(; t-p < n; t++)
     for (i=0; i < 5; i++)
        som += (*t)[i];
   return som;
}

Exemple

 
#define DIM1 10
#define DIM2  4
#define DIM3  5
main()
{
   int tab[DIM1][DIM2][DIM3];
   void init(int (*t)[DIM3], int n);
   int i, n = DIM2;
   for(i=0; i i < DIM1; i++)
     init(tab[i], i);
}
void init(int (*t)[DIM3], int n)
{ int i, j;
   for(i=0; i < DIM2; i++)
     for(j=0; j < DIM3; j++) {
       t[i][j]      = 2*(i+n*DIM2);
       *(*(t+i)+j) += 1;
     } }

8.1.3 Passage d'une structure comme argument

La norme ANSI a introduit la possibilité de transmettre une structure en argument d'une fonction, elle-même pouvant retourner un tel objet.

Exemple

 
#include <stdio.h>
#define NbElts(v) ( sizeof v / sizeof v[0] )
typedef struct
{
   float v[6];
} Vecteur;
 
main()
{
  Vecteur v = { {1.34f, 8.78f, 10.f,
                 4.f, 22.12f, 3.145f} };
  Vecteur inv;
  Vecteur inverse(Vecteur v, int n);
  int     i, n = NbElts(v.v);
  inv = inverse(v, n);
  for (i=0; i < n; i++)
    printf("inv.v[%d] : %f\n", i, inv.v[i]);
}
Vecteur inverse(Vecteur v, int n)
{
  Vecteur w;
  int     i;
  for(i=0; i < n; i++)
    w.v[i] = v.v[i] ? 1./v.v[i] : 0.f;
  return w;
}

8.1.4 Passage d'une fonction comme argument

Le nom d'une fonction est une constante symbolique dont la valeur est un pointeur sur la 1$^{ere}$ instruction exécutable du code machine de la fonction. Passer une fonction en argument, c'est donc transmettre l'adresse, par valeur, du début du code machine constituant cette fonction.

Exemple

 
double integrale(double b_inf, double b_sup,
                 int pas, double (*f)(double));
double carre(double x);
void main()
{
   double b_inf, b_sup, aire;
   int    pas;
   b_inf = 1., b_sup = 6., pas = 2000;
   aire = integrale(b_inf, b_sup, pas, carre);
   printf("Aire : %f\n", aire);
}
double integrale(double b_inf, double b_sup,
                 int pas, double (*f)(double))
{
   double surface = 0., h;
   int    i;
   h = (b_sup - b_inf)/pas;
   for(i=0; i< pas; i++)
     surface += h*(*f)(b_inf+i*h);
   return surface;
}
double carre(double x) {return x*x;}

8.1.5 Passage d'arguments à la fonction main

Lorsqu'un exécutable est lancé sous un interprète de commandes ({shell}), un processus est créé et son exécution commence par la fonction main à laquelle des arguments sont transmis après avoir été générés par le shell.

Ces arguments sont constitués de :

Les premier et dernier sont transmis sous forme de vecteurs de pointeurs de caractères.

Par convention :

Les arguments précédents sont transmis à la fonction main dans cet ordre.

Exemple

La commande a.out toto titi tata génère la structure de données suivante :

Tableau des arguments

Exemple

 
#include <stdio.h>
main(int argc, char **argv, char **envp)
{
   void usage(char *s);
   if (argc != 3)
     usage(argv[0]);
   for(; *argv; argv++)
     printf("%s\n", *argv);
   for(; *envp; envp++)
     printf("%s\n", *envp);
}
void usage(char *s)
{
   fprintf(stderr, "usage : %s arg1 arg2\n", s);
   exit(1); }


Pr. Marc BUFFAT
buffat@ufrmeca.univ-lyon1.fr
2004-12-01