Vous êtes sur la page 1sur 43

Préliminaires

Université Assane SECK de Ziguinchor

Unité de Formation et de Recherche


des Sciences et Technologies

Département d’Informatique

Séquence 02 :
La modularité d’un
programme en
Langage C
Janvier 2016

Guy MBATCHOU
Préliminaires

Préliminaires

1.1 - Durée : 21 jours

1.2 - Objectifs pédagogiques


 définir la notion de module (O21) ;

 identifier les paramètres d'une fonction, leurs catégories et portées (O22) ;

 différencier les modes de passage d’un paramètre à un module (O23) ;

 écrire des fonctions récursives (O24) ;

 écrire des fonctions à nombre variable de paramètres (O25) ;

 modulariser un programme (O26) ;

 manipuler le préprocesseur et compiler un programme contenu dans plusieurs


fichiers (O27).

1.3 - Graphe de précédences des objectifs

1.4 - Proposition de scénario


O21  O22  O23  O24  O25  O26  O27

1.5 - Plan de la séquence


Préliminaires................................................................................................................................ i
1.1 - Durée : 21 jours ................................................................................................................ i
1.2 - Objectifs pédagogiques .................................................................................................... i

Guy MBATCHOU Page i


Préliminaires

1.3 - Graphe de précédences des objectifs ............................................................................... i


1.4 - Proposition de scénario .................................................................................................... i
1.5 - Plan de la séquence .......................................................................................................... i
Objectif 21 : Notion de module .................................................................................................. 1
1.1 - Durée : ............................................................................................................................. 1
1.2 - Seuil de validation : 60% ................................................................................................ 1
1.3 - Ressources ....................................................................................................................... 1
1.3.1 - Problématique ........................................................................................................ 1
1.3.2 - Définition ............................................................................................................... 2
1.3.3 - Structure d’un module ou sous-programme ........................................................... 4
1.3.4 - Notion de procédure et de fonction en langage Pascal .......................................... 5
1.3.4.1 - Structure d’une procédure ................................................................................ 5
1.3.4.2 - Structure d’une fonction .................................................................................. 6
1.3.5 - Bibliothèques de fonctions du langage C ............................................................... 9
1.4 - Activités .......................................................................................................................... 9
Objectif 22 : Paramètres d'une fonction, leurs catégories et leurs portées ............................... 10
2.1 - Durée : ........................................................................................................................... 10
2.2 - Seuil de validation : 70% .............................................................................................. 10
2.3 - Ressources ..................................................................................................................... 10
2.3.1 - Définition de paramètre ....................................................................................... 10
2.3.2 - Les catégories de paramètres ............................................................................... 12
2.3.2.1 - Les paramètres formels ou variables formelles.............................................. 12
2.3.2.2 - Les paramètres effectifs ou variables effectives ............................................ 12
2.3.3 - Définition des fonctions ....................................................................................... 12
2.3.4 - Appel des fonctions.............................................................................................. 13
2.3.5 - Déclaration d’une fonction................................................................................... 13
2.3.6 - Portée d’une variable ........................................................................................... 14
2.3.6.1 - Les variables locales ...................................................................................... 14
2.3.6.2 - Les variables globales .................................................................................... 15

Guy MBATCHOU Page ii


Préliminaires

2.3.6.3 - Conflit entre variable locale et variable globale ............................................ 16


2.4 - Activités ........................................................................................................................ 17
Objectif 23 : Mode de passage d’un paramètre à un module ................................................... 18
3.1 - Durée : ........................................................................................................................... 18
3.2 - Seuil de validation : 70% .............................................................................................. 18
3.3 - Ressources ..................................................................................................................... 18
3.3.1 - Passage par valeur ................................................................................................ 18
3.3.2 - Passage par adresse ou par référence ................................................................... 18
3.3.3 - Difficulté à modifier la valeur d’un paramètre .................................................... 18
3.3.3.1 - Utilisation des variables globales ................................................................... 19
3.3.3.2 - Transmission en argument de l’adresse d’une variable ................................. 20
3.4 - Activités ........................................................................................................................ 22
Objectif 24 : Fonctions récursives ............................................................................................ 23
4.1 - Durée : ........................................................................................................................... 23
4.2 - Seuil de validation : 60% .............................................................................................. 23
4.3 - Ressources ..................................................................................................................... 23
4.4 - Activités ........................................................................................................................ 23
Objectif 25 : Fonctions à nombre variable de paramètres ........................................................ 25
5.1 - Durée : ........................................................................................................................... 25
5.2 - Seuil de validation : 50% .............................................................................................. 25
5.3 - Ressources ..................................................................................................................... 25
5.4 - Activités ........................................................................................................................ 27
Objectif 26 : Modularisation d’un programme ........................................................................ 28
6.1 - Durée : ........................................................................................................................... 28
6.2 - Seuil de validation : 80% .............................................................................................. 28
6.3 - Ressources ..................................................................................................................... 28
6.3.1 - La fonction main .................................................................................................. 28
6.3.2 - Fonction statique .................................................................................................. 30
6.4 - Activités ........................................................................................................................ 30

Guy MBATCHOU Page iii


Préliminaires

Objectif 27 : Préprocesseur et compilation séparée ................................................................. 31


7.1 - Durée : ........................................................................................................................... 31
7.2 - Seuil de validation : 50% .............................................................................................. 31
7.3 - Ressources ..................................................................................................................... 31
7.3.1 - Fichier source ....................................................................................................... 31
7.3.2 - Fichier d’entête .................................................................................................... 31
7.3.3 - Les directives du préprocesseur ........................................................................... 32
7.3.3.1 - Les inclusions de fichiers ............................................................................... 32
7.3.3.2 - Les constantes du préprocesseur ou constantes symboliques ........................ 32
7.3.3.3 - Les macros ..................................................................................................... 33
7.3.3.4 - Les conditions ................................................................................................ 34
7.4 - Activités ........................................................................................................................ 36
Activités à objectifs multiples .................................................................................................. 37
Récapitulatif des activités par objectifs .................................................................................... 38

Guy MBATCHOU Page iv


Préliminaires

Objectif 21 : Notion de module

1.1 - Durée :

1.2 - Seuil de validation : 60%

1.3 - Ressources

1.3.1 - Problématique
Durant le cours d’Algorithmique et Programmation 1, les algorithmes et programmes
ont été toujours écrits en un seul bloc. Dans certains algorithmes et programmes, certaines
parties se répètent ou sont très proches à l’exception généralement des données manipulées.
Ces parties peuvent être regroupées en un bloc clairement identifié pour faciliter d’une part la
visibilité de l’algorithme et d’autre part pour faciliter sa maintenance (correction des bugs ou
amélioration de la performance). L’idée est de n’écrire ce bloc qu’une seule fois dans
l’algorithme ou programme et chaque fois qu’on en a besoin, on l’appelle seulement.
𝑵!
En exemple, pour calculer la combinaison de P dans N (∁ 𝑷𝑵 = ) il faut écrire un
𝑷!(𝑵−𝑷)!

ensemble d’instructions pour calculer le factoriel d’un nombre. Ces instructions devront être
reprises trois fois pour calculer le factoriel de N (N !), le factoriel de P (P !) et le factoriel de N-
P ((N-P) !). Lors des différentes reprises des instructions, seules les valeurs manipulées
changent à savoir N lorsqu’on calcule le factoriel de N, P lorsqu’on calcule le factoriel de P et
(N-P) lorsqu’on calcule le factoriel de (N-P).

Guy MBATCHOU Page 1


Préliminaires

#include<stdio.h>

