Vous êtes sur la page 1sur 9

Institut Supérieur des

Etudes Technologiques Cours algorithmique et


de Siliana programmation

Chapitre 6: Sous-programmes en algorithmique


et en langage C

Introduction
La conception d'un algorithme procède en général par des affinements successifs. On
décompose le problème à résoudre en sous-problèmes, puis ces derniers à leur tour, jusqu'à
obtenir des problèmes faciles à résoudre. Pour chacun des sous-problèmes, on écrit un module
appelé sous-programme.
Ainsi, la résolution du problème sera composée d'un algorithme principal et d'un certain
nombre de sous-problèmes. L'algorithme principal a pour but d'organiser l'enchaînement des
sous-programmes.
L'intérêt de l'analyse modulaire est:
- Répartir les difficultés entre les différents sous problèmes
- Faciliter la résolution d'un problème complexe
- Améliorer la qualité d'écriture du programme principal
-Minimiser l'écriture du code source dans la mesure où on utilise la technique de la
réutilisation.
Aujourd'hui, nous allons voir les procédures et fonctions. Dans les grands programmes, il y a
souvent des bouts de code qui peuvent se répéter à plusieurs endroits. Si ces morceaux de
code contiennent de nombreuses lignes, on ne peut pas les copier coller aux endroits
souhaités. Mais, cette pratique révèle aussi possible, limitée et ne constitue pas une bonne
solution pour un code durable et facilement tenable. Pour mieux comprendre le principe,
imaginons que l'on veut créer un algorithme qui demande à l'utilisateur de saisir ses
informations personnelles comme le nom, le prénom, l'adresse, etc.
Après chaque information saisie, on souhaite tracer une ligne faite par un nombre défini de
caractères soulignés. On dira par exemple qu'on veut afficher 20 caractères soulignés à chaque
fois. On peut donc imaginer notre algorithme comme ceux ci.
Algorithme informations
Variables
nom, prénom, adresse : chaine de caractères
i: entier
Début
Ecrire(« Nom : »)
Lire(nom)
Pour i de 1 à 20
Ecrire(« _ »)
FinPour
Ecrire(« Prenom : »)

Z.Narjess
1
Institut Supérieur des
Etudes Technologiques Cours algorithmique et
de Siliana programmation
Lire(prenom)
Pour i de 1 à 20
Ecrire(« _ »)
FinPour
Ecrire(«Adresse: »)
Lire(adresse)
Pour i de 1 à 20
Ecrire(« _ »)
FinPour
Fin
Bien évidemment, il aurait été plus facile d'écrire une ligne qui contient 20 caractères
soulignés au lieu d'utiliser une boucle « pour », mais l'utilité de la boucle sera dévoilée un peu
plus loin dans ce chapitre. De toute façon, vous avez certainement remarqué que le code de la
boucle « pour » a été répété à l'identique trois fois dans un algorithme avec un copier coller.
Ça sera un jeu d'enfant et on ne sentira pas trop la redondance lors de la saisie. Mais imaginez
un instant qu'on souhaite afficher cette ligne une dizaine de fois, voire plus.
Pour i de 1 à 20
Ecrire(« _ »)
FinPour
Dans ce cas, la redondance sera plus perceptible. En fait, le problème ne réside pas dans la
redondance en soit, bien que celle-ci rende le code un peu plus moche. Mais, le plus grand
problème, c'est que le jour où vous déciderez de modifier la forme de la ligne en agissant sur
le nombre de caractères, sur la valeur de ceci, alors là, il faudra passer en revue tous ces blocs
de code que vous avez répété un peu partout afin de les modifier un à un.
Figurez-vous que le code redondant dans notre exemple est trop petit. S'il contenait des
dizaines, voire des centaines de lignes, alors là, ça sera toute une autre histoire. La solution à
ce problème consiste à factoriser le code redondant, c'est à dire qu’on va déclarer une seule
fois dans notre algorithme ou programme et à chaque fois qu'on en aura besoin, on va tout
simplement invoquer ce code factorisé et connu sous le nom de sous-programme. En fait, il
s'agit d'une sorte de programme que l'on va intégrer dans un programme plus grand.
Les sous-programmes peuvent être soient des procédures, soient des fonctions. Le concept des
procédures et des fonctions est relativement similaires, à une différence près qu'on va voir
plus loin. Donc, pour notre exemple, nous allons créer un sous programme qui, dans ce cas,
sera une procédure. L’algorithme a la même structure qu'un algorithme ordinaire, c'est à dire
qu'il a un bloc pour déclarer les variables et un corps délimiter par début et fin comme ceci.
Procédure Nom_de_procédure()
Variables
Var1 : type1 Variables
Var2 : type2 locales

