Vous êtes sur la page 1sur 35

Chapitre 4 : Les sous programmes

1 : Notions de procédure et fonction


1.1 Exemple 1

Supposons qu’on ait à écrire le programme permettant de calculer la fonction


f(x) = 2x5 + 4x3 + 1 pour un réel x donné. S’il n’existe pas d’instruction permettant de coder le
calcul de la puissance d’un nombre, l’algorithme va s’écrire comme suit :

Programme fonction ;
Variables x, f1, f2, f : réels
i : entier ;
Début
ecrire(‘donnez x’);
lire (x);
f1 ← 1;
pour i ← 1 à 5 faire
f1 ← f1 * x;
f2 ← 1;
pour i ← 1 à 3 faire
f2 ← f2 * x;
f ← 2*f1 + 4*f2 + 1;
ecrire (‘f(‘,x,’) = ‘, f);
fin
1 : Notions de procédure et fonction

On remarque que l’on utilise deux fois la même chose pour calculer les puissances
de x (x5 et x3) et on pourrait paramétrer cela. Il suffira d’écrire un programme qui
calcule la puissance d’un nombre et l’utiliser dans le programme précédent.

Programme puissance ;
Variables p, a : réels
i, b : entier ;
début
lire (a, b);
p ← 1;
pour i ← 1 à b faire
p ← p * a;
ecrire (a, ‘ puissance ‘,b ‘ = ‘, p);
fin
1 : Notions de procédure et fonction
Pour calculer la valeur de f1, il suffit d’utiliser ce programme en donnant à a et b les
valeurs de x et 5 à partir du premier programme (fonction). Cela signifie que les
valeurs de a et b sont fournies non plus par saisie mais par le programme
«utilisateur » c’est-à-dire fonction. Il nous faut donc réécrire le programme
puissance sous la forme:

Programme puissance (a :réel ; b : entier)


Variables p : réel;
i : entier ;
début
p = 1;
pour i ← 1 à b faire
p ← p * a;
ecrire(a, ‘ puissance ‘,b ‘ = ‘, p);
fin

a et b sont les arguments du programme puissance.


1 : Notions de procédure et fonction
Mais la valeur de p doit être récupérée dans le programme de calcul de la fonction
dans la variable f1 et ce n’est pas en l’affichant dans le programme puissance que
cela va se faire. Il faut que le programme puissance retourne (ou renvoie) la valeur
de p au programme «utilisateur». Ainsi, à la place de l’instruction d’affichage ecrire
(a, ‘ puissance ‘,b ‘ = ‘, p) on écrira retourner (p) ou puissance := p.
Ainsi écrit, le programme puissance pourra être utilisé par le premier programme
comme suit :
Programme fonction ;
Variables x, f1, f2, f : réels
début
lire (x)
f1 ← puissance (x,5)
f2 ← puissance (x,3)
f ← 2*f1 + 4*f2 + 1
ecrire (‘f(‘,x,’) = ‘, f)
fin
1 :Notions de procédure et fonction
Quelles sont les particularités du programme puissance écrit et
utilisé de cette façon ?
(i) Il est écrit comme un programme (structurellement parlant).
(ii) Il peut recevoir ses données d’entrée à partir d’un autre
programme.
(iii) Il peut renvoyer ses données de sortie à un autre
programme.
(iv) Son exécution est commandée par un autre programme.

Le programme puissance est un sous programme, plus


précisément une fonction.
1.2 : Définition

Un sous programme est rédigé de façon telle que son exécution puisse être
commandée par un programme.
• L’exécution d’un sous programme est donc déclenchée par un programme.
• Celui-ci est appelé programme appelant (ou programme principal).
• Il fournit des données au sous-programme et récupère les résultats de ce dernier.

En général, on distingue deux types de sous programme : les procédures et les


fonctions. La différence est qu’une fonction renvoie une valeur (c’est l’exemple du
sous programme puissance) alors qu’une procédure ne renvoie pas de valeur.

Remarque :Dans certains langages, le terme Programme est remplacé par le terme
function s’il s’agit d’une fonction et procedure s’il s’agit d’une procédure.
Généralement, les sous-programmes seront écrits à l’intérieur des programmes qui
les utilisent, juste après la déclaration des variables.
Sous programme en C
• En C, il n’existe qu’une seule sorte de module, nommé fonction (il
en ira de même en C++ et en Java, langage dont la syntaxe est
proche de celle de C).