int main(){
unsigned short int N, P, i;
unsigned long int FacP, FacN, FacNmoinsP, Comb;

printf("Calcul de la Combinaison de P dans N \n\n");


printf("Valeur de P : ");
scanf("%i",&P);
printf("Valeur de N : ");
scanf("%i",&N);
/*
ATTENTION : avant de commencer les opérations,
il faudra vérifier que P < N
*/

//Calcul du factoriel de N
FacN = 1;
for(i=1; i<=N; i++)
FacN *= i;

//Calcul du factoriel de P
FacP = 1;
for(i=1; i<=P; i++)
FacP *= i;

//Calcul du factoriel de N-P


FacNmoinsP = 1;
for(i=1; i<=N-P; i++)
FacNmoinsP *= i;

Comb = FacN /(FacP * FacNmoinsP);

printf("\nCombinaison de %i dans %i = %i\n", P, N, Comb);

return 0;
}
Or, il serait intéressant de regrouper les instructions de du calcul du factoriel et d’en
faire appel chaque fois lorsqu’on en a besoin. Ce regroupement permettra de réduire le nombre
d’instructions et de rendre le programme facilement lisible et modifiable (maintenance).
Un ensemble d’instructions est appelé bloc d’instructions et non un module. Pour être
appelé module, l’ensemble d’instructions doit avoir un nom et si nécessaire une liste finie de
variables (paramètres) dont on décidera de la valeur lors de l’appelle du module.

1.3.2 - Définition
Un module est une suite finie d’instructions ordonnées à laquelle on attribue un nom et
une liste de paramètres qui peut éventuellement être vide.
Un algorithme modulaire est un algorithme dans lequel certaines instructions sont
regroupées en module.

Guy MBATCHOU Page 2


Préliminaires

Un algorithme contenant au moins un module est modulaire. En revanche, il est


recommandé dans un algorithme modulaire d’écrire la plupart des instructions dans des
modules. De ce fait, votre algorithme sera un ensemble de briques (modules) dont le résultat
dépendra de leur agencement. L’algorithme vu comme un agencement de modules est plus
lisible et facile à comprendre qu’un algorithme où toutes les centaines voire milliers de lignes
d’instructions sont en un seul bloc. En cas de disfonctionnement d’un module dû à des erreurs
qui y sont contenues, l’algorithmicien ou programmeur ne se contentera de modifier que le
module sans se soucier de sa répétitivité (son appel) dans tout l’algorithme. Si l’algorithme
n’est pas modulaire, il faut identifier les instructions erronées, les corriger et ensuite, parcourir
les autres instructions à la recherche des instructions similaires afin de les corriger. Il peut
arriver que certaines instructions soient similaires mais sans toutefois appartenir à un module.
Dans ce genre de situation, en modifiant les instructions similaires, vous résolvez un problème
mais créant d’autres. D’où la nécessité d’écrire dès à présent des algorithmes modulaires.
Un algorithme modulaire offre les avantages suivants :

 La modularité : une décomposition ascendante ou descendante du problème en sous-


problème.

 La réutilisabilité : un module peut être réutilisé dans un autre algorithme car il permet
de résoudre un sous-problème précis. Donc un module peut être utilisé dans tous les
algorithmes où ce sous-problème est identifié.

 La récursivité : un module peut s’appeler lui-même de façon directe ou indirecte d’où


la récursivité.
Un module correspondant à une portion de l’algorithme n’est pas forcément autonome
mais est compréhensible, analysable et intégrable dans un autre module ou algorithme. En fait,
un module ne peut pas s’exécuter tout seul, il a besoin d’être appelé par un autre module (qui
peut être lui-même dans le cadre de la récursivité) ou par le programme principal.
Chaque module doit être bien commenté pour que son utilisateur comprenne son
contexte d’utilisation (conditions d’entrée, résultats attendus, objectifs, …)
Le langage C permet de faire de la programmation modulaire c’est-à-dire un programme
découpé en plusieurs parties appelées « modules ». Dans certains langages (comme le Pascal),
les modules sont exprimés à l’aide des procédures et des fonctions mais en langage C, les
procédures n’existent pas. Tout est fonction même le programme principal qui est représenté
par la fonction « main ».

Guy MBATCHOU Page 3


Préliminaires

1.3.3 - Structure d’un module ou sous-programme


Un module est un sous-programme car il a une structure similaire à celle d’un algorithme
ou programme comme présenté ci-dessous.
Module NomDuModule ;
Variable
variable1 : type1 ;

variableP : typeP ;
Début
instruction1 ;
instruction2 ;

instructionN ;
Fin ;

En algorithme, nous parlerons de module alors qu’en programmation, nous parlerons de


sous-programme ou module.
Un module contient :

 un entête comportant en une ligne :


 le mot clé module qui introduit le module et permet de le différencier d’un
algorithme ou programme.
 un nom respectant les règles de définition d’un identificateur.
 une liste éventuellement vide de paramètres avec leur type respectif

 une partie de déclaration des variables qui contient la liste des variables et leur type.
Ces variables sont dites locales au module. En général, il n’est pas conseiller de déclarer
de nouveau type dans le module sauf si dans l’algorithme, ce type ne sera utilisé que par
ce module. Cette partie peut être vide et au cas où elle ne l’est pas, elle est introduite par
le mot clé « type » pour les nouveaux types et le mot clé « variable » pour les variables
locales.

 un corps contenant un ensemble d’instructions commençant par Début et se terminant


par Fin. Un module se termine par un point-virgule « ; » contrairement à un algorithme
ou programme qui se termine par un point « . ».

Guy MBATCHOU Page 4


Préliminaires

1.3.4 - Notion de procédure et de fonction en langage Pascal


Tout module à la fin de son exécution produit un résultat (pas forcément une valeur)
mais il arrive souvent que l’on n’ait pas besoin de la valeur des résultats dans la suite
d’exécution de son algorithme ou programme. Une différence est faite entre les modules qui
renvoient un résultat et ceux qui ne le renvoient pas. Une procédure est un module qui ne revoit
pas de résultat alors qu’une fonction est un module qui renvoie toujours un résultat (une valeur).
Renvoyer un résultat ne signifie pas l’afficher ou l’imprimer mais il est question de
retourner dans une variable la valeur du résultat qui sera exploité à d’autre fins.
Exemples :

 Module permettant de calculer le salaire d’un employé est une fonction car après le
calcul, il faut retourner la valeur du salaire pour une utilisation ultérieure. Par contre si
on demande un module de calcul et d’affiche du salaire d’un employé, il s’agira d’une
procédure car le résultat (salaire) est affiché et non retourné pour une quelconque
utilisation.

 Module pour le tri des données est une procédure car après le tri, on ne revoit pas les
données triées et le commanditaire du tri verra que le travail est bel et bien fait.

 Module d’insertion ou de suppression d’une donnée dans un ensemble est une


procédure.

 Module de calcul de la moyenne ou somme des valeurs d’un ensemble est une fonction
car il faudra retourner la valeur de la moyenne ou de la somme.

1.3.4.1 - Structure d’une procédure


Bien qu’une procédure ne revoie pas de résultat, cela ne veut pas dire qu’elle ne produit
pas un résultat.

Guy MBATCHOU Page 5


Préliminaires

Procedure NomProcedure ; Procedure NomProcedure ;


Variable Var
variable1 : type1 ; variable1 : type1 ;
… …
variableP : typeP ; variableP : typeP ;
Début Begin
instruction1 ; instruction1 ;
instruction2 ; instruction2 ;
… …
instructionN ; instructionN ;
Fin ; End ;
Structure de la procédure Structure de la procédure
en langage algorithmique en langage Pascal
Exemple : Procédure permettant de lire le nom d’une personne et de lui dire bonjour
Procedure Salutation ; Procedure Salutation ;
Variable Var
nom : chaine de caractères ; nom : string ;
Début Begin
ecrire(‘Veuillez saisir votre nom : ‘) ; write(‘Veuillez saisir votre nom : ‘) ;
lire(nom) ; read(nom) ;
ecrire(‘Bonjour ‘, nom) ; write(‘Bonjour ‘, nom) ;
Fin ; End ;
Langage algorithmique Langage Pascal
Le résultat de cette procédure est de prodiguer un message de salutation mais elle ne
renvoie pas de valeur même pas le nom lu mais l’affiche.

