INF155 – Introduction à la programmation
Sous-programmes
Amal Ben Abdellah
Ing., PhD., Chargée de cours
Département d'informatique,
Université de Sherbrooke
Sous-programme
▪ Un sous-programme est un ensemble d’instructions effectuant un traitement
spécifique identifiables par un nom distinctif et auquel on fait appel au besoin.
▪ Un sous-programme permet:
▪ De subdiviser un problème en plusieurs sous problèmes plus simples à résoudre;
▪ De favoriser la réutilisation du code;
▪ De faciliter la maintenance.
Sous-programme
Sous-programme
▪ Tout sous-programme doit soit:
▪ Effectuer un calcul et fournir le résultat de ce calcul;
▪ Effectuer un traitement qui a un effet sur l’environnement (ex.: afficher
quelque chose, modifier une information en mémoire, envoyer une
commande à un robot, une machine distante, etc)
▪ Ou les deux (mais idéalement pas)
▪ Un sous-programme qui n’effectue aucune de ces tâches est
inutile!
Types de sous-programmes
Il ya deux types de sous-programmes :
▪ Une fonction: Un sous programme qui effectue un calcul et qui
fournit, à celui qui l’a appelé, le résultat de ce traitement.
➔ Semblable au concept de fonction mathématique.
▪ Une procédure: Un sous programme qui effectue un traitement
qui a un effet sur l’environnement du programme mais ne
fournit aucun résultat à celui qui l’a appelé.
▪ Par abus de langage, nous utiliserons le terme fonction pour
faire référence à un sous-programme (peu importe le type)
Intérêts des fonctions
Les fonctions sont des modules (groupe d'instructions) indépendants
désignés par un nom. Elles ont plusieurs intérêts :
1. Elles permettent de "factoriser" les programmes, càd de mettre en
commun les parties qui se rép étent
2. Elles permettent une structuration et une meilleure lisibilité des
programmes
3. Elles facilitent la maintenance du code (il suffit de modifier une
seule fois)
4. Elles peuvent éventuellement être réutilisées dans d'autres
programmes
Principe
Une fonction est définie par trois éléments :
1. L'entrée : on fait rentrer des informations dans la fonction (en
lui donnant des informations avec lesquelles travailler).
2. Les calculs : grâce aux informations qu'elle a reçues en entrée, la
fonction travaille.
3. La sortie : une fois qu'elle a fini ses calculs, la fonction renvoie un
résultat. C'est ce qu'on appelle la sortie, ou encore le retour.
Déclarer une fonction
Syntaxe :
< T y p e _ R e t o u r > < N o m _ F o n c t > ( < P a r a m e t r e s >)
{
< C o rps de la f o n c t i o n >
}
• type de retour : (correspond la sortie) c'est le type de la
fonction. Ce type d pend du r sultat que la fonction renvoie (int,
double, void,...)
• nomFonction : c'est le nom de votre fonction. Il doit respecter les
m mes r gles que pour les variables.
• parametres : (correspond l'entr e) entre parenth ses, on envoie
des param tres la fonction.
Type de retour Void
• Il se peut que l'on est besoin de coder une fonction qui ne retourne
aucun résultat.
• C'est un cas courant en C. Ce genre de fonction est appel
procédure.
• Pour écrire une procédure, il faut indiquer la fonction en question
qu'elle ne doit rien retourner.
• Pour ce faire, il existe un "type de retour" spécial : void. Ce type signi
fie "vide", et sert indiquer que la fonction n'a pas de résultat.
Exemple
v o i d a f f i c h e r M e n u ()
{
printf (" ===== Menu =====\ n\ n");
p r i n t f (" 1. R o y a l C h e e s e \n");
p r i n t f (" 2. Big B u r g e r \n");
p r i n t f (" 3. C o m plet P o u l e t \n");
p r i n t f (" 4. P a n i n i T h on \n");
}
Paramètres des fonctions
• Un paramètre sert fournir des informations la fonction lors de son
exécution
• Si la fonction nécessite plusieurs paramètres, il suffit de les s éparer
par une virgule.
Exemple :
i n t S o m m e ( i n t a , i n t b)
{
r e t u r n a + b;
}
// f o n c t i on s sans p a r a m è t r e s
v o i d b o n j o u r ()
{
p r i n t f (" B o n jour ");
}
• Les paramètres doivent avoir des noms différents
• Il est aussi possible de ne pas mettre d'arguments dans une fonction.
Dans ce cas on écrit () ou (void).
Corps d'une fonction
• Le corps d'une fonction C est définie l'aide d'un bloc d'instructions.
• Un bloc d'instructions est encadré d'accolades et composé de deux
parties :
< T y p e _ R e t o u r > < N o m _ F o n c t > ( < P a r a m e t r e s >)
{
<declarations locales >
<instructions >
}
• Ceci est vrai pour tous les blocs d'instructions (fonction, if, while ou
for, etc).
• Les variables déclarées dans une fonction ne sont accessibles que
dans cette fonction, et pas de l’extérieur.
• Souvent, ces variables déclarées dans une fonction sont créées quand
on commence l’exécution de la fonction, et elles sont supprimées de la
m moire une fois que la fonction renvoie son résultat.
Instruction return
• L'instruction return permet de préciser quel est le résultat que
la fonction doit retourner (renvoyer)
• On peut mentionner n'importe quelle expression après un return.
Exemple :
f l o a t p o l y n o m e ( f l o a t x , i n t b , i n t c)
{
float resultat ;
resultat = x * x + b * x + c
return (resultat ) ;
// est e q u i v a l e n t a
f l o a t p o l y n o m e ( f l o a t x , i n t b , i n t c)
{
return (x * x + b * x + c) ;
}
Instruction return
• L'instruction return peut apparaître plusieurs reprises dans une
fonction
Exemple :
i n t p r o d u i t A b s o l u ( d o u b l e u , d o u b l e v)
{
double s ;
s = u* v ;
if (s >0) r e t u r n (s) ;
e l s e r e t u r n ( - s)
}
• Le type de l'expression dans return doit être le même que celui
déclaré dans l’en-tête de la fonction. Sinon le compilateur mettra
automatiquement en place des instructions de conversion.
• L'instruction return définit non seulement la valeur du résultat, mais,
en m me temps, elle interrompt l’exécution de la fonction en
revenant dans la fonction qui l'a appelée.
Utilisation d'une fonction
Il suffit de taper le nom de la fonction suivi des paramètres entre parenthèses.
Exemple :
# i n c lude < s t d i o .h>
# i n c lude < s t d l i b .h>
int d o u b l e ( int n o m b r e ) // 6
{
r e t u r n 2 * n o m b r e ; // 7
}
int main () // 1
{
int n o m bre E n t re = 0, n o m bre T r iple = 0; // 2
p r i n t f (" E n t r e z un n o m b r e ... " ) ; // 3
s c a n f ( " % d " , & n o m bre E n t re ); // 4
n o m b r e D o u b l e = d o u b l e ( n o m b r e E n t r e ); // 5
p r i n t f (" Le d o u b l e de ce n o m b r e est %d\ n " , n o m bre D o uble ) ; / / 8
r e t u r n 0; // 9
}
On n'est pas obligé de stocker le résultat d'une fonction
Exemple :
int double (int nombre )
{
return 2 * nombre ;
}
i n t m a i n ()
{
i n t n o m b r e E n t r e = 0;
p r i n t f (" E n t r e z un n o m b r e ... ");
s c a n f ( " % d " , & n o m b r e E n t r e );
/ / L e r e s u l t a t d e l a f o n c t i o n e s t d i r e c t e m e n t e n v o y e au
p r i n t f et n ' est pas s t o c k e dans une variable
p r i n t f (" Le d o u b l e de ce n o m b r e est %d\ n " , d o u b l e (
n o m bre E n t re ));
r e t u r n 0;
}
La fonction main appelle la fonction printf, qui elle-m me appelle la
fonction double. C'est une imbrication de fonctions.
Paramètre formels Vs. Paramètre effectifs
int double (int nombre )
{
return 2 * nombre ;
}
i n t m a i n ()
{
...
p r i n t f (" Le t r i p l e est %d\ n " , d o u b l e ( n o m bre E n t re ));
...
}
Les noms des arguments gurant dans l'en-t te de la fonction se
nomment des « paramètres formels ». Le u r rô l e e st d e
p er me t tr e, a u s ei n d u co r p s d e l a f o n ctio n, d e d é cri r e c e
q u'elle d o it faire .
Les arguments fournis lors de l'utilisation (l'appel) de la fonction se
nomment des «p a r a m è t r e s e f f e c t i f s » . on peut utiliser
n'importe quelle expression comme argument effectif.
Passage de paramètres par valeur
Exemple :
# i n c l u d e < s t d i o .h>
void fonction (int nombre )
{
++ n o m b r e ;
p r i n t f (" V a r iable n o m b r e dans la f o n ction : %d\ n " , nombre
);
}
int main (void )
{
i n t n o m b r e = 5;
f o n c t i o n ( n o m b r e );
p r i n t f ( " V a r i a b l e n o m b r e d a n s l e m a i n : % d \ n " , n o m b r e );
r e t u r n 0;
}
Variable nombre dans la fonction : 6
Variable nombre dans le main : 5
Prototypes
• En e ffet, lorsque la fonction est placée avant, le compilateur
connait ses paramètres et sa valeur de retour.
• Lors de l'appel de la fonction, le compilateur vérifie que
les arguments qu'on lui donne sont bons.
• Si au contraire la fonction est aprè s, le compilateur ne connait pas la
fonction.
• Heureusement, il existe une sorte de mode d'emploi qui permet
d'indiquer toutes les caractéristiques d'une fonction au compilateur.
• Avec cette indication, on peut placer la fonction où on veut dans le
code. Et ce mode d'emploi a un nom : un prototype. Un prototype
se déclare quasiment comme une fonction :
Exemple :
type n o m _ d e _ l a _ f o n c t i o n ( a r g u m e n t s );
• Placez le prototype simplement tout en haut de votre chier et c'est
bon ! votre fonction est utilisable partout dans le code
Prototypes
Exemple :
# i n c lude < s t d i o .h>
i n t c a r r e ( i n t n o m b r e );
int main (void )
{
int nombre , n o mbre_au_carre ;
puts (" E n t r e z un n o m b r e :");
s c a n f ( " % d " , & n o m b r e );
n o m b r e _ a u _ c a r r e = c a r r e ( n o m b r e );
p r i n t f (" V o i c i le c a r r e de %d : %d\ n " , n o m b re ,
n o m b r e _ a u _ c a r r e );
r e t u r n 0;
}
int carre (int nombre )
{
n o m b r e *= n o m b r e ;
return nombre ;
}
Visibilité
▪ On appelle visibilité d’une variable, la portion de code où la
variable est accessible (i.e. utilisable)
▪ Règles de visibilité en C:
▪ Une variable est visible dans le bloc où elle a été déclarée.
(Rappel: une variable doit obligatoirement être déclarée en début
d’un bloc!)
▪ Une variable globale est visible dans tout le programme
▪ Jusqu’à présent, nous n’avions qu’une seule fonction main, et
toutes les variables y étaient déclarées : le problème de
visibilité de se posait pas.
Visibilité - Exemple
int main(void)
{ ** Erreurs **
//Déclaration de variables
int i=0;
La variable “j” n’est
i= 100; pas visible dans la
fonction_test(); fonction main
printf(“La veleur de j est de: %d”, j);
return EXIT_SUCCESS;
}
void fonction_test(void) La variable “i” n’est
{
//Déclaration de variables pas visible dans la
int j; fonction fonction_test
int i;
j = i mod 2;
}
Variables globales
▪ Il est possible, en C, de déclarer des variables en dehors de
toute fonction.
▪ Ces variables ont une visibilité globale: elles sont accessibles
depuis toutes les fonctions du programme.
▪ De telles variables sont appelées des variables globales .
▪ Par opposition, les variables visibles uniquement au sein d’une
fonction sont appelées des variables locales.
Variables globales
*** VARIABLES GLOBALES *****
int i=0;
int j;
int main(void)
{
i= 100;
fonction_test();
printf(“La veleur de j est de: %d”, j);
return EXIT_SUCCESS;
}
void fonction_test(void)
{
j = i mod 2;
}
Remarques
• Le type par défaut est int ; autrement dit : si le type d'une fonction
n'est pas déclaré explicitement, elle est automatiquement du type
int.
• Il est interdit de définir des fonctions à l’intérieur d'une autre
fonction (comme en Pascal).
• En principe, l'ordre des définitions dans le texte du programme ne
joue pas de rôle, mais chaque fonction doit être déclarée (prototype) ou
définie avant d’être appelée.
• Dans les paramètres du prototype, seuls les types sont vraiment
nécessaires, les identificateurs sont facultatifs.
Variables et Mémoire
La mémoire allouée à notre programme par le système d’exploitation
est divisée en 3 parties: le Data Segment, la Pile et le Tas.
double k;
Pile (stack)
int main(void)
{
//Déclaration de variables
int i=0;
i= 100;
fonction_test();
printf(“La veleur de j est de: %d”, j);
return EXIT_SUCCESS;
}
int fonction_test(void) Tas (heap)
{
//Déclaration de variables
int j;
Data segment
j = i mod 3;
return j;
}
Variables et Mémoire
Lors du chargement du programme par le système d’exploitation, son
code machine est chargé dans le Data Segment, ainsi que les variables
globales.
double k;
Pile (stack)
int main(void)
{
//Déclaration de variables
int i=0;
i= 100;
fonction_test();
printf(“La veleur de j est de: %d”, j);
return EXIT_SUCCESS;
}
int fonction_test(void) Tas (heap)
{
//Déclaration de variables Data segment
Data segment
int j;
Variables globales k
j = i mod 3;
return j;
Code objet
}
Variables et Mémoire
À chaque fois qu’une fonction est appelée, un espace mémoire lui est
reserve dans la Pile pour y stocker paramètres et variables locales de
la fonction
double k;
Pile (stack)
int main(void)
{ main
//Déclaration de variables
int i=0; i
i= 100;
fonction_test();
printf(“La veleur de j est de: %d”, j);
return EXIT_SUCCESS;
}
int fonction_test(void) Tas (heap)
{
//Déclaration de variables Data segment
Data segment
int j;
Variables globales k
j = i mod 3;
return j;
Code objet
}
Variables et Mémoire
À chaque fois qu’une fonction est appelée, un espace mémoire lui est
reserve dans la Pile pour y stocker paramètres et variables locales de
la fonction
double k;
Pile (stack)
int main(void)
{ main
//Déclaration de variables
int i=0; i
i= 100; function_test
fonction_test();
printf(“La veleur de j est de: %d”, j); j param
return EXIT_SUCCESS;
}
int fonction_test(void) Tas (heap)
{
//Déclaration de variables Data
Data segment
segment
int j;
Variables globales k
j = i mod 3;
return j;
Code objet
}
Variables et Mémoire
Dès qu’une fonction se termine, le bloc de mémoire qui lui a été
réservé dans la Pile est détruit, et l’espace mémoire est à nouveau
disponible.
double k;
Pile (stack)
int main(void)
{ main
//Déclaration de variables
int i=0; i
i= 100; function_test
fonction_test();
printf(“La veleur de j est de: %d”, j); j param
return EXIT_SUCCESS;
}
int fonction_test(void) Tas (heap)
{
//Déclaration de variables Data
Data segment
segment
int j;
Variables globales k
j = i mod 3;
return j;
Code objet
}
Variables et Mémoire
Après que la fonction soit terminée, l’exécution reprend là où l’appel
de la fonction a été effectué. (l’adresse de retour est enregistrée dans
la Pile)
double k;
Pile (stack)
int main(void)
{ main
//Déclaration de variables
int i=0; i
i= 100;
fonction_test();
printf(“La veleur de j est de: %d”, j);
return EXIT_SUCCESS;
}
int fonction_test(void) Tas (heap)
{
//Déclaration de variables Data
Data segment
segment
int j;
Variables globales k
j = i mod 3;
return j;
Code objet
}
Variables et Mémoire
Lorsque la fonction main se termine, son espace réservé dans la Pile
est détruit (comme toute autre fonction), puis le SE reprend l’intégralité
de la mémoire
double k;
Pile (stack)
int main(void)
{ main
//Déclaration de variables
int i=0; i
i= 100;
fonction_test();
printf(“La veleur de j est de: %d”, j);
return EXIT_SUCCESS;
}
int fonction_test(void) Tas (heap)
{
//Déclaration de variables Data
Data segment
segment
int j;
Variables globales k
j = i mod 3;
return j;
Code objet
}