Début
Traitement voulu

Z.Narjess
2
Institut Supérieur des
Etudes Technologiques Cours algorithmique et
de Siliana programmation
Fin

Le mot clé procédure indique qu'il s'agit d'une procédure et non pas une fonction.
Le nom de la procédure doit respecter les mêmes règles que pour des noms de variables.
Concernant les parenthèses situées juste après, nous allons voir leur utilité dans ce qui suit. Le
bloc variables permet de déclarer toutes les variables qu'on en invoquera dans la procédure
courante. Ils peuvent être des variables scalaires ou des tableaux. Notez que l'ensemble des
variables déclarées dans une procédure sont dites variables locales, c'est à dire qu'ils sont pris
en compte localement au sein de la procédure courante. Donc, si on veut y accéder de
l'extérieur de celle ci, alors se seront comme inexistantes. Il existe aussi des variables qu'on
appelle des variables globales, elles sont reconnues partout dans l’algorithme, y compris à
l'intérieur des sous-programmes déjà déclarées. Le fait qu'une variable soit locale ou globale
est connu en programmation par le terme portée de la variable. Et cette portée est gérée
différemment d'un langage de programmation à un autre. Et pour faire simple, on va
considérer que des variables déclarées dans les sous-programmes sont locales. A titre
d'exemple, la procédure qui permet de dessiner la ligne sera déclarée de cette manière.
Procédure Ligne( )
Variables
i : entier
Début
Pour i de 1 à 20
Ecrire(« _ »)
FinPour
Fin
Maintenant, afin d'exécuter cette procédure et afficher ainsi la ligne, nous avons simplement
l’invoqué en déclarant son nom comme ceci.
Ligne()
On dit alors qu'on a appelé la procédure. Celle ci sera exécutée au moment de l'appel et
affichera à l'écran nos 20 caractères soulignés. En algorithmique, on préfère souvent déclarer
nos procédures entre la déclaration du nom de l'algorithme et le bloc consacré aux variables
de celui-ci. Alors, notre algorithme qui permet à l'utilisateur de saisir ses informations
personnelles sera fait de cette manière.
Algorithme informations
Procédure Ligne()
Variables
i : entier
Début
Pour i de 1 à 20
Ecrire(« _ »)
FinPour
Fin

Z.Narjess
3
Institut Supérieur des
Etudes Technologiques Cours algorithmique et
de Siliana programmation
Variables
nom, prénom, adresse : chaine de caractères
i: entier
Début
Ecrire(« Nom : »)
Lire(nom)
Ligne( )
Ecrire(« Prenom :
») Lire(prenom)
Ligne( )
Ecrire(«Adresse: »)
Lire(adresse)
Ligne( )
Fin
Vous avez donc remarqué comment nous avons factorisé le code qui permet de tracer notre
ligne dans une seule et unique procédure que l'on a appelé trois fois dans le corps de
l'algorithme. Désormais, si on souhaite modifier le comportement de notre procédure, il suffit
d'agir sur son code dans un seul endroit. Jusqu'ici, nous avons pu factoriser et réutiliser le
code de traçage de la ligne plusieurs fois. Cependant, à l'appel de la procédure, celle ci agira
toujours de la même façon, c'est à dire qu'il va afficher 20 caractères soulignés à chaque fois.
Or, il serait mieux qu'au moment de l’appel, on exprime à notre procédure la nature des
caractères à afficher et le nombre de fois qu'on souhaite le faire. En procédant ainsi, on pourra
changer son comportement sans toucher à son code. C'est là où nous aurons besoin des
parenthèses qui suivent le nom de la procédure. Ces parenthèses permettent de renfermer des
arguments. Ces derniers sont des variables qui seront utilisées au sein de la procédure, mais
leurs valeurs sont spécifiées au moment de l'appel.
En général, pour spécifier les arguments, on procède de cette manière.
Procédure Nom_de_procédure(Argument1 : type1, Argument2 : type2,..)