1.3.4.2 - Structure d’une fonction


Contrairement à la mathématique où une fonction peut retourner plusieurs valeurs, en
algorithmique comme en programmation, une fonction ne peut retourner qu’une seule valeur.

Guy MBATCHOU Page 6


Préliminaires

Fonction NomFonction : TypeValeurResultat ; Function NomFunction : TypeValeurResultat ;


Variable Var
variable1 : type1 ; variable1 : type1 ;
… …
variableP : typeP ; variableP : typeP ;
resultat : TypeValeurResultat ; resultat : TypeValeurResultat ;
Début Begin
instruction1 ; instruction1 ;
instruction2 ; instruction2 ;
… …
instructionN ; instructionN ;

NomFonction  resultat ; NomFunction := resultat ;


Fin ; End ;
Structure de la fonction en langage Structure de la fonction en langage
algorithmique Pascal

Pour renvoyer un résultat, on doit affecter le résultat au nom de la fonction. Cela veut
dire que dans la liste des variables locales, il faut absolument une variable qui doit contenir le
résultat ou plusieurs variables dont la combinaison par des opérateurs arithmétiques ou logiques
donnera le résultat.
Function CalculAge : integer ; Function CalculAge : integer ;
Var Var
annee_en_cours : integer ; annee_en_cours : integer ;
annee_naissance : integer ; annee_naissance : integer ;
Begin age : integer ;
writeln(‘Programme de calcul d’âge’) ; Begin
write(‘Donner l’année courante :’) ; writeln(‘Programme de calcul d’âge’) ;
read(annee_en_cours) ; write(‘Donner l’année courante :’) ;
write(‘Donner votre année de naissance’) ; read(annee_en_cours) ;
read(annee_naissance) ; write(‘Donner votre année de naissance’) ;
read(annee_naissance) ;
CalculAge := annee_en_cours – annee_naisance ; age := annee_en_cours – annee_naisance ;
End ;
CalculAge := age ;
End ;
Fonction sans variable contenant le résultat. Fonction avec variable contenant le
Ici, le résultat est renvoyé sans besoin d’être résultat. Ici, le résultat est d’abord stocké
stocké dans une variable résultat dans la variable age avant d’être renvoyé

Intégrons à présent la procédure Salutation et la fonction CalculAge dans un programme


complet.

Guy MBATCHOU Page 7


Préliminaires

Program Salutation_et_Calcul_Age;

{Définition de la procédure Salutation}


Procedure Salutation;
Var
nom : string;
Begin
write('Veuillez saisir votre nom : ');
read(nom);
write('Bonjour ', nom);
End;

{Définition de la fonction CalculAge}


Function CalculAge() : integer;
Var
annee_en_cours : integer;
annee_naissance : integer;
age : integer;
Begin
writeln('Programme de calcul d"âge');
write('Donner l"année courante :');
read(annee_en_cours) ;
write('Donner votre année de naissance') ;
read(annee_naissance) ;
age := annee_en_cours - annee_naissance ;

CalculAge := age ;
End;

{Déclaration des variables du programme principal}


VAR
MonAge : integer;

{Début du programme principal}


BEGIN
Salutation; {appel de la procédure Salutation}
MonAge := CalculAge; {appel de la fonction CalculAge et affectation du
résultat dans la variable MonAge}
write('Votre age est de : ', MonAge);
END.
Pour matérialiser une procédure en C, on utilise une fonction de type de retour void
c’est-à-dire une fonction qui ne retourne pas de valeur.

Guy MBATCHOU Page 8


Préliminaires

1.3.5 - Bibliothèques de fonctions du langage C


Le langage C dispose d’un ensemble de fonctions mis à la disposition des utilisateurs
(programmeurs). Vous trouverez à l’adresse ci-dessous les fonctions du langage C organisées
dans leur bibliothèque.
https://fr.wikipedia.org/wiki/Biblioth%C3%A8que_standard_du_C
Une bibliothèque standard est introduite par #include<NomBibliotheque.h>

1.4 - Activités
Exercice 201 : Poids : 100% - Seuil de validation : 80% - Titre : QCM

Guy MBATCHOU Page 9


Préliminaires

Objectif 22 : Paramètres d'une


fonction, leurs catégories
et leurs portées

2.1 - Durée :

2.2 - Seuil de validation : 70%

2.3 - Ressources
Jusqu’à présent, tous les modules écrits ne sont pas paramétrés ! Cela veut dire que ces
modules ont tout le nécessaire pour réaliser leur tâche sans intervention de celui qui exécute le
module. Or si nous prenons la fonction CalculAge écrite précédemment, celui qui vous
demande de calculer son âge ne sera pas présent lorsque vous le ferez or dans la fonction
CalculAge, il y a une instruction qui lui demande de saisir son année de naissance. Que faire ?
Avant de commencer l’exécution de la fonction ou de la procédure, le programmeur doit
s’assurer qu’il dispose tout le nécessaire pour le faire. La question qu’il faut se poser pour
trouver les paramètres d’une fonction ou procédure est la suivante : De quoi ai-je besoin de
celui qui passe la commande de la fonction ou procédure pour la réaliser ?
Dans notre exemple, si vous voulez que je calcule votre âge, j’ai absolument besoin
que vous me donnez votre date de naissance (pour simplifier dans l’exemple, nous avons
demandé seulement l’année de naissance). Cette date de naissance est appelée paramètre pour
la fonction CalculAge car la valeur de retour de la fonction dépend de la valeur du paramètre.
Dans le cas d’une procédure le résultat produit dépendra de la valeur du paramètre.

2.3.1 - Définition de paramètre


Un paramètre est une variable mise à l’entrée d’un module dont sa valeur conditionne
le résultat que produira ce module.
Lorsqu’un module (procédure ou fonction) contient au moins un paramètre, il est dit
paramétré.
La syntaxe d’un module paramétré est la suivante :

Guy MBATCHOU Page 10


Préliminaires

Module NomModule(parametre1 : type1, .parametre2 : type2, .parametre3 : type3,…, parametreN : typeN)


En langage C, la syntaxe d’une fonction paramétrée est la suivante :
typeValeurDeRetour nomFonction(type1 parametre1, type2 parametre2, …, typeN parametreN)
Une fonction ou procédure peut comporter plusieurs paramètres pourvu qu’ils soient de
noms différents. Evidemment, il faudrait aussi que la sémantique des paramètres soit différente.
C’est-à-dire qu’il ne sert à rien de mettre par exemple 2 paramètres de noms différents qui
jouent le même rôle. Pour chaque paramètre, il faut préciser son type de données. Les
paramètres sont séparés par des virgules « , ».
En reprenant l’exemple précédent, nous nous rendons compte que la procédure
Salutation et la fonction CalculAge doivent être paramétrées. La procédure doit avoir un
paramètre de type chaîne de caractères (string en Pascal) pour représenter le nom tandis que la
fonction doit avoir un paramètre de type entier (int en langage C) pour représenter une année
de naissance.
Program Salutation_et_Calcul_Age;
USES DOS;{Appel de la bibliothèque DOS pour utiliser la fonction getdate}

{Définition de la procédure paramétrée Salutation}


Procedure Salutation(nom : string);{nom est le paramètre de la procédure Salutation}
Begin
writeln('Bonjour ', nom);
End;

{Définition de la fonction paramétrée CalculAge}


Function CalculAge(annee_naissance : integer) : integer;{annee_naissance est le paramètre de la
fonction CalculAge}
Var
annee, mois, jour_mois, jour_semaine : word;{variables devant contenir les éléments de la date}
age : integer;
Begin
writeln('Programme de calcul d"âge');
getdate(annee, mois, jour_mois, jour_semaine);{lecture de la date courante}
age := annee - annee_naissance ;

