Vous êtes sur la page 1sur 8

LES SOUS PROGRAMMES

1. Généralités

Lorsque la complexité d'un problème s'accroît, il devient nécessaire d'utiliser les sous-programmes
pour alléger la tâche. Ces sous-programmes sont les procédures et les fonctions. De façon générale
les sous programmes nous permettent:

 D'éviter de copier un segment de code plusieurs fois dans un même algorithme.


 De décomposer un grand problème en sous problème, chacun effectuant une tâche bien
précise. Les modules peuvent être écrits par plusieurs personnes de façon indépendante.
 De constituer une bibliothèque de sous-programmes

Les sous-programmes sont ainsi le moyen pour le programmeur de définir ses propres instructions et
opérateurs.

2. Définitions

 Le sous-programme est une suite d'instruction ordonnée (comme un algorithme) mais que la
machine n'exécute que lorsque c'est nécessaire
 La procédure est un sous-programme qui peut calculer et mettre à la disposition de
l'utilisateur zéro ou plusieurs valeurs, mais qui ne retourne explicitement aucun résultat.
 La fonction est un sous-programme qui calcule et met à la disposition de l'utilisateur une
valeur unique qu’elle retourne explicitement. La valeur calculée est mise à la disposition de
l'utilisateur par l'intermédiaire du nom de la fonction considéré comme une variable d'un
type donné: celui de la valeur calculée.

3. Structure de sous programmes

Un sous-programme a besoin de données pour travailler. Ces données sont appelées paramètres ou
arguments. Quand on écrit (déclare) un sous-programme et que l’on ne connait pas encore la valeur
des paramètres, ils sont dits paramètres formels. Lors de l’appel, quand on précise les valeurs, les
paramètres sont dits paramètres effectifs.

La spécification d’un sous-programme correspond à sa signature (son nom et ses paramètres


formels) et sa documentation explique ce que fait le sous-programme, les conditions d’applications,
son effet, etc. Il suffit de connaître la spécification d’un sous-programme pour être capable de
l’utiliser.

L’implémentation d’un sous-programme consiste en l’écriture des instructions qui permettent de


réaliser la spécification du sous-programme. Plusieurs implémentations sont généralement possible
pour une même spécification et l’utilisateur n’a pas à connaître l’implémentation choisie.
Procédure: nom (liste des paramètres)
déclaration
début
corps de la procédure
fin

Fonction: nom (liste des paramètres): type


déclaration
debut
corps de la fonction
nom_de_la_foncton←valeur_calculée
fin

Appeler un sous-programme, c’est fournir une valeur (le paramètre effectif) pour chacun des
paramètres formels du sous-programme. En général, c’est la position du paramètre effectif qui
permet de le rapprocher de son paramètre formel : le ième paramètre effectif permet d’initialiser le
ième paramètre formel.

4. Transmission de paramètres

Un sous-programme peut avoir trois types de paramètre:

 Les paramètres d'entrée qui fournissent les données au sous-programme. Ils sont transmis
par valeur.
 Les paramètres de sortie qui contiennent les résultats à la fin du déroulement du sous-
programme. Ils sont transmis par adresse.
 Les paramètres d'entrée-sortie qui jouent les deux rôles: Ils jouent le rôle de paramètre
d'entré et celui de paramètre de sortie. Ils sont transmis par adresse.

Les modes de transmission ne concernent pas les sous programmes sans paramètres. Lorsqu’un
sous-programme possède des paramètres, on associe :

- Uniquement des paramètres donnés aux fonctions


- Des paramètres donnés ou des paramètres résultats aux procédures

En algorithmique la déclaration d’un paramètre résultat est précédée du mot clé var.

Exemple

Function max(a,b,c : entier) : entier


Int max(int a; int b; int c)
M = max(x, y, z) simillaire en C et en algorithmique.

Procedure maxi(a,b,c : entier ; var rep : entier)


Void maxi(int a; int b; int c; int *rep)
maxi(x, y, z, M) en C, maxi(x, y, z, &M)
Les instructions d’un sous-programme travaillent sur des copies de paramètres transmis par valeur.
Les valeurs de ces paramètres sont donc identiques avant et après l’appel du sous-programme. Par
contre, les paramètres transmis par adresse sont explicitement manipulées par les instructions des
programmes. Leur valeur peut être modifiée par le sous-programme et donc la valeur finale d’une
variable après exécution peut-être différente de sa valeur initiale avant l’appel.

Un paramètre effectif transmis par valeur peut être soit une variable déjà initialisée soit une
constante. Un paramètre effectif transmis par adresse ne peut être qu’une variable.