• Certes, la fonction y est utilisée comme dans d’autres langages,


c’est-à-dire recevoir des arguments et fournir un résultat scalaire
qu’on utilisera dans une expression.
• Mais, en C, la fonction pourra prendre des aspects différents,
pouvant complètement dénaturer l’idée qu’on se fait d’une fonction.
Par exemple :
• La valeur d’une fonction pourra très bien ne pas être utilisée ; c’est
ce qui se passe fréquemment lorsque vous utilisez printf ou scanf .
Sous programme en C
• Une fonction pourra ne fournir aucune valeur.

• Ainsi, donc, malgré son nom, en C, la fonction pourra jouer un rôle aussi
général que la procédure ou le sous-programme des autres langages.
• Une fonction pourra ne fournir aucune valeur.
• La définition d’une fonction est la donnée du texte de son algorithme,
qu’on appelle corps de la fonction. Elle est de la forme
type nom-fonction ( type-1 arg-1,..., type-n arg-n)
Exemple:
int produit (int a, int b)
{
return(a*b);
}
Exemple de fonction C
Le programme C complet de l’exemple est :
#include<stdio.h>
float x, f1, f2, f ;

/* definition du sous programme puissance */

float puissance(float a , float b){


float p ;
int i ;
p=1 ;
for(i=1 ;i<=b ; i++)
p=p*a ;
return p;
}
main()
{ scanf("%f", &x) ;
f1 = puissance (x,5) ;
f2 = puissance (x,3) ;
f = 2*f1 + 4*f2 + 1;
printf("f(x) = %.2f\n", f) ;
}
1.3 : Exemple 2

On veut écrire un programme C qui saisit une heure et affiche «Bonjour» si on est
avant 19h et «Bonsoir» sinon en utilisant deux procédures SalutationsJour et
SalutationsSoir qui affichent respectivement «Bonjour» et «Bonsoir ».

Program salutations
variable heure : entier ;

procedure SalutationsJour ;
debut
ecrire(‘Bonjour’);
Fin
1.3 : Exemple 2
procedure SalutationsSoir
debut
ecrire(‘Bonsoir’);
Fin

debut
lire(heure);
si heure < 19 alors
SalutationsJour;
sinon
SalutationsSoir;
fin
#include<stdion.h>

int heure;
%--------------------------------------------------------------

Void SalutationJour()
{
printf(‘’ Bonjour’’);
}

%--------------------------------------------------------------

Void Salutation soir()


{
printf(‘’ Bonsoir ’’);
}

%--------------------------------------------------------------
Main()
{
printf(« Donnez le nombre d’heure»);
Scanf( ’’ ‰d’’, &heure);
if (heure<19)
salutationSoir()
else
Salutation Jour()
}
1.4 : Remarque

Quand un programme A utilise un sous programme B, il se


passe successivement :
a) Appel du sous programme B par le programme appelant A ;
b) Suspension de l’exécution du programme A ;
c) Exécution du sous programme B ;
d) Retour au programme A.
2: Echange d’informations entre programme
et sous-programme

2.1. Les variables globales et les variables locales


On distinguera les variables du programme principal, appelées
variables globales, de celles des sous-programmes, appelées variables
locales.
Les variables globales peuvent être utilisées aussi bien par le
programme principal que par les sous programmes alors que les
variables locales ne peuvent être utilisées que dans les sous
programmes qui les ont définies (leur durée de vie est la durée
d’exécution du sous programme).
Par exemple, considérons le programme suivant :
2.1. Les variables globales et les variables locales

• On appelle visibilité ou portée des variables les règles qui régissent


l'utilisation des variables. Les mêmes règles régissent les types.
• Règle 1 : variables globales
Les variables déclarées avant la 1ere fonction peuvent être utilisées dans
toutes les fonctions. Ces variables sont dites globales.
#include "stdio.h"
int i;

void f1 () {
i = i+1;
}

void main(){
i=0;
f1();
printf("%d\n",i) -> 1
}
2.1. Les variables globales et les
variables locales
• Règle 2 : variables locales
Les variables déclarées dans une fonction ne peuvent être
utilisées que dans cette fonction. Ces variables sont dites
locales.