CalculAge := age ;
End;
{Déclaration des variables du programme principal}
VAR
MonNom : string;
MonAge : integer;
MonAnneeNaissance : integer;

{Début du programme principal}

Guy MBATCHOU Page 11


Préliminaires

BEGIN
write('Veuillez saisir votre nom : ');
read(MonNom);
Salutation(MonNom); {appel de la procédure Salutation avec le paramètre MonNom}
write('Donner votre année de naissance') ;
read(MonAnneeNaissance) ;
MonAge := CalculAge(MonAnneeNaissance); {appel de la fonction CalculAge avec le paramètre
MonAnneeNaissance et retour du résultat dans la variable MonAge}
write('Votre age est de : ', MonAge);
END.

2.3.2 - Les catégories de paramètres


Les paramètres sont désignés différemment selon leur emplacement dans le code source.
Le code source est l’ensemble des instructions d’un algorithme ou d’un programme.

2.3.2.1 - Les paramètres formels ou variables formelles


Un paramètre formel est une variable utilisée lors de l’écriture (définition) du module.
Il n’a pas d’existence réelle et ne sert qu’à définir l’expression du module comme c’est le cas
en mathématique où lorsque écrit f(x), x n’est qu’un paramètre pour exprimer f.

2.3.2.2 - Les paramètres effectifs ou variables effectives


Un paramètre effectif est une variable ou valeur utilisée lors de l’appel du module. Cette
variable a une existence réelle car elle est déclarée dans le programme et réside en mémoire.
En mathématique, on peut calculer f(4) ou calculer f(p) avec p=4. Dans le premier cas,
le paramètre est une valeur alors que dans le second cas, c’est une variable.

2.3.3 - Définition des fonctions


Une fonction en C se définit comme suit :
typeValeurDeRetour nomFonction(paramètres)
{
... /* Instructions de la fonction. */
}
 typeValeurDeRetour est le type de la valeur renvoyée par la fonction ;
 nomFonction est le nom de la fonction ;
 paramètres est la liste de paramètres de la fonction. Chaque paramètre est
précédé de son type comme dans la déclaration d’une variable. Les paramètres
sont séparés entre eux par la virgule (,)

Guy MBATCHOU Page 12


Préliminaires

La valeur de la fonction à renvoyer est spécifiée en utilisant la commande return, dont


la syntaxe est : return valeur;
Exemple de définition d’une fonction :
int discriminant(int a, int b, int c) /* Calcul du discriminant de l’équation du
second degré ax² + bx + c = 0*/
{
return (b*b - 4*a*c) ; //b² = b*b =pow(b,2)
}
Si une fonction n'a pas de paramètres, sa liste de paramètres sera void ou n'existera pas.
Il n'est pas nécessaire de mettre une instruction return à la fin d'une fonction qui ne renvoie pas
de valeur.
Exemple de fonction sans paramètre et sans valeur de retour :
void afficheAlea(void)
{
printf("Un nombre aléatoire : %f \n", (float)rand());
return; /*Pas nécessaire de mettre le return*/
}

L’instruction return définit la valeur du résultat mais aussi interrompt l’exécution de la


fonction en revenant dans la fonction qui l’a appelée.
Le compilateur met automatiquement en place le return dans les fonctions qui ne
renvoient pas de résultat et qui ne disposent pas d’instruction return.

2.3.4 - Appel des fonctions


L'appel d'une fonction se fait en donnant son nom, puis les valeurs de ses paramètres
entre parenthèses. S'il n'y a pas de paramètres, il faut quand même mettre les parenthèses, sinon
la fonction n'est pas appelée.
Exemple :
afficheAlea() ;
delta = discriminant(5, 6, 3) ;

2.3.5 - Déclaration d’une fonction


Il peut se trouver des situations où une fonction doit être appelée dans une autre fonction
définie avant elle. Comme cette fonction n'est pas définie au moment de l'appel, elle doit être
déclarée. De même, il est courant d'avoir à appeler une fonction définie dans un autre fichier
que le fichier d'où se fait l'appel. Encore une fois, il est nécessaire de déclarer ces fonctions.

Guy MBATCHOU Page 13


Préliminaires

Le rôle des déclarations est donc de signaler l'existence des fonctions aux compilateurs
afin de les utiliser, tout en reportant leur définition plus loin ou dans un autre fichier.
La syntaxe de la déclaration d'une fonction est la suivante :
typeValeurDeRetour nomFonction(typeParametres) ;
typeParamètres est la liste des types des paramètres que la fonction admet séparés par
des virgules.
De façon naturelle, la déclaration d’une fonction est placée à l’intérieur des déclarations
de toute fonction l’utilisant. Dans ce cas, nous avons à faire une déclaration dont la portée est
locale et limitée à la fonction où elle est déclarée.
Il est également possible de la déclarer avec une portée globale à toutes les fonctions
tout comme les variables globales. Il suffit de la déclarer à l’extérieur de toute fonction et qu’elle
soit avant la première définition d’une fonction.
Toute fonction devrait être déclarée avant d'être appelée pour la première fois mais la
définition d'une fonction peut faire office de déclaration si elle est définie avant son appel.
Entête de la fonction Factoriel
Entête de la fonction PPMC
Entête de la fonction PGCD
Entête de la fonction Puissance (puissance entière)
Entête de la fonction calculant le nième terme de la suite de Fibonacci

2.3.6 - Portée d’une variable


En fonction de la position de sa déclaration dans le code source, une variable peut avoir
une portée locale ou une portée globale. La portée de la variable exprime son accessibilité par
le programme principal ou par un module (fonction ou procédure).

2.3.6.1 - Les variables locales


Une variable a une portée locale (variable locale) dans les cas suivants :

 Elle est déclarée dans un module (fonction ou procédure) : variable locale au module.

 Elle est déclarée juste avant le début du programme principal : variable locale au
programme principal. En langage C, le programme principal n’existe pas puisque tout
est fonction !

Guy MBATCHOU Page 14


Préliminaires

 Elle est un paramètre d’un module : un paramètre d’un module est une variable locale
à ce module.

2.3.6.2 - Les variables globales


Une variable a une portée globale (variable globale) lorsqu’elle est déclarée hors d’un
module et avant ce module. Ainsi, on peut avoir des variables qui sont globales à certains
modules mais non accessibles aux autres.

Exemple en Pascal
Program Portée_des_variables;

VAR A : integer;

Procedure Procedure1;
Var
x : integer;
Begin
...
End;

VAR B : integer;

Function Fonction1() : integer;


Var
y : integer;
Begin
...
End;

VAR C : integer;

Function Fonction2() : integer;


Var
z : integer;
Begin
...
End;

VAR D : integer;

Procedure Procedure2;
Begin
...
End;

Guy MBATCHOU Page 15


Préliminaires

VAR E : integer;

{Début du programme principal}


BEGIN
...
END.

 La variable A est globale à tout le programme

 La variable B est globale à Fonction1, Fonction2, procédure2 et le programme


principal

 La variable C est globale à Fonction2, procédure2 et le programme principal

 La variable D est globale à procédure2 et le programme principal

 La variable E est locale au programme principal

 La variable x est locale à Procédure1

 La variable y est locale à Fonction1

 La variable z est locale à Fonction2

2.3.6.3 - Conflit entre variable locale et variable globale


