Explorer les Livres électroniques
Catégories
Explorer les Livres audio
Catégories
Explorer les Magazines
Catégories
Explorer les Documents
Catégories
Programmation modulaire
Pr Rachid DEHBI
Département Mathématique et
informatique
Faculté des sciences Ain chock
dehbirac@yahoo.fr
PRÉ-REQUIS
• Programmation 1.
• La règle de 3R.
dehbirac@yahoo.fr
• La crise du génie logiciel
• Critères de qualité logiciel
• Principes de génie logiciel
• Historique des langages
• Historique des méthodologies de programmation
dehbirac@yahoo.fr
(anglais software engineering) est une science
de génie industriel qui étudie les méthodes de travail et les
bonnes pratiques des ingénieurs en développement logiciels.
dehbirac@yahoo.fr
La crise du logiciel
dehbirac@yahoo.fr
Critères de qualité du logiciel
• Utilité : le logiciel doit correspondre aux besoins des
utilisateurs
• Utilisabilité : ergonomie et facilité d'apprentissage et
d'utilisation
• Fiabilité : correction et conformité, robustesse et sureté
• Efficacité : temps d'exécution faible et utilisation réduite
des ressources
• Interopérabilité : interactions possibles entre logiciels
• Portabilité : le logiciel doit pouvoir tourner sur le plus
possible de systèmes
• Maintenabilité : facilité de test, brièveté et lisibilité,
extensibilité
• Réutilisabilité : le code doit pouvoir être réutilisé au
maximum
dehbirac@yahoo.fr
Principes du génie logiciel
• Généralisation : regrouper du code commun à
plusieurs programmes dans un seul programme et
regrouper un ensemble de fonctionnalités semblables en
une fonctionnalité paramétrable.
• Abstraction : décrire des entités à différents niveaux
d'abstraction, ne donner que les éléments pertinents et
omettre ceux qui ne le sont pas.
• Modularité : décomposer les logiciels en composants
aussi petits et indépendants que possible.
• Documentation : documenter le code et produire des
notices permettant la réutilisation.
• Vérification : respecter des spécifications initiales,
permettre des tests unitaires.
dehbirac@yahoo.fr
Historique des langages
dehbirac@yahoo.fr
dehbirac@yahoo.fr
Classement Tiobe 2015
dehbirac@yahoo.fr
Historique sur les méthodes de
programmation
dehbirac@yahoo.fr
Synthèse
dehbirac@yahoo.fr
Principe de la programmation
modulaire
Un long programme est difficile à appréhender
globalement.
Il vaut donc mieux le scinder en petits programmes
un programme principal fait appel à ses sous-
programmes , qui peuvent eux-mêmes faire appel à
d’autres sous-programmes, du programme principal, et
ainsi de suite.
C’est le principe du raffinement successif.
De plus certains sous-programmes peuvent servir dans
d’autres programmes,
C’est le principe de la modularité.
Ces principes sont mis en œuvre en langage C grâce
aux fonctions.
dehbirac@yahoo.fr
Principe de la modularité
• Plutôt que de placer tout le code de notre
programme dans un seul fichier: main.c
• Nous le découpons en plusieurs action
Raffinement successif
• Puis nous regroupons les actions dans de petits
fichiers
modularité
dehbirac@yahoo.fr
Avantage de la programmation
modulaire
• Réutilisation du code
• Notion de librairie
• Augmente la lisibilité d’un programme
• Réalise des objectifs précis
• Améliore le débogage (Compilation séparée)
• Améliore la maintenance d’un programme
dehbirac@yahoo.fr
Implémentation de la modularité
• Plusieurs fichiers par projet
dehbirac@yahoo.fr
La compilation séparée
dehbirac@yahoo.fr
Synthèse
• Avantage de la modularité en C
• Expliquer le principe de la compilation séparée
• Lister et trier les étapes de la compilation en C
Fonctions définies par les
utilisateurs
Exemple
Sans Fonction: Avec Fonction:
#include <stdio.h>
#include <stdio.h> #include <math.h>
#include <math.h> double f(double x)
void main(void) {
{ return((sin(x) + log(x))/(exp(x)
float x, y; + 2));
printf("x = "); }
scanf("%f",&x); void main(void)
while (x != 1000) {
{ float x, y;
y = (sin(x) + log(x))/(exp(x) + 2); printf("x = ");
printf("f(%f) = %f\n", x, y); scanf("%f",&x);
printf("x = "); while (x != 1000)
scanf("%f",&x); {
} y = f(x);
} printf("f(%f) = %f\n", x, y);
printf("x = ");
scanf("%f",&x);
}
}
dehbirac@yahoo.fr
Fonction?
• Une suite d'instructions élémentaires
• Représente une seule action.
• La base de la programmation modulaire:
La réalisation d'un algorithme c'est la
décomposition en une suite de fonctions simples
pouvant réaliser une ou plusieurs fonctions
beaucoup plus compliquées.
dehbirac@yahoo.fr
Caractéristiques des fonctions: appel,
retour
dehbirac@yahoo.fr
Utilisation des fonctions
• Etape1- La déclaration des prototypes: Elle
permet de définir au compilateur les paramètres
d'entrée et de sortie afin de pouvoir vérifier lors
d'appel de fonction l'ordre de passage des
paramètres.
• Etape2- La déclaration de fonction: Elle décrit
l'enchaînement de toutes les instructions permettant
de réaliser la fonction.
• Etape3- L'appel de fonction: elle dirige le
programme principal ou une autre fonction sur la
fonction à exécuter en donnant les variables
d'entrées (et/ou)l'affectation de la variable de sortie.
dehbirac@yahoo.fr
Syntaxe d’utilisation
• La déclaration des prototypes:
<type_iden_sortie> iden_fonc(<type> iden_1,..., <type> iden_n);
• La déclaration de fonction:
<type_iden_sortie> iden_fonc(<type> iden_1,..., <type> iden_n)
{
/* Déclaration de variable(s) locale(s) */
<type> iden_2,...,iden_m;
.
.
.
/* renvoie dans le paramètre de sortie */
return(valeur);
}
• L'appel de fonction:
iden_var_sortie = iden_fonc(iden_1_var,...,iden_n_var) ;
ou
iden_fonc(iden_1_var,...,iden_n_var) ;
dehbirac@yahoo.fr
Scénario Exemple:
#include <stdio.h>
/* Déclaration des variables globales */
int a,b,res;
/* Programme Principal */
void main()
{
printf("Donnez les valeurs de a et b ");
scanf("%d %d",&a,&b);
res=a+b;
printf("\t\tJe traite\n");
dehbirac@yahoo.fr
Solution1: sans valeur de retour ni
paramètre
#include <stdio.h> void affichage(void)
/* Déclaration des variables globales */ {
int a,b,res; printf("L'addition de a=%d et de
/* Déclaration des prototypes */ b=%d est égale à %d\n",a,b,res);
void saisie(void); }
void traitement(void); /* Programme Principal */
void affichage(void); void main()
/* Déclaration des fonctions */ {
void saisie(void) saisie();
{ traitement();
printf("Donnez les valeurs de a et b "); affichage();
scanf("%d %d",&a,&b); }
}
void traitement(void)
{
res=a+b;
printf("\t\tJe traite\n");
}
dehbirac@yahoo.fr
solution2: Exemple sans valeur de retour
#include <stdio.h> void traitement(int val1,int val2)
/* Déclaration des variables {
globales */ printf("\t\tJe traite\n");
/* traitement */
int a,b,res;
res=val1+val2;
/* Déclaration des prototypes */ }
void saisie(void); void affichage(void)
void traitement(int val1,int val2); {
void affichage(void); printf("L'addition de a=%d et de
/* Déclaration des fonctions */ b=%d est égale à %d\n",a,b,res);
void saisie(void) }
{ /* Programme Principal */
void main()
printf("Donnez les valeurs de a et b
{
"); saisie();
scanf("%d %d",&a,&b); traitement(a,b);
} affichage();
}
dehbirac@yahoo.fr
solution3: Exemple avec valeur de retour
#include <stdio.h> printf("\t\tJe traite\n");
/* Déclaration des variables globales /* traitement */
*/ val3=val1+val2;
int a, b, res; /* Renvoie la valeur de val3 */
/* Déclaration des prototypes */ return(val3);
void saisie(void); }
int traitement(int val1,int val2); void affichage(void)
void affichage(void); {
/* Déclaration des fonctions */ printf("L'addition de a=%d et de
void saisie(void) b=%d est égale à %d\n",a,b,res);
{ }
printf("Donnez les valeurs de a et b /* Programme Principal */
"); void main()
scanf("%d %d",&a,&b); {
} saisie();
int traitement(int val1,int val2) res=traitement(a,b);
{ affichage();
/* Déclaration de variable locale */ }
int val3;
dehbirac@yahoo.fr
Fonction globale ou locale?
#include <stdio.h> #include <stdio.h> #include <stdio.h>
#include <math.h> #include <math.h> #include <math.h>
dehbirac@yahoo.fr
Pragmatique
• Pour mettre un peu d’ordre dans un programme
faisant intervenir beaucoup de fonctions:
▫ On peut commencer par la définition de la fonction
principale, précédée de la déclaration des fonctions
dont elle a besoin.
▫ On définit ensuite ces fonctions auxiliaires, chacune
d’elles précédée des déclarations des fonctions
auxiliaires de second niveau dont elles ont besoin, et
ainsi de suite.
dehbirac@yahoo.fr
Problème 1
• Ecrire une fonction SOMME de type float qui
calcule la somme de deux nombres réels.
• Ecrire une fonction MOYENNE de type float qui
calcule la moyenne arithmétique de deux
nombres réels.
• Ecrire un programme se servant de ces deux
fonctions pour afficher la somme et la moyenne
de deux nombres réels saisis au clavier.
Problème
dehbirac@yahoo.fr
La compilation séparée
dehbirac@yahoo.fr
Exemple de déclaration avec les
fichiers en-tête
/* calcul.c */ /* defini.h */
#include <stdio.h> double f(double x)
#include <math.h> {
#include "defini.h" return((sin(x) + log(x))/(exp(x) +
void main(void) 2));
{ }
float x, y;
printf("x = ");
scanf("%f",&x);
while (x != 1000)
{
y = f(x);
printf("f(%f) = %f\n", x, y);
printf("x = ");
scanf("%f",&x);
}
}
dehbirac@yahoo.fr
Exemple de déclaration avec les
fichiers en-tête et les fichiers source
/* calcul.c */ /* defini.h */ /* defini.c */
#include <stdio.h> double f(double x); #include <math.h>
#include <math.h> #include "defini.h"
#include "defini.h"
void main(void) double f(double x)
{ {
float x, y; return((sin(x) +
printf("x = "); log(x))/(exp(x) + 2));
scanf("%f",&x); }
while (x != 1000)
{
y = f(x);
printf("f(%f) =
%f\n", x, y);
printf("x = ");
scanf("%f",&x);
}
}
dehbirac@yahoo.fr
Mode de transmission des paramètres
• Passage par valeur: Lorsqu’on ne veut pas
changer la valeur d’un paramètre on parle de
transmission par valeur (call by value) (mode par
défaut)
le Sous-programme ne reçoit qu’une copie de la
valeur.
• Passage par référence: Lorsqu’on veut se
permettre la possibilité de changer la valeur on parle
de transmission par référence (call by reference)
Technique d’ utilisation des pointeurs
dehbirac@yahoo.fr
Passage par valeur
/* valeur_1.c */ /* valeur_2.c */
#include <stdio.h> #include <stdio.h>
void affiche(int n) void affiche(int n)
{ {
printf("%d \n", n); n = 4;
} printf("%d \n", n);
void main(void) }
{ void main(void)
int n = 3; {
affiche(n); int n = 3;
} affiche(n);
printf("%d \n", n);
}
Résultat: Résultat:
3 4
3
La fonction affiche() n’a donc pas changé la valeur de n dans la fonction principale.
dehbirac@yahoo.fr
Problème3
• Implémenter la modularité sur le problème 1
Porté des variables: variable globale
• Une variable globale est une variable déclarée
avant toute définition de fonction.
• Elle est connue de toutes les fonctions,
dehbirac@yahoo.fr
Voyons cependant comment cela
fonctionne
/* global_1.c */
#include <stdio.h>
int n = 3; L’exécution de ce
void affiche(void) programme fait afficher
{ printf("%d \n", n);
n = 4; La fonction affiche() a
printf("%d \n", n); donc changé la valeur de n
} dans la fonction principale.
void main(void)
{
printf("%d \n", n);
n = 2;
affiche();
printf("%d \n", n);
}
dehbirac@yahoo.fr
Par opposition • Quelle
considérée
est la
lors
variable
de son
/* global_2.c */ utilisation ?
#include <stdio.h> • La réponse est simple : celle
int n = 3; qui a été déclarée le plus
void affiche(int n) récemment, c’est à-dire la plus
{ locale à l’intérieur du sous-
n = 4; programme (et, plus
printf("%d \n", n); généralement, à l’intérieur du
} bloc).
void main(void) Explication: La déclaration de l’argument
{ n dans la fonction affiche() le fait
affiche(n); considérer comme une variable locale. La
printf("%d \n", n); variable n du corps de cette fonction
} correspond à la dernière variable déclarée,
donc à la variable locale, et non à la
Son exécution fait afficher 4 variable globale ; ceci explique pourquoi la
puis 3. valeur de la variable globale, elle, n’a pas
changée.
POURQUOI???
dehbirac@yahoo.fr
La classe d’allocation des variables
globales
• Les variables globales existent pendant toute
l’exécution du programme dans lequel elles
apparaissent.
• Leurs emplacements en mémoire sont parfaitement
définis lors de l’édition de liens.
Elles font partie de la classe d’allocation
statique.
• RQ: ces variables se voient initialisées à zéro,
avant le début de l’exécution du programme, sauf,
bien sûr, si vous leur attribuez explicitement une
valeur initiale au moment de leur déclaration.
dehbirac@yahoo.fr
Variable locale automatique
double puiss(double x, int n) Par défaut, les variables locales ont
{ une durée de vie limitée à celle
double y; d’une exécution de la fonction dans
int i; laquelle elles figurent.
y = 1; Plus précisément, leurs
for (i=1; i <= n; i++) y = y*x; emplacements ne sont pas
return(y); définis de manière permanente
} comme ceux des variables globales.
Un nouvel espace mémoire leur
est alloué à chaque entrée dans
la fonction et libéré à chaque
sortie.
Il sera donc généralement différent
d’un appel au suivant.
On traduit cela en disant que la
classe d’allocation de ces variables
est automatique.
dehbirac@yahoo.fr
Les variables locales statiques
#include <stdio.h> Le besoin d’attribuer un
main() emplacement permanent à une
{ variable locale et qu’ainsi sa
void fct(void) ; valeur se conserve d’un appel
int n ;
au suivant
for ( n=1 ; n<=5 ; n++)
fct() ; mise en œuvre: la déclarer à
} l’aide du mot-clé static
void fct(void) le mot static employé sans
{ indication de type est équivalent à
static int i ; static int
i++ ;
printf ("appel numéro :
%d\n", i) ; Remarque: Prenez garde à ne pas
} confondre une variable locale de
Résultat : classe statique avec une variable
appel numéro : 1 globale. En effet, la portée d’une
appel numéro : 2 telle variable reste toujours limitée
appel numéro : 3 à la fonction dans laquelle elle est
appel numéro : 4 définie.
appel numéro : 5
dehbirac@yahoo.fr
Le cas des fonctions récursives
Le langage C autorise la récursivité des appels de
fonctions selon deux aspects :
dehbirac@yahoo.fr
Exemple fort classique
long fac (int n)
{
if (n>1) return (fac(n-1)*n) ;
else return(1) ;
}
chaque nouvel appel de fac, provoque une allocation mémoire pour les
paramètres, les variables locales et le retour, sans que les emplacements
précédents soient libérés.
Il y a donc un empilement des espaces alloués aux variables locales,
parallèlement à un empilement des appels de la fonction.
Ce n’est que lors de l’exécution de la première instruction return que l’on
commencera à « dépiler » les appels et les emplacements et donc à libérer de
l’espace mémoire.
dehbirac@yahoo.fr
dehbirac@yahoo.fr
La portée d’une variable globale - la
déclaration extern
A priori, la portée d’une variable globale semble limitée au fichier source
dans lequel elle a été définie.
source 1 source 2
int x ; fct2()
main() {
{ .....
..... }
} fct3()
fct1() {
{ .....
.....} }
int x ; fct2()
main() {extern int x ;
{ .....
..... }
} fct3()
fct1() {
{ .....
.....} }
dehbirac@yahoo.fr
Les variables globales cachées- la
déclaration static
Il est possible de « cacher » une variable globale: la rendre
inaccessible à l’extérieur du fichier source où elle a été définie (on
dit aussi « rendre confidentielle » au lieu de « cacher » ; on parle alors
de « variables globales confidentielles »).
Il suffit d’utiliser la déclaration static:
static int a ;
main()
{
.....
}
fct()
{
.....
}
dehbirac@yahoo.fr
Le cas des fonctions
• La fonction est considérée par le langage C comme
un objet global.
• C’est ce qui permet d’ailleurs à l’éditeur de liens
d’effectuer correctement son travail.
Note: il n’est pas nécessaire d’utiliser une
déclaration extern pour les fonctions définies dans
un fichier source différent de celui où elles sont
appelées (mais le faire ne constitue pas une erreur).
• En tant qu’objet global, la fonction peut voir sa
portée limitée au fichier source dans lequel
elle est définie à l’aide d’une déclaration static
comme dans : static int fct (...)
dehbirac@yahoo.fr
Synthèse
dehbirac@yahoo.fr
Le besoin d’interactivité
#include <stdio.h> int main(int argc, char *argv[]) {
#include <stdlib.h>
switch (menu())
{
int menu() case 1:
{ printf("Addition:\n");
int choix = 0; break;
while (choix <1 || choix > 5) case 2:
{ printf("Multiplication: \n");
printf("Menu :\n"); break;
printf("1 : Addition \n") ; case 3:
printf("2 : Multiplication \n"); printf("Soustraction: \n");
printf("3 : Soustraction \n"); break;
printf("4 : division \n"); case 4:
printf("5 : Quitter \n"); printf("Division: \n");
printf("Votre choix ? "); break;
scanf("%d", &choix); }
} return 0;
return choix; }
}
Atelier: Compléter le programme suivant en implémentant les
différentes fonctions possibles