void f1 () {
int i;
i = i+1;
}
void main(){
i=0; -> ERREUR : i n'existe pas pour main
...
}
Visibilité des variables
• Règle 3 : arguments = variables locales
Les arguments d'une fonction sont des variables locales de la fonction.
void f1 (int i) {
i = i+1; /* i est une variable locale de la fonction */
}
void main(){
int j=1;
f1(j);
printf("%d\n",j)
}
• Règle 4 : Au sein d'une fonction, toutes les variables doivent avoir des noms
distincts
void f1 () {
int i;
char i; -> ERREUR : i existe déjà
i = i+1;
}
Visibilité des variables
• Règle 5 : Des variables déclarées dans des fonctions différentes
peuvent porter le même nom sans ambiguïté.
void f1 () {
int i; sous-entendu i_f1
...
}
void f2 () {
char i; sous-entendu i_f2
...
}
void main(){
int i; sous-entendu i_main
....
}
Ces 3 variables n'ont rien de commun
Visibilité des variables
• Règle 6 : Si une variable globale et une variable locale ont le même
nom, on accède à la variable locale dans la fonction où elle est déclarée

int i;
void f1 () {
int i;
i=2; /* i de f1 */
}
void main(){
i=0; /* i global */
f1();
printf (%"d\n",i); -> 0
}
Conseils
• Evitez autant que possible l'usage des variables globales =>
limitation des effets de bord indésirables
int i;
void f1 () {
...
i=i+1;
}
void main(){
i=0;
f1();
printf (%"d\n",i); -> 1
}
• Dans f1, on travaille sur i global :

– Est-ce bien ce que l'on désirait (oubli de déclaration d'une


nouvelle variable locale ?)
– Débogage difficile : il faut inspecter le code en détail pour voir
où sont modifiées les variables.
Conseils

• Si l'on ne peut éviter les variables globales, respecter un code pour


différencier les variables globales des variables locales.

• Par exemple :
si l'initiale de la variable est une majuscule -> globale : Vglob
minuscule -> locale : vloc
ou bien
le nom de chaque variable globale commence par G_ : G_variable

etc...
• Pas de confusion entre variables locales et globales.
• Mêmes règles pour les déclarations de type que pour les variabes
2.2 Les paramètres

2.2.1 Définition
Les paramètres permettent à un programme appelant de transmettre à
un sous programme des données lors de l’appel de ce dernier.

Un sous programme est rédigé de façon à pouvoir recevoir des données


du programme appelant : cela est possible grâce aux paramètres. On les
appellera formels dans leur définition dans le sous programme et
effectifs lors de l’appel du sous programme. A cet instant, les
paramètres formels sont remplacés par des paramètres effectifs. Ces
derniers sont fournis par le programme appelant.
Appel des fonctions
• L'appel d'une fonction se fait en donnant son nom, suivi de la liste des paramètres entre
parenthèses. L'ordre des paramètres correspond à celui des arguments.
• Exemple
float puiss (float x, int n) {
float y=1.0;
if (n>0)
for (i=1;i<=n;i++)
y = y*x;
else
for (i=1; i<=n; i++)
y = y/x;
return (y);
}