Les arguments sont spécifiés avec leurs types et ils sont séparés par une virgule au moment
de l’appel. Il faut renseigner la valeur de chacun des arguments tout en veillant sur le respect
du type défini comme ceci.
Nom_de_procédure(valeur1, valeur2,..)
Dans ce cas, on affecte systématiquement la valeur1 à l’argument1 et la valeur2 à
l'argument2, etc. On dit alors qu'on a passé la valeur1 à l'argument1 et la valeur2 à l'argument
2. Ecrivons maintenant notre algorithme de cette manière.
Algorithme informations
Procédure Ligne(nbr : Entier, car :chaine de caractère)
Variables
i : entier
Début
Pour i de 1 à nbr faire

Z.Narjess
4
Institut Supérieur des
Etudes Technologiques Cours algorithmique et
de Siliana programmation
Ecrire(car)
FinPour
Fin
Variables
nom, prénom, adresse : chaine de caractères
i: entier
Début
Ecrire(« Nom : »)
Lire(nom)
Ligne(20, ‘_’)
Ecrire(« Prenom :
») Lire(prenom)
Ligne(15, ’*’)
Ecrire(«Adresse: »)
Lire(adresse)
Ligne(10, ‘+’)
Fin

Lors du premier appel, l'argument nbr vaut 20 et l'argument car vaut ‘_’ (soulignez) dans la
procédure on a remplacé deux arguments par leur valeur et on exécute le traitement. On
affiche donc un caractère souligné. De la même manière, on affiche 15 astérisques au moment
du deuxième appel et 10 symboles ‘+’ lors du dernier appel. Vous avez donc vu qu'on a rendu
notre procédure plus maniable. On a d'autant d'arguments et on peut donc agir différemment
selon les valeurs qui sont passées à ceux ci.
Jusqu'ici, nous avons vu comment factoriser un code au sein d'une procédure et comment
appliquer celle ci en lui passant ou non des arguments. Mais imaginez qu'au moment de
l'appel de notre procédure, on ne veut pas qu'elle affiche directement de la ligne à l'écran,
mais on veut juste qu’elle nous renvoi cette ligne. Ensuite, c'est à nous de décider si on va
l'afficher, l'affecter à une variable de notre choix ou en faire autre chose si on veut avoir un tel
comportement il faut utiliser les fonctions.
Une fonction est un sous programme qui peut aussi accepter des arguments et faire un
traitement comme une procédure. Mais à la différence de celle ci, la fonction nous renvoie
un résultat. Dans le jargon de la programmation, on dit qu'elle retourne un résultat. En
général, on représente une fonction de cette manière.
Fonction Nom_de_fonction( arg1 : type1, arg2 : type2,…) : type de retour
Variables
Var1 : type1 Variables
Var2 : type2 locales

Début
Traitement voulu
Retourne valeur_de_retour
Fin

Z.Narjess
5
Institut Supérieur des
Etudes Technologiques Cours algorithmique et
de Siliana programmation

La structure de la fonction est semblable à celle d'une procédure. Cependant, on constate la