5. Portée de variables

Une variable locale est une variable déclarée dans un sous-programme. Elle n’est accessible que
depuis ce sous-programme.

La portée d’une variable est la portion du programme où une instruction a le droit de référencer
cette variable.

En général, la portée d’une variable commence avec sa création (son initialisation) et se termine avec
la fin du sous-programme dans lequel elle a été créée. Dans le cas d’une variable créée en dehors de
tout sous-programme, sa portée couvre tous les sous-programmes que sa déclaration précède.

En C, on peut limiter la portée d’une variable à un bloc.

Une variable globale est une variable qui est potentiellement accessible à partir de plusieurs sous-
programmes. Une variable est donc dite globale si sa portée inclut plusieurs sous-programmes.

6. Application
- Programme de calcul du maximum de 3 nombres basé sur un sous-programme de calcul du
maximum de 2 nombres
- Programme qui permute 2 nombres
- Calcul du factoriel
- Affichage
- Recherche dans un vecteur
- Utilisation de structure

7. Récursivité
STRUCTURES DE DONNEES
1. Expression du besoin

Jusqu’à présent nous avons assimilé les concepts de base de l’algorithmique, notamment :

- La manipulation des données : variable, type, constante, les déclarations


- Le traitement des expressions
- La gestion des entrées/sorties : lecture et écriture
- Les traitements conditionnels
- Les traitements répétitifs

Nous souhaitons écrire des programmes qui traitent un nombre important de données, comme par
exemple ceux qui correspondent aux énoncés ci-dessous.

Exemple 1
Ecrire un programme qui lit une suite de nombre qui se termine par -1 puis qui calcule la somme des
termes de la suite.

Exemple 2
Ecrire un programme qui affiche les caractères d’une chaîne ch comprise entre les positions a et b.

Analyse des problèmes

Les deux exemples traitent des ensembles de données :

- La suite d’entiers dans l’exemple 1


- La chaîne de caractères dans l’exemple 2

Identification des ensembles

- La chaîne de caractères a un identifiant : ch


- La suite de nombre ne possède pas d’iditifiants

Accès aux éléments des collections

- Pour la suite, une même variable x a successivement pris les valeurs de chacun des termes de
la suite : x1, x2, …, xN.
- Pour la chaîne, l’accès au ième de ch s’est fait par l’expression ch[i]

Disponibilité des éléments de la collection après leur lecture

- Tous les éléments de ch sont disponibles après la lecture


- Aucun élément de la suite n’est disponible après la lecture

Le besoin
L’indisponibilité des éléments de la suite après la lecture est problématique. Deux solutions sont
envisageables pour assurer leur disponibilité :

- Déclarer autant de variables que nécessaire


- Trouver une solution similaire à celle de la chaîne de caractères.

La première solution est fastidieuse. Quel programmeur envisagerait-il la déclaration de milliers voire
de millions de variables pour stocker les éléments d’un ensemble ? Aucun, car il s’agirait là d’une
charge de travail très couteuse en temps et de plus non gratifiante pour le programmeur qui
passerait plusieurs jours de programmation uniquement à réaliser des déclarations ou à écrire une
expression impliquant toutes ces variables.

La solution appropriée est celle qui, à l’exemple du traitement de la chaîne de caractères, offre la
possibilité de donner un nom d’identificateur à une collection, d’assimiler la collection à une variable
et de stocker tous ses éléments en mémoire via cette variable à l’emplacement qui lui est réservé,
d’offrir un mécanisme d’accès à chacun de ses éléments via l’identificateur de l’ensemble.

Il s’agit là du concept de structure de données qui fait l’objet de chapitre.

2. Définitions

Une structure de données est un concept de l’algorithmique qui permet d’implémenter une
collection organisées de données comme une variable classique, de structurer leur organisation en
mémoire et d’offrir un mécanisme d’accès à chaque élément de la collection. Une structure de
données est donc perçue comme un type composé, créé à partir de type de bases.

Il existe deux organisations de base pour les ensembles de données : les tableaux et les
enregistrements. A partir de ces structures de base on peut concevoir des structures de données
évoluées comme les piles, les files, les arbres, les graphes, etc.

3. Les tableaux

Définition
Un tableau est un ensemble fini d’éléments de même type, stockés en mémoire à des adresses
contigües.

