1 of 24

Langage C

I. II. III. IV. V. VI. VII. VIII. IX.

La programmation modulaire et les fonctions

CHAPITRE VI

2 of 24

Langage C

I. II. III. IV. V. VI. VII. VIII. IX.

La programmation modulaire et les fonctions

1) Définition et utilisation d’une fonction en C

  • Les fonctions en C sont proches de la notion mathématique correspondante

  • Une fonction dispose d’arguments qui correspondent à des informations qui lui sont transmises

  • Une fonction fournit un unique résultat scalaire (simple) ; désigné par le nom même de la fonction, ce dernier peut apparaître dans une expression

3 of 24

Langage C

I. II. III. IV. V. VI. VII. VIII. IX.

La programmation modulaire et les fonctions

1) Définition et d’utilisation d’une fonction en C

#include <stdio.h>

/***** le programme principal (fonction main) *****/

main()

{

float fexple (float, int, int) ; /* déclaration de fonction fexple */

float x = 1.5 ;

float y, z ;

int n = 3, p = 5, q = 10 ;

/* appel de fexple avec les arguments x, n et p */

y = fexple (x, n, p) ;

printf ("valeur de y : %e\n", y) ;

/* appel de fexple avec les arguments x+0.5, q et n-1 */

z = fexple (x+0.5, q, n-1) ;

printf ("valeur de z : %e\n", z) ;

}

/*************** la fonction fexple ****************/

float fexple (float x, int b, int c)

{

float val ; /* déclaration d’une variable "locale" à fexple */

val = x * x + b * x + c ;

return val ;

}

4 of 24

Langage C

I. II. III. IV. V. VI. VII. VIII. IX.

La programmation modulaire et les fonctions

1) Définition et d’utilisation d’une fonction en C

#include <stdio.h>

/***** le programme principal (fonction main) *****/

main()

{

float fexple (float, int, int) ; /* déclaration de fonction fexple */

float x = 1.5 ;

float y, z ;

int n = 3, p = 5, q = 10 ;

/* appel de fexple avec les arguments x, n et p */

y = fexple (x, n, p) ;

printf ("valeur de y : %e\n", y) ;

/* appel de fexple avec les arguments x+0.5, q et n-1 */

z = fexple (x+0.5, q, n-1) ;

printf ("valeur de z : %e\n", z) ;

}

/*************** la fonction fexple ****************/

float fexple (float x, int b, int c)

{

float val ; /* déclaration d’une variable "locale" à fexple */

val = x * x + b * x + c ;

return val ;

}

5 of 24

Langage C

I. II. III. IV. V. VI. VII. VIII. IX.

La programmation modulaire et les fonctions

1) Définition et d’utilisation d’une fonction en C

#include <stdio.h>

/***** le programme principal (fonction main) *****/

main()

{

float fexple (float, int, int) ; /* déclaration de fonction fexple */

float x = 1.5 ;

float y, z ;

int n = 3, p = 5, q = 10 ;

/* appel de fexple avec les arguments x, n et p */

y = fexple (x, n, p) ;

printf ("valeur de y : %e\n", y) ;

/* appel de fexple avec les arguments x+0.5, q et n-1 */

z = fexple (x+0.5, q, n-1) ;

printf ("valeur de z : %e\n", z) ;

}

/*************** la fonction fexple ****************/

float fexple (float x, int b, int c)

{

float val ; /* déclaration d’une variable "locale" à fexple */

val = x * x + b * x + c ;

return val ;

}

6 of 24

Langage C

I. II. III. IV. V. VI. VII. VIII. IX.

La programmation modulaire et les fonctions

1) Définition et d’utilisation d’une fonction en C

#include <stdio.h>

/***** le programme principal (fonction main) *****/

main()

{

float fexple (float, int, int) ; /* déclaration de fonction fexple */

float x = 1.5 ;

float y, z ;

int n = 3, p = 5, q = 10 ;

/* appel de fexple avec les arguments x, n et p */

y = fexple (x, n, p) ;

printf ("valeur de y : %e\n", y) ;

/* appel de fexple avec les arguments x+0.5, q et n-1 */

z = fexple (x+0.5, q, n-1) ;

printf ("valeur de z : %e\n", z) ;

}