présence du type de retour juste après les arguments de la fonction et la ligne retourne
valeur_de_retour dans son corps. En fait, quand on appelle une fonction, on reçoit
automatiquement la valeur qu'elle retourne. Cette valeur à un type, c'est le type de retour. Pour
mieux comprendre le principe, imaginez qu'on veut créer une fonction qui permet de calculer
la factorielle d'un nombre entier positif. Mais, au lieu d'afficher le résultat à l'écran, on veut
récupérer ce résultat là afin de l'inclure dans des opérations de calcul. On peut donc proposer
la fonction suivante.
Fonction Factorielle (nbr : Entier): Entier
Variables
R, i : Entier
Début
R1
Pour i de 1 à nbr faire
RR*i
FinPour
Retourne R
Fin

Dans ce cas, quand notre fonction aura fini de traitement, elle retournera la variable R qui
contient la factorielle du nombre passé en argument.
Cette factorielle est un nombre entier. C'est pourquoi nous avons spécifie le type de retour de
la fonction en tant qu'entier. Notez que dans ce cas aussi, les variables R et i sont considérés
comme des variables locales. Désormais, si on appelle notre fonction par l'instruction
suivante :
Factorielle(3)
Alors, on aura calculé la factorielle de 3 qui vaut 6. Mais rien ne sera affiché à l'écran, car
nous n'avons rien fait de la valeur de retour qui est 6. Mais si on fait ça.
Ecrire(« La factorielle de 3 vaut », Factorielle(3))
Dans ce cas, on affiche à l'écran le message la factorielle de 3 vaut 6.
Sinon, on peut juste affecter le résultat de retour à une variable de notre choix ou d'inclure
dans une opération arithmétique tout simplement.
𝑛!
(𝑛 − 𝑘)! ∗ 𝑘!

A titre d'exemple, le programme qui permet de calculer la combinaison de k parmi n objet


ressemblera à celui ci.
Algorithme combinaison
Fonction Factorielle (nbr : Entier): Entier

Z.Narjess
6
Institut Supérieur des
Etudes Technologiques Cours algorithmique et
de Siliana programmation
Variables
R, i : Entier
Début
R1
Pour i de 1 à nbr faire
RR*i
FinPour
Retourne R (ou FactorielleR)
Fin
Variables
n, k: entier
c : réel
Début
Ecrire(« Entrez n et k svp : »)
Lire(n, k)
c Factorielle(n)/( Factorielle(n-k)* Factorielle(k))
Ecrire(« La combinaison de », k, « parmi », n, « vaut : », c)

Fin
Vous avez sans doute compris l'avantage des fonctions dans cet exemple au lieu de calculer la
factorielle de trois nombres différents trois fois dans un algorithme, nous n'avons déclaré
qu'une seule et unique fonction qui se charge de nous retourner le résultat.
On lui passe en argument des nombres dont on souhaite calculer la factorielle. Dans le
chapitre 4 où nous avons vu les structures itératives. Nous avons mentionné que pour répéter
un traitement plusieurs fois, on peut également se servir de fonction récursive. La récursivité
est le fait d'appeler une fonction depuis son corps, c'est à dire que notre fonction s'appelle par
elle même. Ce qui donne lieu à un traitement répétitif. Si cette récursivité ne prend pas fin, on
tombe dans une sorte de boucle infinie, exactement comme c'est le cas pour les structures
répétitives mal formulées.
A titre d'exemple, la fonction qui permet de calculer la factorielle peut être exprimée ainsi.
Fonction Factorielle (nbr : Entier): Entier
Variables
Début
Si nbr =0 alors
Retourne 1
Sinon
Retourne nbr* Factorielle(nbr-1)
Fin

Notez qu'une fonction prend fin si elle retourne quelque chose. Dans ce cas, tant que nbr ne
vaut pas 0. Alors la fonction retourne le nombre multiplié par la factorielle de ce même
nombre-1. A ce stade, on devrait quitter la fonction, mais celle ci est rappelé d'une manière
récursive et se ré-exécute une fois de plus jusqu'à ce que nbr vaut 0. Alors, elle renvoi 1 et la