Deux variables sont en conflit dans une portion du code (algorithme ou programme)
lorsqu’elles sont déclarées avec le même nom et type et sont accessibles par cette portion de
code.
En général, il s’agit d’un conflit entre une variable locale et une variable globale car le
compilateur n’acceptera pas la déclaration de deux variables ayant dans le même nom et même
type dans un module ou comme variable globale.
En cas de conflit, la variable locale l’emporte sur la variable globale c’est-à-dire que
c’est le contenu de la variable locale qui sera utilisé au lieu du contenu de la variable globale.
Attention : l’utilisation des variables globales doit être évitée au maximum et ne doit se
justifier que si elle ne peut pas être déclarée autrement.
Si vous déclarez une variable globale accessible par un module et que vous oubliez de
déclarer la variable locale alors qu’elle est nécessaire, le compilateur ne vous signalera pas
d’erreur et utilisera la variable globale : ce qui rendra vos résultats probablement faux.

Guy MBATCHOU Page 16


Préliminaires

2.4 - Activités
Exercice 202 : Poids : 10% - Seuil de validation : 80% - Titre : Module qui
affiche par ordre croissant 3 entiers.
Exercice 203 : Poids : 10% - Seuil de validation : 80% - Titre : Module qui
affiche la table de multiplication d’une valeur.
Exercice 204 : Poids : 20% - Seuil de validation : 80% - Titre : Calcul itératif
du factoriel
Exercice 205 : Poids : 20% - Seuil de validation : 70% - Titre : PGCD itératif
Ecrire une fonction itérative qui calcule le PGCD de deux entiers.
Exercice 206 : Poids : 20% - Seuil de validation : 70% - Titre : PPMC
itératif
Ecrire une fonction itérative qui calcule le PPMC de deux entiers.

Guy MBATCHOU Page 17


Préliminaires

Objectif 23 : Mode de passage d’un


paramètre à un module

3.1 - Durée :

3.2 - Seuil de validation : 70%

3.3 - Ressources
Lorsqu’on utilise un paramètre dans un module, on dit qu’on passe le paramètre au
module. Ce passage peut se faire de façons différentes en fonction du comportement du module
sur le contenu de la variable.

3.3.1 - Passage par valeur


Un paramètre est passé par valeur lorsque le module ne modifie pas le contenu du
paramètre. C’est-à-dire qu’il n’existe aucune instruction dans le module capable de modifier le
contenu du paramètre. Dans tous les exemples vus précédemment, les paramètres sont passés
par valeur puisque dans le corps du module, aucune instruction ne permet de modifier le
paramètre.

3.3.2 - Passage par adresse ou par référence


Un paramètre est passé par adresse si le module peut modifier le contenu du paramètre.
Dans ce cas, il existe au moins une instruction qui permet de changer le contenu du paramètre
par affection.

3.3.3 - Difficulté à modifier la valeur d’un paramètre


Or, en langage C, les paramètres ne sont passés que par valeur !
Exemple : Fonction de calcul de la valeur absolue d’un entier
#include <stdio.h>

int main(){
void valeurAbsolue(int);
int n = -8;

printf("Valeur avant l'appel de la fonction : %d \n", n);

Guy MBATCHOU Page 18


Préliminaires

valeurAbsolue(n);
printf("Valeur après l'appel de la fonction : %d \n", n);

return 0;
}

void valeurAbsolue(int x){


printf("Valeur au début de la fonction : %d \n", x);
if (x<0) x = -x;
printf("Valeur à la fin de la fonction : %d \n", x);
}
Résultat d’exécution
Valeur avant l'appel de la fonction : -8
Valeur au début de la fonction : -8
Valeur à la fin de la fonction : 8
Valeur après l'appel de la fonction : -8
A l’appel de la fonction valeurAbsolue, il y a eu transmission de la valeur de la variable
« n ». Cette valeur a été recopiée localement dans la fonction valeurAbsolue dans
l’emplacement nommé « x ». C’est sur cette copie de « n » que la fonction valeurAbsolue a été
exécutée ; c’est pour cette raison qu’à l’intérieur de la fonction la modification a eu bel et bien
lieu mais à la sortie de la fonction, la valeur de « n » n’a guère été modifiée.
En fait la fonction admet la modification du ou de ses paramètres mais à la sortie de la
fonction, le ou les paramètres gardent leur valeur initiale car les valeurs ont été recopiées en
local dans la fonction. Pour remédier à cette situation, en C, il faut bien que les fonctions
puissent modifier les valeurs de leur paramètre. Pour cela nous pouvons utiliser les variables
globales ou l’adresse des variables représentant les paramètres.

3.3.3.1 - Utilisation des variables globales


#include <stdio.h>

int n = -8;

int main()
{
void valeurAbsolue(void);

printf("Valeur avant l'appel de la fonction : %d \n",n);


valeurAbsolue();
printf("Valeur après l'appel de la fonction : %d \n",n);

return 0;

Guy MBATCHOU Page 19


Préliminaires

void valeurAbsolue(void){
printf("Valeur au début de la fonction : %d \n",n);
if (n<0) n = -n;
printf("Valeur à la fin de la fonction : %d \n",n);
}
Résultat d’exécution
Valeur avant l'appel de la fonction : -8
Valeur au début de la fonction : -8
Valeur à la fin de la fonction : 8
Valeur après l'appel de la fonction : 8
La variable « n » n’est plus déclarée dans la fonction main() mais comme une variable
globale à toutes les fonctions car elle est déclarée avant la définition des fonctions. De ce fait,
elle est accessible par toutes les fonctions nous permettant de réaliser notre solution de calcul
de la valeur absolue.
L’utilisation des variables globales doit être exceptionnelle car il peut se produire des
effets de bord ; une fonction peut malencontreusement modifier une valeur globale et cette
modification affectera la suite de vos résultats.

3.3.3.2 - Transmission en argument de l’adresse d’une variable


Nous passons en paramètre les adresses de nos paramètres sachant qu’elles ne peuvent
pas être modifiées puisque le C n’autorise que le passage par valeur. Dans la fonction appelée,
nous utiliserons cette adresse pour accéder à la valeur de la variable et nous aurions
l’opportunité de modifier sa valeur. Pour réaliser cela, nous ferons appel à la notion de pointeurs
que nous verrons plus loin. On passe en paramètre l’adresse (&nomVariable) de la variable
servant de paramètre comme nous l’avons vu lors de la lecture d’une variable avec la fonction
scanf("%d", &a). Pour que cela soit possible, il faut lors de la définition de la fonction, écrire
le ou les paramètres à modifier comme des pointeurs sur le type de données.

Guy MBATCHOU Page 20


Préliminaires

#include <stdio.h>

int main()
{
void valeurAbsolue(int *);
int n = -8;

printf("Valeur avant l'appel de la fonction : %d \n",n);


valeurAbsolue(&n);
printf("Valeur après l'appel de la fonction : %d \n",n);

return 0;
}

void valeurAbsolue(int * x){


printf("Valeur au début de la fonction : %d \n",(*x));
if ((*x)<0) (*x) = -(*x);
printf("Valeur à la fin de la fonction : %d \n",(*x));
}}
Résultat d’exécution
Valeur avant l'appel de la fonction : -8
Valeur au début de la fonction : -8
Valeur à la fin de la fonction : 8
Valeur après l'appel de la fonction : 8
« int *x » signifie que la variable « x » est un pointeur sur une valeur entière donc « x »
contient l’adresse de la valeur entière.
« *x » représente la valeur de la variable (emplacement mémoire) pointée par « x »
« &n » représente l’adresse de la variable « n »
Il en est de même lorsque nous utilisons la fonction scanf où il faut lui passer l’adresse
de la variable à lire et non la variable elle-même car le contenue de la variable devra être
changée après lecture.

Exemple :

Guy MBATCHOU Page 21


Préliminaires

//la fonction doubler double la valeur de la variable en paramètre


void doubler(int *p) //la fonction attend une adresse d’un entier et non l’entier en question
{
*p = (*p) * 2 ; // identique à (*p) *= 2; Modification de la valeur pointée par p
return;
}