/*************** la fonction fexple ****************/

float fexple (float x, int b, int c)

{

float val ; /* déclaration d’une variable "locale" à fexple */

val = x * x + b * x + c ;

return val ;

}

7 of 24

Langage C

I. II. III. IV. V. VI. VII. VIII. IX.

La programmation modulaire et les fonctions

1) Définition et d’utilisation d’une fonction en C

#include <stdio.h>

/***** le programme principal (fonction main) *****/

main()

{

float fexple (float, int, int) ; /* déclaration de fonction fexple */

float x = 1.5 ;

float y, z ;

int n = 3, p = 5, q = 10 ;

/* appel de fexple avec les arguments x, n et p */

y = fexple (x, n, p) ;

printf ("valeur de y : %e\n", y) ;

/* appel de fexple avec les arguments x+0.5, q et n-1 */

z = fexple (x+0.5, q, n-1) ;

printf ("valeur de z : %e\n", z) ;

}

/*************** la fonction fexple ****************/

float fexple (float x, int b, int c)

{

float val ; /* déclaration d’une variable "locale" à fexple */

val = x * x + b * x + c ;

return val ;

}

8 of 24

Langage C

I. II. III. IV. V. VI. VII. VIII. IX.

La programmation modulaire et les fonctions

1) Définition et d’utilisation d’une fonction en C

float fexple (float x, int b, int c)

| | | | |

Type de la valeur de retour

Nom de la fonction

Premier Argument (type float)

Deuxième Argument (type int)

Troisième Argument (type int)

  • Les noms des arguments n’ont d’importance qu’au sein du corps de la fonction
  • Ils servent à décrire le travail que devra effectuer la fonction quand on l’appellera en lui fournissant trois valeurs
  • float val ;

La fonction a besoin d’une variable de type float nommée val (c’est une variable locale à la fonction fexple)

  • return val ;

Précise la valeur que fournira la fonction à la fin de son travail

  • float fexple (float, int, int) ;

Déclaration : prévient le compilateur que fexple est une fonction et précise les types

9 of 24

Langage C

I. II. III. IV. V. VI. VII. VIII. IX.

La programmation modulaire et les fonctions

2) Quelques règles

  • Arguments muets et arguments effectifs
    • Les noms des arguments dans l’en-tête de la fonction se nomment des « arguments muets ». Leur rôle est de permettre, au sein du corps de la fonction, de décrire ce qu’elle doit faire
    • Les arguments fournis lors de l’utilisation (l’appel) de la fonction se nomment des « arguments effectifs », on peut utiliser n’importe quelle expression comme argument effectif ; c’est la valeur de cette expression qui sera transmise à la fonction lors de son appel

z = fexple (x+0.5, q, n-1) ;

10 of 24

Langage C

I. II. III. IV. V. VI. VII. VIII. IX.

La programmation modulaire et les fonctions

2) Quelques règles

  • L’instruction « return »
    • L’instruction return peut mentionner n’importe quelle expression

    • L’instruction return peut apparaître à plusieurs reprises dans une fonction

    • L’instruction return définit la valeur du résultat, mais, en même temps, elle interrompt l’exécution de la fonction
    • Une fonction peut ne comporter aucune instruction return

float fexple (float x, int b, int c)

{

return (x * x + b * x + c) ;

}

double absom (double a, double b)

{

double s ;

s = a + b ;

if (s>0) return (s) ;

else return (-s) ;

}

11 of 24

Langage C

I. II. III. IV. V. VI. VII. VIII. IX.

La programmation modulaire et les fonctions

2) Quelques règles

  • L’instruction « return »
    • Si le type de l’expression figurant dans return est différent du type du résultat tel qu’il a été déclaré dans l’en-tête, le compilateur mettra automatiquement en place des instructions de conversion
    • Il est toujours possible de ne pas utiliser le résultat d’une fonction, même si elle en produit un
    • Il est interdit d’utiliser la valeur d’une fonction ne fournissant pas de résultat (certains compilateurs l’acceptent mais les valeurs seront aléatoires)

12 of 24

Langage C