Déclaration
La déclaration d’un tableau à une dimension se fait de la façon suivante :
type nom-du-tableau[nombre-éléments];
où nombre-éléments est une expression constante entière positive. Par exemple, la déclaration
« int tab[10]; » indique que tab est un tableau de 10 éléments de type int. Cette déclaration alloue
donc en mémoire pour l’objet tab un espace de 10 × 4 octets consécutifs.
Pour plus de clarté, il est recommandé de donner un nom à la constante nombre-éléments par une
directive au préprocesseur, par exemple
#define nombre-éléments 10
Accès aux éléments du tableau
On accède à un élément du tableau en lui appliquant l’opérateur []. Les éléments d’un tableau sont
toujours numérotés de 0 à nombre-éléments -1. Le programme suivant imprime les éléments du
tableau tab :
#define N 10
main()
{
int tab[N];
int i;
...
for (i = 0; i < N; i++)
printf("tab[%d] = %d\n",i,tab[i]);
}

Opérations sur les tableaux


On n’effectue pas d’opérations globales sur un tableau. La manipulation d’un tableau se fait élément
par élément. Les éléments d’un tableau supportent toutes les opérations associées à leur type
d’appartenance.

Exercices
- Ecrire un programme qui lit puis affiche les éléments d’un tableau dans l’ordre inverse.
- Ecrire un programme qui détermine le plus grand élément d’un tableau.
- Ecrire un programme qui calcule la somme de 2 vecteurs de n éléments chacun.
- Ecrire un programme qui calcule le produit scalaire de deux vecteurs.
- Ecrire un programme qui calcule la somme de deux matrice.
- Ecrire un programme qui calcule le produit de deux matrices.
- Ecrire un programme qui calcule la transposée d’une matrice.
- Ecrire un programme qui calcule la trace d’une matrice.
- Ecrire un programme qui affiche un triangle de pascal d’ordre n.

Tableaux à plusieurs dimensions


De manière similaire, on peut déclarer un tableau à plusieurs dimensions. Par exemple, pour un
tableau à deux dimensions :
type nom-du-tableau[nombre-lignes][nombre-colonnes]
En fait, un tableau à deux dimensions est un tableau unidimensionnel dont chaque élément est lui-
même un tableau. On accède à un élément du tableau par l’expression “tableau[i][j]”.
Pour initialiser un tableau à plusieurs dimensions à la compilation, on utilise une liste dont chaque
élément est une liste de constantes :
#define M 2
#define N 3
int tab[M][N] = {{1, 2, 3}, {4, 5, 6}};
main() {
int i, j;
for (i = 0 ; i < M; i++)
{
for (j = 0; j < N; j++)
printf("tab[%d][%d]=%d\n",i,j,tab[i][j]);
}
}
4. Les enregistrements

Définition
Une structure est une suite finie d’objets de types différents. Contrairement aux tableaux, les
différents éléments d’une structure n’occupent pas nécessairement des zones contigües en
mémoire. Chaque élément de la structure, appelé membre ou champ, est désigné par un
identificateur.

Déclaration
On distingue la déclaration d’un modèle de structure de celle d’un objet de type structure
correspondant à un modèle donné. La déclaration d’un modèle de structure dont l’identificateur est
modele suit la syntaxe suivante :
struct modele
{
type-1 membre-1;
type-2 membre-2;
...
type-n membre-n;
};
Pour déclarer un objet de type structure correspondant au modèle précédent, on utilise la syntaxe :
struct modele objet;
ou bien, si le modèle n’a pas été déclaré au préalable :
struct modele
{
type-1 membre-1;
type-2 membre-2;
...
type-n membre-n;
} objet;

Opération d’accès
On accède aux différents membres d’une structure grâce à l’opérateur membre de structure, noté
“.”. Le i-ème membre de objet est désigné par l’expression
objet.membre-i
On peut effectuer sur le i-ème membre de la structure toutes les opérations valides sur des données
de type type-i. Par exemple, le programme suivant définit la structure complexe, composée de deux
champs de type double ; il calcule la norme d’un nombre complexe.
#include <math.h>
struct complexe
{
double reelle;
double imaginaire;
};
main()
{
struct complexe z;
double norme;
...
norme = sqrt(z.reelle * z.reelle + z.imaginaire * z.imaginaire);
printf("norme de (%f + i %f) = %f \n",z.reelle,z.imaginaire,norme);
}
}

Opérations sur les enregistrements


On peut effectuer une seule opération globale sur un enregistrement, l’affectation. La manipulation
d’un enregistrement se fait champ par champ. Les éléments d’un enregistreùment supportent toutes
les opérations associées à leur type d’appartenance.

Exercices
- Ecrire un programme qui lit deux dates puis affiche la durée qui les sépare : en année, en
mois, en jour.
- Ecrire un programme qui calcule le conjugué d’un nombre complexe.

Vous aimerez peut-être aussi