int main()
{
int a = 5;
printf("Valeur avant = %d", a);
doubler(&a); //Passage en paramètre l’adresse de a
printf("Valeur après = %d", a);
return 0;
}
Entête de la fonction de tri dans l’ordre croissant de 3 valeurs
flottantes
Entête de la fonction qui prend en entrée 4 valeurs entières et
retourne le minorant et le majorant sans modifier les valeurs initiales

3.4 - Activités
Exercice 207 : Poids : 30% - Seuil de validation : 80% - Titre : Tri des
nombres
Ecrire la fonction de tri dans l’ordre croissant de 3 valeurs flottantes
Exercice 208 : Poids : 70% - Seuil de validation : 70% - Titre : Minimun et
Maximum des nombres
Ecrire la fonction qui prend en entrée 4 valeurs entières et retourne le minorant et le
majorant sans modifier les valeurs initiales

Guy MBATCHOU Page 22


Préliminaires

Objectif 24 : Fonctions récursives

4.1 - Durée :

4.2 - Seuil de validation : 60%

4.3 - Ressources
Un algorithme est dit récursif si dans son exécution, il s’appelle lui-même (récursivité
directe) ou s’il appelle un autre algorithme qui l’appelle (récursivité indirecte).
Un algorithme récursif doit obéit aux règles suivantes :
 il doit exister des critères pour lesquels la récursivité (les auto-appels) doit
s’arrêter
 chaque fois que l’algorithme s’appelle (directement ou indirectement), il doit
être plus proche de ses critères d’arrêt.
Le langage C autorise la récursivité des appels de fonctions.
Une fonction est dite récursive si elle contient dans sa définition un appel à elle-même
(récursivité directe) ou si elle contient dans sa définition un appel de fonction qui appelle à son
tour (ou à plus tard) la fonction initiale (récursivité indirecte).
Chaque appel de fonction entraîne une allocation d’espaces pour les variables locales et
les paramètres. La récursivité entraine donc un empilement d’espaces mémoires et ce n’est que
lors de la première instruction de return que les appels et les emplacements mémoires
commenceront à être dépilés et libérés.

4.4 - Activités
Exercice 209 : Poids : 20% - Seuil de validation : 80% - Titre : Factoriel
récursif
Ecrire une fonction récursive qui calcule le factoriel d’un entier.

Exercice 210 : Poids : 20% - Seuil de validation : 70% - Titre : PGCD


récursif
Ecrire une fonction récursive qui calcule le PGCD de deux entiers.

Guy MBATCHOU Page 23


Préliminaires

Exercice 211 : Poids : 20% - Seuil de validation : 70% - Titre : PPMC


récursif
Ecrire une fonction récursive qui calcule le PPMC de deux entiers.
Exercice 212 : Poids : 20% - Seuil de validation : 70% - Titre : Puissance
récursive
Ecrire une fonction récursive qui calcule Xn.

Exercice 213 : Poids : 20% - Seuil de validation : 80% - Titre : Suite de


Fibonacci
Ecrire une fonction qui calcule le nième terme de la suite de Fibonacci définie par :
U1=1 U2=1 UN=UN-1 + UN-2 (pour N>2)

Guy MBATCHOU Page 24


Préliminaires

Objectif 25 : Fonctions à nombre


variable de paramètres

5.1 - Durée :

5.2 - Seuil de validation : 50%

5.3 - Ressources
En général, les fonctions ont un nombre constant de paramètres (arguments) mais le
langage C offre aux fonctions la possibilité d’avoir des arguments variables en nombre. C’est
le cas des fonctions d'entrée / sortie du C dont la liste des arguments n'est pas fixée afin de
pouvoir réaliser un nombre arbitraire d'entrées / sorties.
Pour déterminer le nombre de paramètres, on peut soit :
 mettre un premier argument en paramètre désignant le nombre de paramètres
 définir une valeur particulière de paramètre qui détermine la fin de la liste des
paramètres
Pour récupérer les différents paramètres, le langage C dispose du type de données
va_list et des fonctions va_start(), va_arg() et va_end() contenues dans la bibliothèque
stdarg.h. Pour réaliser une fonction à nombre d’arguments variables, il faut qu’un certain
nombre d’arguments (au moins 1) soit fixe c’est-à-dire obligatoire.
Pour indiquer au compilateur qu'une fonction peut accepter une liste de paramètres à
nombre variable, il faut simplement utiliser des points de suspension dans la liste des
paramètres.

typedeRetour nomFonction(parametresFixes, …)
Dans la fonction, il faut déclarer une variable de type va_list permettant de stocker un
à un les différents paramètres de la fonction.
Pour positionner sur les arguments variables, il faut initialiser la variable de type va_list
par le dernier argument à nombre variable de la fonction. Cela se fait à travers la fonction
va_start(variable, paramètre) où « variable » est le nom de la variable de type va_list, et
paramètre est le dernier paramètre fixe de la fonction. Dès que « variable » est initialisée, vous
pouvez récupérer un à un les paramètres à l'aide de la fonction va_arg().

Guy MBATCHOU Page 25


Préliminaires

va_arg(variable, typeValeur) : renvoie la valeur de l’argument en cours avec le type


typeValeur et met à jour variable pour passer au paramètre suivant. Vous pouvez utiliser cette
expression autant de fois que vous le désirez, mais assurez-vous qu’il y a encore des arguments
avant de l’utiliser. Après avoir tout récupérer les paramètres, il faut libérer la mémoire avec la
fonction va_end().
va_end(variable) : permet de détruire la variable « variable » pour libérer la mémoire
des arguments lus.
#include<stdio.h>
#include<stdarg.h> //utiliser pour le type va_list et les fonctions va_start(), va_arg() et va_end()

int Somme(unsigned int nombre, ...){//nombre représente le nombre d'arguments


va_list parametre; //contient les différents arguments non définis
unsigned int i;
int Resultat = 0;
int Valeur_Courante;

va_start(parametre, nombre);//initialisation de la variable parametre par le premier argument variable

for(i=0; i<nombre; i++){


Valeur_Courante = va_arg(parametre, int);//recupérer l'argument courant
printf("Valeur en cours de traitement = %d\n",Valeur_Courante);
Resultat += Valeur_Courante;
}
va_end(parametre);

return Resultat;
}

double Produit(double Valeur_Fin, ...){// Valeur_Fin = la valeur de fin de la liste des valeurs en paramètre
va_list parametre;
unsigned int i;
double Resultat = 1;
float Valeur_Courante;

va_start(parametre, Valeur_Fin);//initialisation de la variable parametre par le premier argument variable

while((Valeur_Courante = va_arg(parametre, double)) != Valeur_Fin){


printf("Valeur en cours de traitement = %.2lf\n",Valeur_Courante);
Resultat *= Valeur_Courante;
}
va_end(parametre);

return Resultat;
}

int main(){
printf("\n\nLa somme des 5 premiers entiers non nuls = %d\n\n", Somme(5, 1,2,3,4,5));
printf("\n\nLe produit des réels = %0.2lf\n\n", Produit(-1.0, 1.0, 2.0, 3.0, 4.0, 5.0, -1.0));
return 0;
}

Guy MBATCHOU Page 26


Préliminaires

5.4 - Activités
Exercice 214 : Poids : 30% - Seuil de validation : 80% - Titre : QCM
Exercice 215 : Poids : 70% - Seuil de validation : 50% - Titre : Comptage du
nombre de voyelles dans une liste de caractères (pas une chaîne) en paramètre

Guy MBATCHOU Page 27


Préliminaires

Objectif 26 : Modularisation d’un


programme

6.1 - Durée :

6.2 - Seuil de validation : 80%

6.3 - Ressources

6.3.1 - La fonction main