I. II. III. IV. V. VI. VII. VIII. IX.

La programmation modulaire et les fonctions

2) Quelques règles

  • Cas des fonctions sans valeur de retour ou sans arguments
    • Quand une fonction ne renvoie pas de résultat, on le précise, à la fois dans l’en-tête et dans sa déclaration, à l’aide du mot-clé void

Naturellement, la définition d’une telle fonction ne doit, contenir aucune instruction return

    • Quand une fonction ne reçoit aucun argument, on place le mot-clé void

    • On peut réaliser une fonction ne possédant ni arguments ni valeur de retour

void sansval (int) ; // Déclaration

void sansval (int n)

float tirage (void) ; // Déclaration

float tirage (void)

void message (void) ; // Déclaration

void message (void)

13 of 24

Langage C

I. II. III. IV. V. VI. VII. VIII. IX.

La programmation modulaire et les fonctions

3) Les fonctions et leurs déclarations

  • Autre façon de déclarer
    • la définition de la fonction fexple peut être faite avant celle de la fonction main

    • La déclaration complète d’une fonction porte le nom de prototype; c’est de faire figurer des noms d’arguments, lesquels sont alors arbitraires

ht

main()

{

float fexple (float, int, int) ; /* déclaration de la fonc. fexple */

.....

y = fexple (x, n, p) ;

.....

}

float fexple (float x, int b, int c) ;

14 of 24

Langage C

I. II. III. IV. V. VI. VII. VIII. IX.

La programmation modulaire et les fonctions

3) Les fonctions et leurs déclarations

  • Emplacement de la déclaration d’une fonction

    • la déclaration de fexple est connue à la fois de main et de f1

float fexple (float, int, int) ;

main()

{

.....

}

void f1 (...)

{

.....

}

15 of 24

Langage C

I. II. III. IV. V. VI. VII. VIII. IX.

La programmation modulaire et les fonctions

4) Les arguments sont transmis par valeur

#include <stdio.h>

main()

{

void echange (int a, int b) ;

int n=10, p=20 ;

printf ("avant appel : %d %d\n", n, p) ;

echange (n, p) ;

printf ("après appel : %d %d", n, p) ;

}

void echange (int a, int b)

{

int c ;

printf ("début echange : %d %d\n", a, b) ;

c = a ;

a = b ;

b = c ;

printf ("fin echange : %d %d\n", a, b) ;

}

avant appel : 10 20

début echange : 10 20

fin echange : 20 10

après appel : 10 20

16 of 24

Langage C

I. II. III. IV. V. VI. VII. VIII. IX.

La programmation modulaire et les fonctions

    • La fonction echange reçoit deux valeurs correspondant à ses deux arguments muets a et b . Elle effectue un échange de ces deux valeurs
    • Lorsque l’on est revenu dans le programme principal, aucune trace de cet échange ne subsiste sur les arguments effectifs n et p
    • Il y a eu transmission de la valeur des expressions n et p. On peut dire que ces valeurs ont été recopiées localement dans la fonction echange dans des emplacements nommés a et b
    • Ce problème possède plusieurs solutions
      • Transmettre en argument la valeur de l’adresse d’une variable (technique des pointeurs)
      • Utiliser des variables globales

4) Les arguments sont transmis par valeur

17 of 24

Langage C

I. II. III. IV. V. VI. VII. VIII. IX.

La programmation modulaire et les fonctions

    • Plusieurs fonctions (dont, le programme principal main) peuvent partager des variables communes qu’on qualifie alors de globales (ou externe)
  • Exemple d’utilisation de variables globales

5) Les variables globales

#include <stdio.h>

int i ;

main()

{

void optimist (void) ;

for (i=1 ; i<=5 ; i++)

optimist() ;

}

void optimist(void)

{

printf ("il fait beau %d fois\n", i) ;

}

il fait beau 1 fois

il fait beau 2 fois

il fait beau 3 fois

il fait beau 4 fois

il fait beau 5 fois

18 of 24

Langage C

I. II. III. IV. V. VI. VII. VIII. IX.

