Prog Proc Chap 1
Prog Proc Chap 1
Prog Proc Chap 1
Introduction à la programmation
procédurale
1.1 Le paradigme
1
2 CHAPTER 1. INTRODUCTION À LA PROGRAMMATION PROCÉDURALE
suite_de_directives
/* Un ensemble de fonctions */
type_1 fonction_1(. . .)
{
..
.
}
..
.
type_n fonction_n(. . .)
{
..
.
}
/* Le programme principal */
int main()
{
..
.
return 0;
}
Programme 1: Structure globale d'un programme C.
Selon les préceptes de la programmation procédurale, un programme est une suite non
vide de procédures. Pour le langage C, on parle plutôt de fonction au lieu de procédure,
car chaque procédure C retourne une valeur, à la manière d'une fonction mathématique.
Un programme procédural contient, au moins, la fonction programme principal, dont le
prototype simplié est int main() dans le cas du langage C (voir Programme 1). Cette
dernière est une fonction qui peut être appelée sans paramètre et qui retourne un entier,
d'où l'instruction return 0; qui se trouve à la n de la fonction main() du Programme 1.
La valeur retournée par la fonction main() a pour rôle de faire savoir au système si une
erreur a été détectée. Par convention, une valeur nulle indique que le programme s'est
bien déroulé alors qu'une valeur non nulle indique une erreur.
La fonction main() est automatiquement appelée dès que le programme démarre et
lorsqu'elle termine, le programme termine aussi.
Par ailleurs, il est possible de paramétrer la fonction main(), car cette dernière admet,
en réalité, deux paramètres. Le prototype complet de la fonction main() est le suivant:
int main(int argc, char *argv[]);
où
• argc est le nombre de paramètres passés au programme, lors de son exécution, plus
1. Donc, ce nombre est toujours supérieur ou égal à 1 car le premier paramètre est,
automatiquement, le nom de l'exécutable.
1.3. LES DIRECTIVES 3
Figure 1.1: Programme C achant le nombre et les arguments reçus lors de son exécution.
Un programme C commence, le plus souvent, par une suite de directives (voir Pro-
gramme 1). Contrairement aux instructions, qui seront étudiées dans la Section 1.4,
les directives peuvent se trouver à l'extérieur de toute fonction. Les directives sont facile-
ment reconnaissables dans un programme C car elles commencent toujours par le symbole
#.
Les directives sont traitées par un sous-programme du compilateur C qui s'appelle
le préprocesseur. Ce dernier eectue des modications textuelles sur le chier source au
niveau des directives, justement. Ces modications consistent à remplacer, dans le code
source, des bouts de code apparaissant dans les directives par d'autres bouts de code,
(plus volumineux en général), qui se trouvent aussi dans les directives.
Parmi les directives les plus utilisées, on retrouve:
• #include qui permet l'inclusion de chiers entête ou source, notamment des biblio-
thèques contenant des fonctions prédénies par le langage, comme car exemple la
4 CHAPTER 1. INTRODUCTION À LA PROGRAMMATION PROCÉDURALE
L'entête d'une marco comporte le nom de la marco ainsi que ses paramètres, sans
précision de type. Le corps d'une macro est une expression. Par exemple, la directive
suivante dénit une macro qui retourne le cube d'un nombre:
#define Cube(x) ((x)*(x)*(x))
Comme il a été précisé plus haut, un programme procédural se compose d'un ensemble
non vide de procédures. Une procédure est, à son tour, composée de briques de base
appelées instructions. Ceci sous-entend que toute instruction du programme doit gurer
à l'intérieur d'une procédure. Une instruction peut être élémentaire ou composée. Dans ce
qui suit, nous présentons, tout d'abord, les instructions élémentaires puis les instructions
composées les plus courantes du langage C.
type liste_d'identicateurs ;
où la liste des identicateurs contient des identicateurs séparés par des virgules. Un
exemple de déclaration de variables se trouve à la Ligne 9 du programme de la Figure 1.2.
Une variable ne peut avoir que des valeurs ayant le type qui lui est aecté lors de sa
déclaration. C'est sur ce type que le compilateur du langage s'appuie pour vérier la
cohérence des opérations eectuées sur la variable en question.
Le langage C ore un ensemble de types de base qui sont résumés dans le Tableau 1.1.
Le moyen le plus simple permettant d'aecter une valeur à une variable est d'exécuter
une aectation. L'aectation est sans doute l'instruction élémentaire la plus utilisée lors
de l'écriture d'un programme procédural. Dans le fragment de Programme 2, les deux
variables ville et annee ont étés initialisées à la chaîne de caractère La Marsa et à la
valeur entière 1967, en utilisant deux aectations. Le symbole = est celui de l'aectation
en langage C. À gauche du =, on trouve toujours le nom d'une variable et à droite on
trouve une expression qui va donner sa valeur à la variable. La variable et l'expression
doivent être de même type ou, du moins, de types compatibles.
6 CHAPTER 1. INTRODUCTION À LA PROGRAMMATION PROCÉDURALE
..
.
// Déclaration d'une variable de type entier
int annee;
// Déclaration et initialisation d'une variable de type chaîne de caractères
char ville[64] = "La Marsa";
..
.
// Aectation de valeur aux deux variables déjà déclarées
annee = 1967;
ville = La Goulette // affectation incorrecte;
..
.
Programme 2: Déclaration et aectation de valeurs aux variables.
Règle 1. Avant d'utiliser une variable dans un calcul, il faut la déclarer et lui
aecter une valeur.
Par ailleurs, le langage C ore des aectations dites combinées. Il s'agit d'aectations
combinées avec des opérateurs binaires de l'arithmétique usuelle ou booléenne. La liste
de ces aectations combinées est la suivante: += -= *= /= %= &= |=. D'une manière
générale, une instruction de la forme: var op = expression ; est équivalente à
var = var op expression ;
Le langage C se distingue aussi par deux opérateurs à eet de bord2 . Ce sont les
opérateurs d'auto-incrémentation (++) et d'auto-décrémentation (--). Ces opérateurs
permettent d'ajouter ou de retrancher 1 au contenu d'une variable. Chacun de ces opéra-
teur peut être utilisée de manière préxée ou postxée. Ainsi, on peut écrire ++var ou
var ++ pour l'incrémentation et --var ou var -- pour la décrémentation. La diérent en-
tre la version préxé et la version postxée est très subtile et se résume dans la valeur
renvoyée par l'expression composée. Ainsi, la valeur renvoyée par ++var vaut var +1, alors
celle renvoyée par var ++ vaut var. La valeur renvoyée par une auto-décrémentation suit
la même logique.
2 Nous appelons eet de bord le fait de modier le contenu d'une variable.
8 CHAPTER 1. INTRODUCTION À LA PROGRAMMATION PROCÉDURALE
dont l'entête est dénie dans la bibliothèque standard du C stdio.h, qu'on doit inclure
avec la directive #include <stdio.h> . En tant que fonction, scanf() retourne un
entier, qui est non nul si la fonction s'est bien déroulée. La fonction scanf() permet la
lecture des valeurs tapées au clavier et, par la même, aecte ces valeurs aux variables dont
les adresses lui sont passées en paramètre (voir le programme de la Figure 1.2).
Le langage C ore deux autres fonctions de saisie de donnée, la première getchar() re-
tourne comme résultat un caractère saisi au clavier et la seconde, gets(chaine ), récupère
dans son paramètre une chaîne de caractère (voir le programme de la Figure 1.4).
An de communiquer ses résultat, une fois les calculs terminés, un programme C doit
avoir accès à un dispositif de sortie. Le moyen le plus simple pour acher des résultats
est d'utiliser la fonction:
printf("f ormats_d0 af f ichage",liste_d0 expressions)
Figure 1.4: Test de quelques fonctions d'entrée/sortie pour caractère et chaîne de carac-
tère.
structures dites de contrôle, qui modient l'ordre d'exécution linéaire. Pour ce faire, on
fait principalement recours aux structures de contrôle décrites dans les sous-paragraphes
suivants.
Le langage C ore les trois schéma conditionnels classiques, qui sont les schémas à
une, deux ou plusieurs alternatives. La syntaxe de ces schémas est montrée dans le
Programme 3.
L'instruction if : c'est le schéma conditionnel le plus simple, qui implique un seul
traitement dont l'exécution est contrôlé par une condition. Cette dernière est, le plus
souvent, une expression logique.
L'instruction if-else : ce schéma impliques deux traitements, dont un et un seule-
ment est exécuté selon la valeur logique de l'expression de contrôle.
L'instruction switch : Ce schéma, appelé aiguillage, est utilisé quand il y a plus que
deux traitements diérents à exécuter selon les valeurs constantes d'une expression dite
de contrôle. La syntaxe générale de l'aiguillage se trouve dans la colonne de droite du
Programme 3. Si aucune des constantes listées n'est égale à la valeur de l'expression de
contrôle alors un traitement par défaut est exécuté.
Exercice 1. Écrivez un programme C qui saisit trois nombres réels, supposés
correspondre aux longueurs des trois cotés d'un triangle, puis détermine si le triangle
en question est rectangle ou pas.
if (condition )
{ switch (expression )
bloc {
} case val _1 :
bloc _1
break;
if (condition ) case val _2 :
{ bloc _2
bloc_alors break;
} ..
.
else
case val _n :
{
bloc_sinon bloc _n
break;
}
default :
bloc_par_defaut
}
gramme 4.
La boucle for : cette boucle à une structure bien précisée. Le plus souvent, elle est
utilisée pour répéter un traitement qui dépend de la valeur d'un compteur. Le programme
de la Figure 1.6 montre un cas typique de l'utilisation de la boucle for.
Figure 1.6: Programme C pour le calcul de la suite de Fibonacci pour un nombre n donné.
1.4. LES INSTRUCTIONS 13
while (condition )
{
instructions_à_répéter
}
do
{
instructions_à_répéter
}
while (condition );
Programme 4: Les boucles du langage C.
Exercice 3.
Parmi les constituant d'un programme C, on peut trouver des expressions arithmétiques et
logiques. Ces dernières ne constituent pas des instructions à part entière, car une expres-
sion arithmétique ou logique ne constitue pas, à elle seule, une instruction du programme.
Cependant, le membre droit d'une aectation est, le plus souvent, une expression arith-
métique ou logique.
Une expression arithmétique bien formée peut contenir des constantes et/ou variables
numériques, (entières ou réelles), combinées à l'aide des opérateurs arithmétiques (voir le
premier point de la liste ci-après), avec éventuellement des parenthèses ouvrantes et fer-
mantes3 . Quelques exemple d'expression arithmétiques apparaissent dans le programme
de la Figure 1.2. La valeur d'une expression arithmétique bien formée est un nombre
(un entier ou un réel). Pour calculer correctement une telle valeur, on doit tenir compte
des priorité des opérateurs arithmétique qui y gurent. Rappelons que * et / sont plus
prioritaires que + et -. Si l'expression arithmétique désirée ne suit pas ces priorités, on
doit recourir à l'utilisation de parenthèses.
Pour les expressions logiques, on peut les obtenir à l'aide d'opérateurs de comparaison
(voir le deuxième point de la liste ci-après), plus les connecteurs logiques usuels (voir le
troisième point de la liste qui suit).
En plus des variables et constantes, les expressions arithmétiques peuvent faire inter-
venir des appels de fonctions mathématiques usuelles telles que les fonctions trigonométriques,
la racine carrée ou la fonction logarithme. Toutes ces fonctions sont disponibles dans la
bibliothèque standard math.h qu'on peut inclure avec la directive #include <math.h> .
Dans une expression arithmétique ou logique, on peut aussi trouver des appels de fonctions
dénies par le programmeur.
Un exemple d'une expression en langage C est la formule de Gauss:
1/(sig*sqrt(2*pi))*exp(pow(x-mu,2)/(2*sig*sig))
Nous terminons le paragraphe avec les expressions dites conditionnelles, qui sont spé-
ciques au langage C. Il s'agit d'expressions dont la forme générale est la suivante:
où expression _1 est interprétée comme une expression booléenne de sorte que si sa valeur
est non nulle alors la valeur de l'expression conditionnelle vaut expression _2, sinon elle
vaut expression _3.
Les expressions conditionnelles sont notamment utilisées lors de la dénition de macros
(voir Section 1.3). En voici un exemple dénissant une marco qui retourne le maximum
de deux nombres:
#define Max(a,b) (a > b ? a : b)
Dans les exemples qui ont précédés, dans un même calcul nous n'utilisions que des vari-
ables ou fonctions de même type ou, du moins, de types cohérents. Il arrive néanmoins
qu'il soit nécessaire de faire intervenir des types diérents dans un même calcul. On peut,
par exemple, trouver dans un même calcul, des nombres réels et des nombres entiers.
Deux cas de gure sont possibles:
• si le compilateur sait que la transmission d'une valeur d'un type à un autre peut
se faire sans perte d'information, (d'un entier vers un réel, par exemple), alors la
conversion aura lieu implicitement,
Néanmoins, une conversion ne modie pas la valeur d'origine mais en produit une
copie dont le type est changé (la variable d'origine garde bien évidemment sa valeur et
son type).
16 CHAPTER 1. INTRODUCTION À LA PROGRAMMATION PROCÉDURALE
..
.
y = (type _2) x; /* conversion du type _1 vers le type _2 */
Les données qu'on peut avoir à manipuler par un programme sont, parfois, composées d'un
grand nombre de données élémentaires similaires, en l'occurrence, de même type. C'est
le cas, par exemple, si on veut saisir et mémoriser les notes des étudiants d'une classe.
Pour représenter de telles données au niveau d'un programme, on a besoin d'un grand
nombre de variables de même type, des variables réelles, par exemple. Si on se limitait
aux variables simples utilisées dans le début du chapitre, on serait obligé de déclarer, dans
le programme, autant de variables que de notes à saisir. Ceci n'est pas pratique, car le
nombre d'étudiants d'une classe peut être assez grand et, surtout, peut varier d'une classe
à une autre. On serait donc obligé de modier le programme pour chaque classe!
Dans des cas pareils, la solution se trouve dans l'utilisation des tableaux. Ces derniers
sont des structures de données composées de plusieurs variables simples de même type.
L'accès à ces variables se fait à l'aide d'indices, qui sont des entiers dans le cas du lan-
gage C. Selon le besoin, ces tableaux peuvent être uni- ou multi-dimensionnels et on y
accédera en utilisant un ou plusieurs indices, selon la dimension (voir la Figure 1.8 qui
illustre un tableau uni-dimensionnel). Néanmoins, quelque soit sa dimension, les cases
d'un même tableau se trouveront lors de l'exécution dans des zones contiguës de la RAM
de l'ordinateur et c'est d'ailleurs cette particularité qui rend l'accès via des indices possible.
Pour pouvoir utiliser un tableau dans un programme C, il faut tout d'abord le déclarer,
comme toute autre variable (Règle 1). Cette déclaration se fait au début des fonctions
du programme, comme pour n'importe quelle variable. Il est aussi possible de déclarer
des tableaux globaux, et ceci à l'extérieur de toutes les fonctions, d'habitude juste après
la suite des directives du programme.
Lors de la déclaration d'un tableau, on doit préciser trois informations:
• le type de chaque élément du tableau.
Taille du tableau = 10
Figure 1.8: Un tableau uni-dimensionnel contenant 10 cases indexées par les entiers de 0
à 9.
n/p 0 1 2 3 4 5
0 1
1 1 1
2 1 2 1
3 1 3 3 1
4 1 4 6 4 1
5 1 5 10 10 5 1
Dans l'Exemple 1, il n'était pas nécessaire de faire recours à une structure de donnée
plus complexe qu'une suite linéaire d'éléments. Une fois cette suite stockée dans un
tableau, ce dernier permet un accès direct à n'importe quel élément de la suite, à l'aide
d'un indice unique.
Dans d'autres situations, la collection d'éléments de même type peut avoir une struc-
ture plus complexe. Elle peut, par exemple, être sous-forme d'un tableau bi-dimensionnel.
Une utilisation très fréquente des tableaux bi-dimensionnels a lieu avec la manipulation
des images numériques dites image à niveau de gris. Avec de telles images, chaque entrée
du tableau sert à mémoriser une valeur numérique, le plus souvent un entier comprit entre
0 et 255. l'accès à un tel tableau se fait donc, à l'aide de deux indices qui varient dans les
deux intervalles spéciés dans la déclaration du tableau. Ainsi, l'entrée (i, j) d'un tableau
tab bi-dimensionnel sera référencé par tab[i][j].
n−1
.
p−1
Exercice 5. Un mot v est une anagramme d'un mot w s'il existe une permutation
des lettres qui transforme v en w. Étant donné un ensemble de n mots de longueur
k , on veut écrire un programme C qui détermine toutes les classes d'anagrammes.
1.8 Conclusion