Nous avons dit précédemment qu’en C, Tout est fonction même le programme principal.
Ce dernier est matérialisé par la fonction main() qui peut être paramétrée ou non et renvoyée
des données. La fonction main() respecte les mêmes règles de définitions des fonctions.
Lorsque la fonction main() est paramétrée, le mécanisme utilisé par l’utilisateur pour
fournir les arguments dépend de l’environnement. Soit l’environnement est graphique et dans
ce cas, il s’agira des commandes de menus ; soit l’environnement est en mode texte (ou mode
commandes comme le DOS ou UNIX) et dans ce cas, il s’agira des valeurs ou paramètres
associés à la commande de lancement de programme. Le nom de la commande est le nom du
programme.
Les paramètres transmis à la fonction main sont toujours (considérés comme) des
chaînes de caractères séparées par des espaces. La fonction main() a deux paramètres :
 Le premier argument est de type int et représente le nombre de paramètres
fournis lors de l’appel de la commande. Le nom de la commande (programme)
est considéré comme un paramètre et représente le tout premier paramètre.
 Le second est un tableau de chaînes caractères. Or la chaîne de caractères
n’existant pas en C, le second argument sera un tableau de pointeurs de
caractères ou un pointeur des pointeurs de caractères. La première chaîne ou le
premier élément pointe toujours sur la chaîne donnant le nom du programme.
Les autres éléments (chaînes) pointent sur les paramètres de la ligne de
commande.
L’entête de la fonction main :

Guy MBATCHOU Page 28


Préliminaires

int main(int nbre_arg, char * liste_arg[])


Le programme appelé peut renvoyer un code d'erreur au programme appelant (soit le
système d'exploitation, soit un autre programme). Ce code d'erreur est en général 0 quand le
programme s'est déroulé correctement. Toute autre valeur indique qu'une erreur s'est produite
en cours d'exécution. La valeur du code d'erreur est renvoyée par la fonction main. Le code
d'erreur doit toujours être un entier. La fonction main peut donc (et même normalement doit)
être de type entier.
Exemple :
#include <stdio.h>

int main(int nbre_arg, char * liste_arg[])


{
int i;

printf("Le nom de la commande est : %s \n", liste_arg[0]);


if (nbre_arg > 1){
printf("La commande a %d paramètres \n", nbre_arg - 1);
for(i=1; i < nbre_arg; i++){
printf("Paramètre N° %d = %s \n", i, liste_arg[i]);
}
}
else{
printf("La commande n'a pas de paramètre \n");
}
system("PAUSE");
return 0;
}
Résultat d’exécution :
D:\>Test_Com.exe

Le nom de la commande est : Test_Com.exe


La commande n'a pas de paramètre

Guy MBATCHOU Page 29


Préliminaires

D:\>Test_Com.exe azerty qwerty jean remi

Le nom de la commande est : Test_Com.exe


La commande a 4 paramètres
Paramètre N° 1 = azerty
Paramètre N° 2 = qwerty
Paramètre N° 3 = jean
Paramètre N° 4 = remi

6.3.2 - Fonction statique


Par défaut, en C, lorsqu'une fonction est définie dans un fichier, elle peut être utilisée
dans tout autre fichier pourvu qu'elle soit déclarée avant son utilisation. Dans ce cas, la fonction
est dite externe. Il peut cependant être intéressant de définir des fonctions locales à un fichier,
soit afin de résoudre des conflits de noms (entre deux fonctions de même nom et de même
signature mais dans deux fichiers différents), soit parce que la fonction est uniquement d'intérêt
local. Le C fournit donc le mot clé static qui, une fois placé devant la définition et les
éventuelles déclarations d'une fonction, la rend unique et utilisable uniquement dans ce fichier.
À part ce détail, les fonctions statiques s'utilisent exactement comme des fonctions classiques.

6.4 - Activités
Exercice 216 : Poids : 20% - Seuil de validation : 80% - Titre : Traduction
en langage C d’un programme modulaire
Traduire le programme (Salutation_et_Calcul_Age) ci-dessus en langage C en
remplaçant la chaîne de caractères par un caractère.

Exercice 217 : Poids : 50% - Seuil de validation : 60% - Titre : Arithmétique


libre
Ecrire un programme qui prend en entrée une opération arithmétique et le réalise. A
l’exécution du programme, si l’utilisateur saisit par exemple 5 + 3 et le programme réalisera la
somme de 5 et 3 puis affichera le résultat.

Guy MBATCHOU Page 30


Préliminaires

Objectif 27 : Préprocesseur et
compilation séparée

7.1 - Durée :

7.2 - Seuil de validation : 50%

7.3 - Ressources
Jusqu’à présent, nous avons toujours écrit tout notre programme (main + autres
fonctions) dans un seul fichier d’extension « .c ». Or il arrive que le programme contienne un
nombre grand de fonctions ; ce qui rend le fichier long et difficile à lire. Précédemment, nous
avons vu la modularité du programme en plusieurs fonctions. A présent, nous allons découper
notre programme en plusieurs fichiers ce qui facilitera son organisation, sa lecture, sa
compréhension, la réutilisation de certaines fonctions dans d’autres projets et sa maintenance.

7.3.1 - Fichier source


Un programme écrit en plusieurs fichiers contient obligatoirement plusieurs fichiers
sources. Un fichier source est un fichier d’extension « .c » contenant le code source (définition)
des fonctions. Nous avons vu précédemment pour éviter de respecter un quelconque ordre lors
de la définition des fonctions, on peut insérer au début du fichier source les déclarations des
différentes fonctions. En compilation séparée, ces déclarations peuvent faire l’objet d’un fichier
qui est appelé fichier d’entête.

7.3.2 - Fichier d’entête


Un fichier d’entête est un fichier d’extension « .h » contenant les :
 déclarations de fonctions,
 définitions des types de données (types utilisateur),
 définitions de macros,
 etc.
communes à plusieurs fichiers sources.
Un fichier d’entête ne doit pas forcément contenir tous les éléments cités.

Guy MBATCHOU Page 31


Préliminaires