La programmation modulaire et les fonctions

    • La variable i a été déclarée en dehors de la fonction main. Elle est alors connue de toutes les fonctions qui seront compilées par la suite au sein du même programme source
    • La fonction optimist se contente d’utiliser la valeur de i mais rien ne l’empêche de la modifier
    • C’est précisément ce genre de remarque qui doit vous inciter à n’utiliser les variables globales que dans des cas limités
  • La portée des variables globales
    • Les variables globales ne sont connues du compilateur que dans la partie du programme source suivant leur déclaration

5) Les variables globales

19 of 24

Langage C

I. II. III. IV. V. VI. VII. VIII. IX.

La programmation modulaire et les fonctions

    • Les variables n et x sont accessibles aux fonctions fct1 et fct2, mais pas au programme principal
    • Pour des raisons de lisibilité, on préférera regrouper les déclarations de toutes les variables globales au début du programme source
    • Ces variables sont initialisées à zéro, avant le début de l’exécution du programme, sauf si vous leur attribuez explicitement une valeur initiale au moment de leur déclaration

5) Les variables globales

main()

{

....

}

int n ;

float x ;

fct1 (...)

{

....

}

fct2 (...)

{

....

}

20 of 24

Langage C

I. II. III. IV. V. VI. VII. VIII. IX.

La programmation modulaire et les fonctions

    • Les variables locales sont définies au sein d’une fonction (qui pouvait être main). Ils sont locales à la fonction dans laquelle elles sont déclarées
  • La portée des variables locales
    • Les variables locales ne sont connues qu’à l’intérieur de la fonction où elles sont déclarées, leur portée est donc limitée à cette fonction
    • Les variables locales n’ont pas de lien avec des variables globales de même nom ou avec d’autres variables locales à d’autres fonctions

    • Il est alors impossible d’utiliser la variable globale n dans la fonction fct1

6) Les variables locales

int n ;

main()

{

int p ;

....

}

fct1 ()

{

int p ;

int n ;

}

21 of 24

Langage C

I. II. III. IV. V. VI. VII. VIII. IX.

La programmation modulaire et les fonctions

    • Les variables locales ont une durée de vie limitée à celle d’une exécution de la fonction dans laquelle elles figurent. Un nouvel espace mémoire leur est alloué à chaque entrée dans la fonction et libéré à chaque sortie
  • Les variables locales statiques
    • Il est possible d’attribuer un emplacement permanent à une variable locale et qu’ainsi sa valeur se conserve d’un appel au suivant. Il suffit pour cela de la déclarer à l’aide du mot-clé static (par défaut, initialisées à zéro)

6) Les variables locales

#include <stdio.h>

main()

{

void fct(void) ;

int n ;

for ( n=1 ; n<=5 ; n++)

fct() ;

}

void fct(void)

{

static int i ;

i++ ;

printf ("appel numéro : %d\n", i) ;

}

appel numéro : 1

appel numéro : 2

appel numéro : 3

appel numéro : 4

appel numéro : 5

22 of 24

Langage C

I. II. III. IV. V. VI. VII. VIII. IX.

La programmation modulaire et les fonctions

  • Le cas des fonctions récursives
    • Récursivité directe : une fonction comporte, dans sa définition, au moins un appel à elle-même
    • Récursivité croisée : l’appel d’une fonction entraîne celui d’une autre fonction qui, à son tour, appelle la fonction initiale (le cycle pouvant d’ailleurs faire intervenir plus de deux fonctions)

Fonction récursive de calcul de factorielle

6) Les variables locales

long fac (int n)

{

if (n>1) return (fac(n-1)*n) ;

else return(1) ;

}

23 of 24

Écrire une fonction qui se contente de comptabiliser le nombre de fois où elle a été appelée en affichant seulement un message de temps en temps, à savoir :

● au premier appel : *** appel 1 fois ***

● au dixième appel : *** appel 10 fois ***

● au centième appel : *** appel 100 fois ***

● et ainsi de suite pour le millième, le dix millième appel...

● On supposera que le nombre maximal d’appels ne peut dépasser la capacité d’un long

24 of 24

Fonctions Récursives

Ecrire un programme complet permettant de calculer la somme de

1×2 + 2×3 + 3×4 + . . . + n×(n+1).