void main () {
float z,t;
z = puiss(10.7,2);
t = puiss (z, -6);
...
}
Appel des fonctions
• Un appel de fonction peut se faire comme opérande d'une expression, soit comme
paramètre d'un autre appel de fonction.
• Exemple
int maximum (int x, int y) {
return((x>y)?x,y));
}
void main () {
int v1,v2,v3,m1;
scanf("%d %d %d , &v1,&v2,&v3);
m1 = maximum(v1,v2);
m1 = maximum(m1,v3);
printf("valeur maximale %d\n", m1);
}
ou bien
m1 =maximum(v1,v2);
printf("valeur maximale %d\n", maximum(m1,v3));
ou bien
printf("valeur maximale %d\n", maximum(maximum(v1,v2),v3));
Le passage des paramètres

Rappelons que les variables globales existent pendant tout le


temps que dure l’exécution du programme principal alors que
les variables locales n’existent que durant l’exécution du sous
programme qui les a déclarées. Ce qui fait que les valeurs
affectées à ces variables sont perdues après l’exécution du sous
programme.
Les paramètres des sous programmes se comportent comme des
variables locales.
Passage des paramètres
• Rappel : les paramètres sont associés aux arguments suivant l'ordre de
déclaration.
• En c, cette association se fait par COPIE de la valeur du paramètre dans
l'argument. Chaque argument est en fait une variable locale de la fonction.
La fonction travaille sur l'argument.
• Conséquence : Une fonction ne modifie pas les paramètres d'appels
void f (int a){
a=a+1;
}
void main(){
int b;
b=0;
f(b);
printf("%d\n",b); ->0
}
Détail
void f (int a){
a=a+1; /*3*/
}
void main(){
int b;
b=0; /*1*/
f(b); /*2*/
printf("%d\n",b); /*4*/
}

b 0 b 0 b 0 b 0 Inchangé
Copie
a 0 a 1

/*1*/ /*2*/ /*3*/ /*4*/


Modification des paramètres
• Si l'on veut qu'une fonction modifie un paramètre, on ne passe pas la
variable mais l'adresse de la variable. Il y a copie de l'adresse de la variable.
Dans la fonction on va chercher la variable par son adresse.

• Rappels :
opérateur & : & variable -> adresse de la variable
opérateur * : * adresse -> valeur qui se trouve à cette adresse
int i;
int * adresse_i; /* déclaration d'une adresse d'entier */
i=0;
adresse_i=&i;
printf("%d\n",i); -> 0;
...
Modification des paramètres
void f2 (int * a){ // a est l'adresse, *a est l'entier
*a=*a+1; /*t3 on incrémente le mot d'adresse a*/
}
void main(){
int b;
b=0; /*t1*/
f(&b); /*t2 &b est l'adresse de b */
printf("%d\n",b); /*t4*/ -> 1
}

b 0 728 b 0 b 1 *a b 1

&b 728 &b 728


Copie
a 728 a 728
/*t1*/ /*t2*/ /*t3*/ /*t4*/

Exemple : scanf ("%d",&v);


Passage d'un tableau à une dimension en
paramètre
• Rappels:
– Lorsqu'on déclare un tableau, par ex int t[10], t est l'adresse du
1er élément du tableau
– Chaque élément du tableau peut être accédé par t[i] ou *(t+i)
– La première dimension d'un tableau n'est pas utilisée dans le
calcul de l'adresse d'une case
• Exemple
void printtab (int t1[50]) {
int i;
for (i=0;i<50;i++)
printf("%d",t1[i]);
}
void main () {
int t[50];
.....
printtab(t);
}
Passage d'un tableau à une dimension en
paramètre
• Puisque la dimension n'est pas utilisée, on peut
ne pas la donner
void printtab (int t1[50]){
int i;
for (i=0;i<50;i++)
printf("%d",t1[i]);
}
ou bien
void printtab (int t1[]) { Syntaxes équivalentes
int i;
for (i=0;i<50;i++)
printf("%d",t1[i]);
}
Passage d'un tableau à une dimension en
paramètre
Conséquence : on peut donc appeler cette fonction avec tout tableau d'entiers quelle
que soit sa dimension. C’est au programmeur à gérer les débordements de
tableau => donner le nombre de cases sur lequel travaille la fonction
void printtab (int t1[], int n){
int i;
for (i=0;i<n;i++)
printf("%d",t1[i]);
}

void main () {
int t[50],t2[100];
...
printtab(t,50); /*affiche toutes les cases de t de 0 à 49*/
printtab(t2,100); /*affiche toutes les cases de t2 de 0 à 99*/
printtab(t+20,30);/*affiche toutes les cases de t de 20 à 49*/
printtab(t+20,10);/*affiche toutes les cases de t de 20 à 30*/
}
Passage d'un tableau à une dimension en paramètre

Puisqu'en fait t1 est une adresse, on peut le déclarer comme tel

void printtab (int * t1,int n) {


int i;
for (i=0;i<n;i++)
printf("%d",t1[i]);
}
Passage d'un tableau à une dimension en paramètre

Conséquence :
Si un argument est de type tableau (càd une adresse), la fonction peut
modifier les cases du tableau

void misea0 (int t1[], int n){


int i;
for (i=0;i<n;i++)
t1[i]=0;
}

void main () {
int t[10]={1,2,3,4,5,6,7,8,9,10};
printtab(t,10); -> 1 2 3 4 5 6 7 8 9 10
misea0(t,10);
printtab(t,10); -> 0 0 0 0 0 0 0 0 0 0
}

Vous aimerez peut-être aussi