Ces fichiers doivent être inclus dans les fichiers sources nécessaires avec l’instruction
suivante :
include "fichier_entete.h"
L’inclusion du fichier d’entête se fait avec les guillemets (") contrairement aux fichiers
des bibliothèques qui se fait avec des crochets (< et >).

7.3.3 - Les directives du préprocesseur


Vu qu’un fichier d’entête est conçu pour être inclus dans plusieurs fichiers sources
pouvant appartenir au même projet, il peut arriver qu’il y ait des inclusions multiples qui
alourdissent inutilement le programme. Pour éviter cela, il existe des directives du
préprocesseur qui vérifiera si les fichiers d’entête non pas été inclus avant de les inclure.
Les directives du préprocesseur sont des instructions commençant par le symbole « # »
qui sont réalisées avant la compilation des fichiers sources.

7.3.3.1 - Les inclusions de fichiers


La directive include permet l’inclusion d’un fichier d’entête (#include "Entete.h" par
exemple) ou d’une bibliothèque de fonctions (#include <float.h> par exemple) dans un fichier
source.
En fait, avant la compilation, le préprocesseur parcourt tous les fichiers sources et
remplace les directives par le contenu du fichier inclus.

7.3.3.2 - Les constantes du préprocesseur ou constantes symboliques


La directive define permet de définir une constante du préprocesseur. Sa syntaxe est la
suivante :
#define Nom_Constante Valeur_Constante
Remarquez qu’à la fin de la directive define, il n’y a pas de « ; »
Ne pas confondre une constante du préprocesseur et une constante (const float pi =
3,14 ;) telle que vu précédemment. Les constantes occupent de l’espace en mémoire bien que
leur valeur ne puisse être changée alors que les constantes du préprocesseur n’occupent pas.
Avant la compilation, les constantes du préprocesseur sont remplacées par leur valeur.
Ces constantes du préprocesseur nous permettent d’éviter de fixer les valeurs dans nos
programmes : il est plus facile de lire un programme contenant une constante de préprocesseur
(chaîne de caractère explicite) qu’un programme contenant une valeur. De plus, si la valeur

Guy MBATCHOU Page 32


Préliminaires

représentée par la constante du préprocesseur doit être modifiée, on la modifie juste dans la
directive du processeur sans se soucier du reste du programme Une utilité de cette constante du
préprocesseur se verra lors de la déclaration des tableaux puisque la taille d’un tableau ne peut
être ni une variable, ni une constante.
Il est possible de définir des constantes du préprocesseur contenant des calculs à base
des opérations de base telle que l’addition, la soustraction, la multiplication, la division et le
modulo. Dans ce cas, il faut mettre vos expressions entre parenthèses.
Exemple :
#define TAILLE_MOYENNE 175 //taille exprimée en centimètre
#define MASSE_MOYEN 80 //masse exprimée en kilogramme
#define IMC_MOYEN (MASSE_MOYEN / (TAILLE_MOYENNE * TAILLE_MOYENNE)) //IMC = Indice
de Masse Corporelle
Il est fortement recommandé que les constantes soit en lettres majuscules.
Il existe aussi des constantes de préprocesseur sans valeur :
#define Nom_Constante
Elle permet juste de savoir que la constante est tout simplement définie. Son intérêt sera
mis en exergue lorsque nous définirons plus loin les conditions dans les directives du
préprocesseur.

7.3.3.3 - Les macros


Une macro est un ensemble d’instructions auquel un identificateur est affecté pour
l’identifier. Une macro contient un nombre faible d’instructions simples (pas complexes). Une
macro est introduite par define et respecte la syntaxe suivante :
#define NOM_MACRO(paramètre1, …, paramètre P) instruction 1 ; \
instruction 2 ; \
…\
instruction N ;
Le nom de la macro est suivi des parenthèses ouvrante et fermante même si la macro
n’a pas de paramètre. Les paramètres de la macro n’ont pas de type.
Si la macro dispose de plusieurs instructions que vous voulez mettre sur plusieurs lignes,
il faut absolument précéder la nouvelle ligne du caractère antislash « \ »
Exemple : Macro sans paramètre
#define LIEU() printf("Nous sommes à l’Université Assane SECK de Ziguinchor") ;
Exemple : Macro avec paramètres

Guy MBATCHOU Page 33


Préliminaires

#define ADRESSE(Nom, Ville) \


Printf("%s habite la ville %s", Nom, Ville) ;
Lors de l’utilisation de la macro, elle est appelée comme une fonction. Le processeur
remplace le nom de la macro par le code associé avant la compilation. Si la macro est
paramétrée alors le paramètre est remplacé par la valeur d’appel.

7.3.3.4 - Les conditions


Le langage du préprocesseur contient des instructions conditionnelles permettant
d’exécuter des instructions sous certaines conditions.
#if condition 1
Instructions du code source à compiler si la condition est vraie
#else
Instructions du code source à compiler si la condition est fausse
#endif
S’il y a plusieurs conditions, on aura :
#if condition 1
Instructions du code source à compiler si la condition 1 est vraie
#elif condition 2
Instructions du code source à compiler si la condition 2 est vraie
#elif condition 3
Instructions du code source à compiler si la condition 3 est vraie
#endif
Pour éviter les inclusions multiples des fichiers d’entête annoncées précédemment, on
utilise les constantes symboliques sans valeur. La première inclusion définira la constante et à
la seconde et autre, on testera si la constante symbolique est définie ou non et l’inclusion se fera
en fonction. Pour cela le langage du préprocesseur dispose de #ifdef (avec optionnellement
#elifdef) et #ifndef (avec optionnellement #elifndef) permettant respectivement de tester si une
constante est définie ou non.
Dans le fichier d’entête, les prototypes ou déclarations de fonctions sont conditionnés
par une constante symbolique
Exemple : Réalisation d’une mini-calculatrice
Le fichier d’entête nommé « Entete.h » est le suivant :

Guy MBATCHOU Page 34


Préliminaires

#ifndef ENTETE
#define ENTETE

double Addition(double, double);


double Soustraction(double, double);
double Multiplication(double, double);
double Division(double, double);
#endif // ENTETE
L’interprétation du code ci-dessus est le suivant : lors de l’inclusion du fichier Entete.h,
si la constante symbolique ENTETE est non définie alors on la définit et inclut les prototypes
des fonctions. Si par hasard, dans le même programme, ce fichier est inclus une seconde fois,
les prototypes ne seront plus inclus car la constante symbolique ENTETE sera déjà définie pour
montrer que les prototypes ont été déjà inclus.
Le fichier source nommé « Entete.c » est le suivant :
#include<float.h>
#include "Entete.h"

double Addition(double a, double b){


return a+b;
}

double Soustraction(double a, double b){


return a-b;
}

double Multiplication(double a, double b){


return a*b;
}

double Division(double a, double b){


if (b==0) return FLT_MAX; //Infini
else return a/b;
}
Un extrait du fichier contenant la fonction principale est le suivant :

Guy MBATCHOU Page 35


Préliminaires

#include <stdio.h>
#include "Entete.h"

int main()
{
double A, B, R;

printf("Addition des int\n");


printf(" Valeur A: ");
scanf("%lf",&A);
printf(" Valeur B: ");
scanf("%lf",&B);
R = Addition(A,B);
printf("Résultat = %lf", R);
return 0;
}

7.4 - Activités
Exercice 218 : Poids : 30% - Seuil de validation : 80% Titre : QCM

Guy MBATCHOU Page 36


Activités à objectifs multiples

Activités à objectifs multiples

Exercice 219 : Seuil de validation : 80% - Titre : Menu en un fichier


A partir des exercices d’application contenus dans le cours, réaliser un menu permettant
d’exécuter chacun d’eux.
MENU
1. Factoriel
2. PPMC
3. PGCD
4. Puissance Xn
5. Suite de Fibonacci
0. Quitter

Faites votre choix :


Lors d’exécution du programme, si aucun paramètre n’est donné, le menu s’affiche. Si
un nombre est fourni lors de l’exécution alors le programme exécute directement la fonction
concernée et à la fin s’arrête.
Exemple : Si le fichier exécutable est Menu.exe (sous MS Windows) alors si à
l’exécution, on Menu.exe 3 alors le programme réalise directement le PGCD. Si le nombre
fournit n’existe pas (non compris entre 0 et 5) alors le programme envoie un message d’erreur
et propose de saisir à nouveau le choix en lui proposant les choix possibles.

Exercice 220 : Seuil de validation : 80% - Titre : Menu séparé en plusieurs


fichiers
Reprendre l’exercice précédent en réalisant un programme dont les fonctions itératives
seront dans un fichier source différent des fonctions récursives.
Le menu principal est le suivant :
MENU
1. Itératif
2. Récursif
0. Quitter

Faites votre choix :


Lorsqu’on choisit 1 ou 2, on affiche le menu de l’exercice 1 et on appelle les fonctions
itératives ou récursives.

Guy MBATCHOU Page 37


Récapitulatif des activités par objectifs

Récapitulatif des activités par objectifs

Objectifs
Seuil 60% 70% 70% 60% 50% 80% 50%
Seuil N° O21 O22 O23 O24 O25 O26 O27
80% 201 100%
80% 202 10%
80% 203 10%
80% 204 20%
70% 205 20%
70% 206 20%
80% 207 50% 30%
70% 208 50% 70%
8% 209 10% 20%
Activités

70% 210 10% 20%


70% 211 10% 20%
70% 212 10% 20%
80% 213 10% 20%
80% 214 30%
50% 215 10% 70%
80% 216 20%
60% 217 20% 30% 50%
80% 218 30%
50% 219 50% 10% 50% 50%
50% 220 50% 10% 50% 50% 50% 80%
Total 200% 280% 230% 150% 100% 170% 110%

Guy MBATCHOU Page 38

Vous aimerez peut-être aussi