Z.Narjess
7
Institut Supérieur des
Etudes Technologiques Cours algorithmique et
de Siliana programmation
récursivité prend fin car aucun appel de la fonction est programmé. À la fin, on a calculé
nbr*(nbr-1)*(nbr-2)*…*1
I. Définition et syntaxe
1. Définition
Un sous-programme est une unité fonctionnelle formée d'un bloc d'instructions et
éventuellement paramétré, que l'on déclare afin de pouvoir l'appeler par son nom en affectant
des valeurs à ses paramètres (s'ils existent). Les données fournies au sous-programme et les
résultats produits par ce dernier sont appelés des arguments ou des paramètres.
Un sous-programme peut être une procédure ou une fonction.
 Une procédure est un sous-programme ayant un nombre de paramètres, contenant un
certain nombre d'instructions et admettant zéro ou plusieurs résultats.
 Une fonction est un sous-programme ayant un nombre de paramètres, contenant un
certain nombre d'instructions et admettant au maximum un résultat unique affecté à
son nom.
2. Syntaxe
La syntaxe de définition d'une fonction en algorithmique est:
FONCTION Nom_Fonction (param_formel_1 : type1,.., param_formel_N : type_N) :
type résultat
Variables
Déclaration des variables
Début
Instructions
Nom_fonction ←Resultat (ou bien retourne Resultat)
Fin
La traduction de cette syntaxe en langage C est la suivante :
Type_resultat Nom_fonction ( type1 param_formel_1 ,.., type_N param_formel_N )
{ variables
// Déclaration des variables
Instructions ;
Return(Resultat) ;
}
La syntaxe de définition d'une procédure est:
PROCEDURE Nom_Procédure (param_formel_1 : type1,.., param_formel_N : type_N)
Variables
Déclaration des variables
Début
Instructions
Fin
La traduction de cette syntaxe en langage C est la suivante :
void Nom_procédure ( type1 param_formel_1 ,.., type_N param_formel_N )
{variables
// Déclaration des variables

Z.Narjess
8
Institut Supérieur des
Etudes Technologiques Cours algorithmique et
de Siliana programmation
Instructions ;
}
Les variables déclarées dans la procédure ou la fonction sont appelées variables locales. Une
variable locale est déclarée dans un sous-programme (procédure ou fonction) et ne peut être
utilisées que dans ce sous programme.
- Passage des paramètres
La transmission des paramètres formels aux paramètres effectifs, s’appelle le passage de
paramètre. Il faut différencier entre les paramètres donnée, paramètre résultat et le paramètre
donnée_résultat.
Les paramètres donnés sont des variables utilisées pour effectuer les traitements sans modifier
leurs valeurs.
Quant aux paramètres résultat, ce sont des variables dans lesquelles on enregistre les résultats
de traitement et qui seront changées après l’exécution de la procédure.
NB : Il faut placer le mot clé var devant les paramètres données_résultat et résultat sinon le
changement de leurs valeurs ne sera pas pris en compte dans le programme principal.
II. Appel de sous-programme
L'appel d'une fonction se fait comme suit:
Var ←Nom_Fonction(Parametres_Effectifs)
Ou
écrire(Nom_Fonction(Parametres_Effectifs))

L’appel des fonctions en langage C est écrit comme suit :


Var =Nom_Fonction(Parametres_Effectifs)
Ou
printf(Nom_Fonction(Parametres_Effectifs))

L'appel d'une procédure se fait comme suit:


Nom_Procedure(Parametres_Effectifs)

Généralement, c'est l'algorithme principal qui appelle ou invoque des sous-programmes. D'où,
l'algorithme principal est nommé l'appelant et le sous-programme est nommé l'appelé.
Cependant, un sous-programme peut appeler un autre sous-programme.
Lors de l'appel d'un sous-programme, deux formes de paramètres entrent en jeu : les
paramètres formels et les paramètres effectifs. Les paramètres formels apparaissent au niveau
de la définition du sous-programme, par opposition aux paramètres effectifs qui sont listés
dans un appel du sous-programme.

Z.Narjess
9

Vous aimerez peut-être aussi