Vous êtes sur la page 1sur 117

Support de cours

Algorithmique et programmation
dans l'environnement C/Unix

Mamoun ALISSALI
Octobre 1998

Université du Maine  Le Mans


Sommaire
1 Introduction au système d'exploitation Unix 3
1.1 Débuter Unix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2 Environnement de l'utilisateur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.3 Introduction au C-Shell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.4 Notion de système de chiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.5 Fichiers texte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
1.6 La programmation en C-Shell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
1.7 Processus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
2 Le langage C 31
2.1 Le langage C en bref (Rappels) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
2.2 De l'applicatif à l'impératif : de CAML à C . . . . . . . . . . . . . . . . . . . . . . . . . 36
2.3 Structure de données en C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
2.4 Accès aux chiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
2.5 La compilation Séparée . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
3 Algorithmique et structures de données avancées 55
3.1 Fondements et principes de l'algorithmique . . . . . . . . . . . . . . . . . . . . . . . . . 55
3.2 Exemple : calcul de la somme des N premiers entiers positifs . . . . . . . . . . . . . . . . 55
3.3 Pratique du développement d'algorithmes . . . . . . . . . . . . . . . . . . . . . . . . . . 57
3.4 Notion de complexité d'algorithme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
3.5 Algorithmes de recherche dans un tableau . . . . . . . . . . . . . . . . . . . . . . . . . . 57
3.6 Algorithmes de tri de tableau . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
3.7 Types de données abstraits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
3.8 Listes Chaînées . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
3.9 Piles et queues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
3.10 Arbres binaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
4 Application: Base de Données Universitaire 79
4.1 Description du problème . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
4.2 Analyse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
4.3 Conception . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
4.4 Notions de module et de modularité . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
4.5 Première implantation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
4.6 Améliorations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
4.7 Implantation des améliorations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
4.8 Version 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94

1
2

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


Chapitre 1

Introduction au système d'exploitation


Unix
1.1 Débuter Unix
Le rôle premier d'un système d'exploitation est de présenter un ordinateur sous une forme abstraite
facilitant son utilisation et sa programmation. La gure 1.1 résume de manière simpliée les principales
abstractions mises en ÷uvre par Unix et leurs relations avec les couches basses (matériel et noyau) d'un
côté, et l'utilisatuer de l'autre côté.

1.1.1 La structure d'Unix


11111111111111
00000000000000
Statique Bibiliothèques 00000000000000
11111111111111
00000000000000
11111111111111
Matériel
Shell
libc.a 00000000000000
11111111111111
Identification 00000000000000
11111111111111
Noyau
00000000000000
11111111111111
stdio.h libm.a
nom de login math.h ... 00000000000000
11111111111111
mot de passe ... 00000000000000
11111111111111
00000000000000
11111111111111
Gestion de
Fichiers11111111111111
00000000000000
groupe
Données 00000000000000
11111111111111
Commandes
00000000000000
11111111111111
(fichiers) ls
00000000000000
11111111111111
00000000000000
11111111111111
Environnement

cd cat
00000000000000
11111111111111
Connecteurs
pwd cc
mkdir 00000000000000
11111111111111
de périph.
00000000000000
11111111111111
00000000000000
11111111111111
...
00000000000000
11111111111111
00000000000000
11111111111111
Mémoire
Gestion de11111111111111
00000000000000
00000000000000
11111111111111
00000000000000
11111111111111
Processus Processeur
Édition de prog. 00000000000000
11111111111111
00000000000000
11111111111111
(CPU)
Utilisation Compilation
00000000000000
11111111111111
00000000000000
11111111111111
Edition de liens
Exécution
00000000000000
11111111111111
00000000000000
11111111111111
Programmation
00000000000000
11111111111111
00000000000000
11111111111111
Dynamique 00000000000000
11111111111111

Fig. 1.1  Unix comme environnement d'utilisation et de programmation.

3
4 Chapitre 1 Introduction àUnix

1.1.2 Caractéristiques d'Unix


Créé en 1969 aux laboratoires Bell ; Unix a beaucoup évolué et a donné naissance à une grande
famille de systèmes d'exploitation (plus de 100 systèmes Unix ou Unix-like ). Beaucoup d'eorts ont
été faits récemment pour établir des normes, doter le système d'interface graphique, etc.
Un système d'exploitation appartient à la famille Unix si :
 il est multi-tâche, multi-utilisateur ;
 écrit en C ;
 possède un système de chiers hiérarchique ;
 intègre les E/S dans les opérations sur les chiers ;
 fournit une collection spécique d'appels système : fork, exec, pipe, etc. ;
 fournit des outils tels que : cc, awk, grep et troff ;
 permet le choix de l'interpréteur de commandes (shell).

1.2 Environnement de l'utilisateur


1.2.1 Le terminal
Un terminal est relié à l'ordinateur par une ligne de communication identiée par un chier péri-
phérique (device le ). C'est un chier spécial (cf. 1.4.2) qui se trouve dans le répertoire /dev et qui sert
à xer les règles de communication.
Sous un environnement graphique on peut avoir plusieurs fenêtres simulant chacune un terminal,
l'utilisateur est alors  connecté  à la machine autant de fois qu'il a de fenêtres.
La commande stty permet de consulter ou de modier les paramètres du terminal tels que la vitesse
de communication ou l'interprétation des caractères envoyés par le clavier :
stty [-a][-g][options du terminal]
sans paramètre stty ache les caractéristiques générales du terminal.
Options

 -a donne toutes les informations disponibles ;
 -g permet de générer un chier contenant les informations.

Exemple
1 (alissali@lola) ~>stty erase ^H

xe Ctrl-H comme caractère d'eacement.


1.2.2 Caractéristiques de l'utilisateur
Sous Unix un utilisateur est identié de manière unique par un numéro d'utilisateur . Il est aussi
caractérisé par son nom de login , son mot de passe , son répertoire personnel et son groupe . Ces informa-
tions et bien d'autres sont répertoriées dans le chier /etc/passwd. Elles sont accessibles par diérentes
commandes (cf. ci-dessous).
Chaque utilisateur appartient à un ou plusieurs groupes. Cela permet de classer les diérents uti-
lisateurs et introduit un niveau de sécurité supplémentaire concernant l'accès aux chiers. Le chier
/etc/group contient, pour chaque groupe, un numéro d'identication et la liste des utilisateurs qui en
sont membres. En cours de session il est possible pour un utilisateur de changer de groupe.
logname
Ache le nom d'utilisateur.
id [ -g | -u ] [ -nra ]

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


1.2 Environnement de l'utilisateur 5

Ache le nom de l'utilisateur, son numéro d'identication (UID : User IDentity ), ainsi que le numéro
du groupe actuel (GID : Group IDentity ) et la liste des groupes auxquels il appartient.
newgrp [-] [groupe]
Permet à un utilisateur de changer de groupe, à condition qu'il en fasse partie. Sans paramètre elle
replace l'utilisateur dans son groupe d'origine.
chown utilisateur fichiers

chgrp groupe fichiers


Ces deux commandes, CHange OWNer et CHange GRouP, permettent respectivement de changer
l'utilisateur ou le groupe propriétaire des chiers donnés en argument. Elles ne peuvent être utilisées
que par le propriétaire des chiers ou par l'administrateur (super user ).
Exemple
1 (alissali@lola) ~>logname
2 alissali
3 (alissali@lola) ~>id
4 uid=10017(alissali) gid=100(cuc) groups=100(cuc), 215(lium)
5 (alissali@lola) ~>newgrp lium
6 (alissali@lola) ~>id
7 uid=10017(alissali) gid=215(lium) groups=100(cuc), 215(lium)

1.2.3 Interpréteurs de commandes


Pour accéder aux services fournis par le système, les utilisateurs passent par un interpréteur de
commandes ou shell. Il s'agit d'un utilitaire interactif capable d'interpréter un langage de program-
mation spécique. Il opère comme suit :
1 boucle à l ' i n f i n ie
2 écrire in vit e
3 lire lig n e de commande
4 In t e r p r é t a t io n de la lig n e de commande :
5 In t e r p r é t a t io n des c a r a c t è r e s spéciaux ;
6 Extraction de la commande et , le cas échéant , des options et
7 des arguments ;
8 Exécution commande ( avec options et arguments )
9 fin boucle
Remarques
 L'invite (prompt) est un message (chaîne de caractères) qui indique que le shell est prêt à accepter
une nouvelle commande. L'invite peut être conguré pour indiquer diérentes informations telles
que le nom de la machine, le nom de login de l'utilisateur et le répertoire courant de travail.
 La ligne de commande se termine par un retour-à-la-ligne.
 Les caractères spéciaux (cf. 1.3.1) sont des caractères qui portent chacun un sens précis compris
par le shell.
 Une commande peut être interne (ou incorporée  built-in ), interprétée directement par le shell,
ou une commande Unix (programme exécutable).
 La commande incorporée exit termine l'exécution du shell.
Il existe une variété de shells, dont les plus connus sont : sh (Bourne Shell), jsh (Job Shell), csh (C-shell),
tcsh (Turbo C-shell), ksh (Corn Shell), bash (Bourne Again Shell).
Ces interpréteurs ont des caractéristiques communes. Ils orent tous :
 la même forme pour la ligne de commande :
commande options arguments

certaines commandes ne prennent pas d'arguments, d'autres pas d'options ;


 la possibilité d'exécuter des commandes en arrière plan ;
Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998
6 Chapitre 1 Introduction àUnix

 les redirections des Entrées/Sorties ;


 les tubes (cf. 1.5.3) qui permettent d'envoyer la sortie d'un processus (cf. 1.7) (programme en
cours d'exécution) vers un autre ;
 les caractères spéciaux.
Ils se diérencient par :
 la syntaxe et les capacités du langage qu'ils interprètent (structures de contrôle, dénition et
manipulation des variables, etc.) ;
 certaine caractères spéciaux et mises en ÷uvre comme celles de la redirection des E/S et les tubes ;
 certaines commandes internes (ou incorporées) ;
 certaines capacités d'interactions (plus ou moins évoluées) avec l'utilisateur.
Le paragraphe suivant donne quelques exemples sur sh (qui est le shell original d'Unix) et csh qu'on
étudiera par la suite.
Exemples
Bourne Shell (sh) :
 echo texte commande interne, ache texte sur l'écran ;
 times commande interne, ache le temps consommé par toutes les commandes exécutées par le
shell depuis son lancement ;
 who commande Unix, ache les utilisateurs actuellement connectés ;
 time ls -R commande Unix, exécute ls -R puis ache son temps d'exécution.
C-Shell (csh) :
 echo texte commande interne, équivalente à echo de sh ;
 alias lr 'ls -R' commande interne, dénit l'alias lr équivalent à ls -R ;
 time lr commande interne, équivalente à la commande Unix du même nom. Pour utiliser celle-ci
il faut donner son nom complet (chemin d'accès absolu) /bin/time.
 set monFichier = prog dénit la variable monFichier de valeur prog
 if (-e $monFichier) echo fichier existant évalue monFichier (prog après la commande
précédente) et ache le message si ce chier existe.

1.3 Introduction au C-Shell


1.3.1 Interprétation des commandes
Avant l'exécution d'une commande, csh interprète certains caractères dont les suivants 1 :
 séparateurs : espace, tabulation et retour-chariot (Enter)
1 ~>cd pub/ExemplesCours/
2 ~/pub/ExemplesCours>cd..
3 cd..: Command not found.
4 ~/pub/ExemplesCours>cd ..
5 ~/pub>

La commande en ligne 2 n'est pas comprise et provoque le message de la ligne 3. Ceci est dû à
l'absence du séparateur entre la commande cd et son argument ...
1. Pour un shell ou pour une commande, les termes entrée et sortie désignent les données, la plupart du temps stockées
dans des chiers, consommées et produites par une commande. Ils peuvent aussi désigner le clavier (entrée standard) et
l'écran (sortie standard) qui sont traités comme des chiers (cf. 1.4.2) par Unix.

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


1.3 Introduction au C-Shell 7

 $ : référence aux variables


1 ~/pub>set exemples = ~/pub/ExemplesCours
2 ~/pub>cd $exemples
3 ~/pub/ExemplesCours>

La première ligne dénit la variable exemples en lui attribuant une valeur, celle-ci est substituée
avant l'exécution de la commande. On remarque que le nouveau répertoire indiqué par l'invite
(ligne 3) correspond bien à la valeur de exemples.
 caractères spéciaux dans les noms de chiers :
? : désigne n'importe quel caractère

1 ~/pub/ExemplesCours>ls triBulTab.?
2 triBulTab.c triBulTab.h triBulTab.o

L'argument de la commande ls est interprété comme tous les chiers dont le nom est composé de
triBulTab. suivi de un (seul) caractère quelconque.
 * : désigne n'importe quelle séquence de caractères
1 ~/pub/ExemplesCours>ls *.c
2 affiche.c rechDichRec.c
3 explMdfParFct.c triBulPtr.c
4 rechDichIt.c triBulTab.c
5 ...
6 ~/pub/ExemplesCours>ls tri*.c
7 triBulPtr.c triBulTest.c
8 triBulTab.c triDirectRec.c
9 triDirectTest.c

L'argument de la commande ls en ligne 1 est iterprété comme tous les chiers dont le nom se
termine par .c. En ligne 6 on ajoute la contrainte : commence par tri.
 [...] : choix d'un caractères parmi ceux contenus entre les crochets
1 ~/pub/ExemplesCours>ls affiche.[hc]
2 affiche.c affiche.h

Ici on contraint le choix du caractère en n du nom à h ou c.


 redirection des entrées/sorties :
> : redirige la sortie vers un chier (au lieu de l'écran  sortie standard).
1 ~/pub/ExemplesCours>ls > liste
2 ~/pub/ExemplesCours>more liste
3 Makefile
4 affiche.c
5 affiche.h
6 affiche.o
7 [...]

La commande en ligne 1 redirige la sortie de ls vers le chier liste, rien n'est aché à l'écran. En-
suite la commande more ache les contenus de liste à l'écran, on remarque qu'ils correspondent
bien au résultat de ls.
 < : redirige l'entrée vers un chier (au lieu du clavier  entrée standard).
1 ~/pub/ExemplesCours>more < liste
2 Makefile
3 affiche.c
4 affiche.h
5 affiche.o
6 [...]

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


8 Chapitre 1 Introduction àUnix

Sans arguments la commande more attends une entrée au calvier, mais le caractère spécial < lui
indique que l'entrée vient du chier liste. Avec un fonctionnement totalement diérent, cette
commande est équivalente à celle de la ligne 2 de l'exemple précédent.
 j : tube, communique la sortie d'une commande à l'entrée d'une autre.
1 ~/pub/ExemplesCours>ls | more
2 Makefile
3 affiche.c
4 affiche.h
5 affiche.o
6 [...]
7 ~/pub/ExemplesCours>nl affiche.c
8 1 #include<stdio.h>
9 2 #include"affiche.h"
10
11 3 void affiche(int tab[], int taille)
12 4 {
13 [...]
14 8 } /* END affiche */
15 ~/pub/ExemplesCours>cat affiche.[hc] | nl | lp

La ligne 1 indique que la sortie de ls doit être acheminé vers la commande more au lieu d'être
aché à l'écran. C'est la commande more qui eectue l'achage 2. Ceci est équivalent aux deux
commandes (lignes 1 et 2) de l'exemple sur > ci-haut, mais sans l'utilisation d'un chier intermé-
diaire.
La commande nl (Number lines ), ligne 7, permet de numéroter les lignes d'un chier. En ligne
13 elle eectue cette opération sur les deux chiers affiche.c et affiche.h achés ensemble
à l'écran grâce à la commande cat. Ensuite, le deuxième tube envoie le résultat directement à
l'impression (commande lp).
 ; : séparateur de commandes
1 ~/pub/ExemplesCours>cd .. ; ls
2 BDU ExemplesCours

L'utilisation de ; permet d'enchaîner les commandes, ici au moment de l'exécution ls on se trouve


déjà dans le répertoire père (suite à l'exécution de cd).
 quotations (empêchent l'interprétation) :
\ : empêche l'interprétation du caractère suivant

1 ~/pub>echo un petit message > fichierMsg


2 ~/pub>more fichierMsg
3 un petit message
4 ~/pub>echo un petit message \backslash{}> fichierMsg
5 un petit message > fichierMsg

Dans le premier cas, ligne 1, le caractère > est interprété, ce qui a pour conséquence de diriger le
texte aché par echo dans le chier fichierMsg, ce qu'on vérie en lignes 2 et 3. Dans le deuxième
cas, le \ empêche l'interprétation de >, celui-ci est considéré comme un caractère normal, par
conséquent tout ce qui suit est aché à l'écran (ligne 5).
' ' : empêche l'interprétation de toute la séquence :

1 ~/pub>echo $exemples
2 /export/home/ens/cuc/alissali/pub/ExemplesCours
3 ~/pub>echo '$exemples'
4 $exemples

2. Ceci est utile lorsque la liste est trop longue pour être achée en une seule fois à l'écran; more eectue un achage
page par page.

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


1.3 Introduction au C-Shell 9

Avant d'exécuter la commande en ligne 1, exemples est remplacé par sa valeur d'où le résultat
en ligne 2. À la deuxième exécution on empêche la séquence $exemples d'être interprétée, elle est
donc achée telle que. On obtient le même résultat avec :
1 ~/pub>echo $exemples
2 $exemples

Ici on empêche l'interprétation du seul caractère $, exemples n'est donc plus interprétée comme
une variable et le tout est aché comme une chaîne de caractères ordinaire.
" " : empêche l'interprétation de la séquence sauf certains caractères (comme $)

 & : exécution en arrière plan .


1 ~/pub>emacs &
2 ~/pub>

Lorsqu'une commande est lancée à partir d'un shell, celui-ci attend la n de l'exécution de la com-
mande pour reprendre la main et permettre à l'utilisateur d'entrer d'autres commandes. L'exécu-
tion en arrière plan indique au shell de continuer à opérer  en parallèle avec la commande  ce qui
est particulièrement utile dans le cas des commandes interactives telles que emacs. On remarque,
ligne 2, que l'invite a été aché tout de suite sans attendre la n de l'exécution d'emacs.
1.3.2 Variables prédénies
Comme tous les shells, csh maintient un ensemble de variables prédénies qui dénissent le contexte
courant. Parmi ces variables, les plus utilisées sont :
Variable Valeur
cwd nom complet (chemin d'accès absolu) du répertoire courant .
home répertoire racine (ou personnel) de l'utilisateur ( le caractère  dans un nom de
chier prend la valeur de cette variable).
path liste des répertoires où seront cherchées les commandes.
prompt chaîne achée dans l'invite. Son absence indique qu'il
s'agit d'un shell non interactif.
shell nom du chier exécutable du programme csh.
status état de l'exécution de la dernière commande. Pour un programme C
prend la valeur retournée par main.
user nom de l'utilisateur.

Tab. 1.1  Variables internes (prédénies) du C-Shell.

Exemples
Sur la machine lola le shell par défaut est tcsh, pour travailler en csh il faut lancer l'interpréteur :
1 (alissali@lola) ~>csh
2 (alissali@%m %~)

On remarque le changement d'invite car les séquences qui commencent par % dans prompt sont spéciques
à tcsh : %m et %, interprétée par tcsh comme  le nom de la machine  et  le répertoire courant ,
sont incomprises de csh. Par conséquent, elle sont achées telles que. Il faut alors modier l'invite à
l'aide de l'aectation (commande interne set) :
1 (alissali@%m) %~>set
2 cwd /export/home/ens/cuc/alissali
3 home /export/home/ens/cuc/alissali
4 path (/usr/bin /usr/local/bin .)
5 prompt (alissali@%m) %~>
6 shell /bin/csh

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


10 Chapitre 1 Introduction àUnix

7 status 0
8 user alissali
9 ...
10 (alissali@%m) %~>set prompt='cmd. no. ! > '
11 cmd. no. 3 >

La première utilisation de set (sans argument) permet de consulter les variables actuellement dénies,
en particulier l'invite (prompt). La deuxième utilisation donne une nouvelle valeur à cette variable, le
caractère ! dans l'invite est interprété par csh comme étant le numéro de la commande courante, comme
on le voit en ligne 11.
On eectue quelques opérations pour observer le fonctionnement et l'utilisation de ces variables. Un
changement du répertoire courant modie la valeur de cwd :
1 cmd. no. 3 > cd pub
2 cmd. no. 4 > set
3 [...]
4 cwd /export/home/ens/cuc/alissali/pub
5 [...]

Pour exécuter une commande, csh se réfère à la valeur de path pour savoir dans quels répertoire chercher
l'exécutable correspondant. L'utilisateur peut obtenir la même information grâce à la commande which :
1 cmd. no. 5 > which ls
2 /usr/bin/ls

ce qui veut dire que l'exécutable ls se trouve dans le répertoire /usr/bin, celui-ci fait bien partie de
la valeur de path (cf. 1er exemple ci-dessus). Si on supprime ce répertoire de la valeur de path, csh ne
trouve plus la commande (message d'erreur ligne 3) :
1 cmd. no. 6 > set path='(/usr/local/bin .)'
2 cmd. no. 7 > ls
3 ls: Command not found.

De plus la valeur de status est mise à jour pour indiquer une erreur (la valeur est 0 en cas de bon
déroulement) :
1 cmd. no. 8 > echo $status
2 1

On termine l'exécution de csh, on retrouve tcsh et son invite :


1 cmd. no. 9 > exit
2 cmd. no. 10 > (alissali@lola) ~>

1.3.3 Variables d'environnement


Une variable d'environnement est une chaîne de caractères composée d'un nom et d'une valeur.
Les variables d'environnement servent à communiquer le contexte d'exécution actuel à toute commande
exécutée par le shell.
Quelques variables d'environnement sont prédénies, les plus importantes sont USER, HOME et PATH
qui prennent les mêmes valeurs que leurs homonymes parmi les variables internes. PWD a la même valeur
que la variable interne cwd.
La command interne setenv permet d'aecter ou de consulter la valeur d'une variable d'environne-
ment.
Pour illustrer la diérence entre une variable interne et une variable d'environnement, l'exemple
suivant dénit une variable de chaque type (respectivement maVar et MAVAR) 3, puis lance un nouveau
csh. Seule la variable d'environnement est exportée vers (reconnue par) ce nouveau shell 4.

1 (alissali@lola) ~>csh
2 (alissali@%m) %~>set prompt='csh: ! >'

3. Les variables d'environnement sont toujours en majuscules, les variables internes en minuscules. Il s'agit d'une
convention et non pas d'une règle lexicale.
4. L'exemple ne montre que les variables qui servent notre propos.

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


1.4 Notion de système de chiers 11

3 csh: 2 >set maVar = 'une variable interne'


4 csh: 3 >set
5 maVar une variable interne
6 [...]
7 prompt csh: ! >
8 csh: 4 >setenv MAVAR ``UNE VAR. D'ENV.
9 csh: 5 >setenv
10 HOME=/export/home/ens/cuc/alissali
11 PATH=/usr/bin:/usr/local/bin:.
12 USER=alissali
13 MAVAR=UNE VAR. D'ENV.
14 [...]
15 csh: 6 >csh
16 (alissali@%m) %~>set
17 prompt (alissali@%m) %~>
18 [...]
19 (alissali@%m) %~>setenv
20 HOME=/export/home/ens/cuc/alissali
21 PATH=/usr/bin:/usr/local/bin:.
22 USER=alissali
23 MAVAR=UNE VAR. D'ENV.
24 [...]

La première ligne lance un csh, la deuxième modie l'invite. Ensuite on dénit en l'initialisant une nou-
velle variable (maVar, ligne 3), et on vérie le bon déroulement de l'opération (lignes 4 et 5), ainsi que la
nouvelle valeur de prompt (ligne 7). On répète les mêmes opérations avec une variable d'environnement,
MAVAR, en observant les valeurs de quelques autres variables d'environnement (lignes 8 à 13).
Lorsqu'on lance un nouveau csh, on observe que prompt retrouve son ancienne valeur et que maVar
n'est pas dénie : les variables internes ne sont pas communiquées au nouveau processus. Par contre les
variables d'environnement, y compris MAVAR, sont bien reconnues par le nouveau shell.
1.3.4 Conguration du C-Shell
Au lancement d'un interpréteur de commande celui-ci exécute les commandes qui se trouvent dans
un chier de conguration . Dans le cas du C-Shell ce chier s'appelle .cshrc et se trouve (comme pour
les autres interpréteurs) dans le répertoire de l'utilisateur (HOME). Il peut contenir des modications de
variables ou de variables d'environnement prédénies, des dénitions de variables et d'autres commandes
comme la dénition d'alias.
Exemple
1 csh: 10 >more .cshrc
2 set path=(/usr/bin /usr/local/bin .)
3 set prompt="csh: ! >"
4 alias rm 'rm -i'
5 alias dir 'ls -aF'
6 alias x logout

La première ligne ache les contenus de .cshrc , où on trouve l'initialisation des variables path et
prompt et la dénition de quelques alias.

1.4 Notion de système de chiers


Un système de chiers décrit l'ensemble de des données stockées sur un support permanent de
stockage (disque, CD-ROM, etc.). Il est composé des données proprement dites, organisées en chiers
et en répertoires, et de diverses informations de gestion.
1.4.1 La table des i-nodes
La table des i-nodes fait partie des informations de gestions d'un système de chiers. Chaque élément
(i-node ou index node) de la table décrit entièrement un chier et chaque chier est identié de manière
Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998
12 Chapitre 1 Introduction àUnix

unique par l'indice (i-node number ) de son entrée.


Chaque i-node contient les informations suivantes :
 type de chier et permissions d'accès ;
 identication du propriétaire et de son groupe ;
 nombre de liens sur le chier ;
 taille du chier en octets (bytes ) ;
 dates du dernier accès, dernière modication, dernière modication de l'i-node ;
 tableau de pointeurs sur les blocs de données.
Mise à part la dernière (le tableau de pointeurs) ces informations peuvent être visualisées par la
commande ls (cf. 1.4.4) par exemple.
1.4.2 Fichiers et types de chiers
La notion de chier sous Unix regroupe :
 les chiers normaux : un chier normal (texte, données, objet, exécutable, etc.) est une séquence
d'octets sans aucune organisation interne spécique ;
 les répertoires : un répertoire est un chier spécial dans lequel sont inscrits les liens du répertoire.
un lien est constitué de l'association entre un nom et un numéro d'i-node ;
 les tubes : un tube est un chier spécial permettant de communiquer la sortie d'un programme
(ou commande) à l'entrée d'un autre programme (appelé dans ce cas précis ltre (cf. 1.5.3).
 les chiers spéciaux qui désignent les périphériques (écran, clavier, etc.) ;
Cette organisation permet de généraliser l'uitilisation des commandes, des appels système et des
fonctions prédénies, spéciques aux chiers normaux, aux autres types de chiers. Par exemple la
fonction fprintf de la bibliothèque standard C peut être utilisée pour acher sur l'écran ou écrire dans
un chier.
1.4.3 Commandes de manipulation de chiers
Une commande de manipulation de chier porte sur le chier (dans le sens large du terme) lui-même
ou sur ses contenus. Une même commande peut opérer des deux façons selon son contexte d'utilisation.
Par exemple la commande ls (cf. 1.4.4) lorsqu'elle est appliquée à un répertoire ache des information
sur le répertoire lui-même (option -d) ou sur ses contenus (défaut).
Unix fournit un nombre très important de commandes et d'utilitaires. Le meilleur moyen pour
les découvrir est de récupérer des script s (programmes shell (cf. 1.6)), et la meilleure référence est la
documentation en ligne (commande man). Le tableau 1.2 donne un bref aperçu de quelques commandes
parmi les plus utilisées et pouvant servir de références lorsqu'on cherche à accomplir une opération
donnée 5.
Après quelques exemples, nous détaillerons les commandes ls (cf. 1.4.4) et chmod (cf. 1.4.4). À titre
d'exemple de commandes relativement complexes, on décrit les deux commandes find (cf. 1.4.5) et tar
(cf. 1.4.6). Puis, après avoir présenté les expressions régulières, nous étudierons la commande egrep
(cf. 1.5.2) à titre d'exemple des commandes spéciques aux chiers texte.
Exemples
1 ~/pub>ls
2 BDU ExemplesCours
3 ~/pub>ls -ilR
4 total 8
5 667524 drwxr-xr-x 2 alissali cuc 1024 Dec 11 15:51 BDU
6 667315 drwxr-xr-x 2 alissali cuc 1536 Dec 11 15:36 ExemplesCours
7 ./BDU:
8 total 74

5. La rubrique See also de la documentation en ligne sert d'index croisé permettant de trouver de nouvelles commandes
à partir de celles que l'on connait.

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


1.4 Notion de système de chiers 13

Commande Description
Options
Commandes pour tout type de chier (chiers normaux, répertoires, etc.)
ls [chier] (LiSt) Acher des inforamtions sur le chier ou sur ses contenus.
chmod mode chier (CHange MODe) Changer le mode d'accès (les protections) du chier.
find répertoire critères Rechercher, selon les critères, des chiers à partir du répertoire spécié.
tar opérations archive Eectuer les opérations spéciées (création, consultation, extraction) sur archive.
ln source destination (LiNk) Créer un lien (nom) pour un chier existant.
rm nom (ReMove) Supprimer un lien,
-r (Récursif) supprimer un répertoire et tous ses contenus.
mv source destination (MoVe) Déplacer ou change le nom d'un chier/répertoire.
cp source destination (CoPy) Faire une copie destination de source,
-r (Récursif) Copier tout une arborescence (un répertoire).
Commandes spéciques aux répertoires
pwd (Print Working Directory) Acher le répertoire courant.
cd nom (Change Directory) Changer de répertoire courant.
[sans argument] le répetoire courant devient HOME (répertoire racine de l'utilisateur).
mkdir nom (MaKe DIRectory) Créer un répertoire.
rmdir nom (ReMove DIRectory) Supprimer un répertoire, il doit être vide.
Commandes spéciques aux chiers
cat nom (CATenate) Acher le contenu d'un chier (clavier  entrée standard  par défaut).
more nom Acher le contenu page par page.
wc (Word Count) Compter les caractères, les mots et les lignes.
cmp Acher les numéros de ligne et d'octet où 2 chiers dièrent.
comm Sélectionner ou rejetter les lignes communes à deux chiers.
diff Acher ligne par ligne les diérences entre deux chiers.
sort Trier par ligne un ou plusieurs chiers (avec fusion dans ce dernier cas).
-u (Unique) Supprimer les duplications.
cut Sélectionner des champs dans les lignes d'un chier.
paste Concaténer les lignes de deux chiers.

Tab. 1.2  Quelques commandes de manipulation de chiers sous Unix .

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


14 Chapitre 1 Introduction àUnix

9 3532166 -rw-r--r-- 1 alissali cuc 804 Dec 11 15:49 00LISEZ.MOI


10 1066443 -rw-r--r-- 1 alissali cuc 2370 Dec 11 15:51 Makefile
11 2265946 -rw-r--r-- 1 alissali cuc 1092 Dec 10 18:01 dates.c
12 [...]
13 ./ExemplesCours:
14 total 269
15 1999384 -rw-r--r-- 1 alissali cuc 1668 Nov 25 14:33 Makefile
16 1399970 -rw-rw-rw- 1 alissali cuc 177 Nov 25 14:12 affiche.c
17 1999392 -rwxr-xr-x 1 alissali cuc 14528 Nov 25 14:12 rechDichTest
18 [...]
19 ~/pub>ls ExemplesCours/*.c
20 ExemplesCours/affiche.c ExemplesCours/saisieInverse.c
21 ExemplesCours/explMdfParFct.c ExemplesCours/saisieInverse_test.c
22 [...]

1.4.4 La commande ls
Cette commande permet d'acher des informations sur les chiers et les répertoires en se référant à
la table des i-nodes lorsque nécessaire :
ls [-RadLCxmlnogrtucpFbqisf1%] arg1...argn
argi : liste optionnelle de noms de chiers et de répertoires. Pour chaque répertoire argi ache la
liste des chiers qu'il contient. Pour chaque chier argj ache des informations sur le chier. Sans
argument : ache la liste des chiers du répertoire courant.
Les informations achées et leur format dépendent des options.
Quelques options
 si aucune option n'est présente ache uniquement les noms ;
 -l : liste longue, ache la plupart des informations du i-node ;
 -i : achage des noms et des numéros d'i-nodes correspondants ;
 -R : achage récursif (exploration des sous-répertoires).
La liste longue a la forme suivante :
-rw-rr 1 alissali cuc 804 Dec 11 15:49 00LISEZ.MOI

Le premier champ décrit le type du chier ( `-': chier normal, `d' répertoire, etc.) et les droits
d'accès (r : lecture, w : écriture, x : exécution) pour, successivement, le propriétaire, son groupe et les
autres utilisateurs.
Le deuxième champ ache le nombre de liens du chier. Dans le troisième et le quatrième champs
on trouve respectivement le nom du propriétaire du chier et celui de son groupe.
Les champs suivants décrivent respectivement la taille (en octets), la date et l'heure de la dernière
modication et le nom du chier.
La commande chmod
chmod [ugoa ]{ + j - j = }[ rwxlsStTugo] rg1 arg2 ... argn
Permet de modier lemode ou droits d'accès (les protections) pour le(s) chier(s) spécié(s).
Exemples
1 ~/pub/ExemplesCours>ls -l rechDichTest
2 -rwxr-xr-x 1 alissali cuc 14528 Nov 25 14:12 rechDichTest
3 ~/pub/ExemplesCours>chmod u-x rechDichTest
4 ~/pub/ExemplesCours>ls -l rechDichTest
5 -rw-r-xr-x 1 alissali cuc 14528 Nov 25 14:12 rechDichTest
6 ~/pub/ExemplesCours>rechDichTest
7 rechDichTest: Command not found.
8 ~/pub/ExemplesCours>./rechDichTest

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


1.4 Notion de système de chiers 15

9 ./rechDichTest: Permission denied.


10 ~/pub/ExemplesCours>chmod g+w rechDichTest
11 ~/pub/ExemplesCours>ls -l rechDichTest
12 -rw-rwxr-x 1 alissali cuc 14528 Nov 25 14:12 rechDichTest
13 ~/pub/ExemplesCours>chmod u-w rechDichTest
14 ~/pub/ExemplesCours>rm rechDichTest

La dernière opération, ligne 14, se déroule normalement malgré la protection en écriture du chier. En
eet celle-ci n'empêche pas la suppression d'un chier car il s'agit d'une modication sur le répertoire.
Si on protège le répertoire en écriture la suppression n'est plus possible :
1 ~/pub/ExemplesCours>ls rechDichTest
2 UX:ls: ERROR: Cannot access rechDichTest: No such file or directory
3 ~/pub/ExemplesCours>chmod u-w .
4 ~/pub/ExemplesCours>rm rechDichTest.o
5 UX:rm: ERROR: rechDichTest.o not removed: Permission denied.

1.4.5 La commande find


find liste-chemins-d-acces expBool

Pour chaque chemin d'accès dans liste-chemins-d-acces, rechercher les chiers qui vérient l'expres-
sion booléenne expBool. Cette expression est construite de primitives prédénies (cf. man page) reliées
par les opérateurs logiques de base (la juxtaposition joue le rôle du et logique, le `!' celui de la négation
et (-o) celui du ou logique).

Exemple
1 find $HOME \backslash{}( -name a.out -o -name '*.o' \backslash{}) -atime +7 -exec rm {} \backslash{};

Recherche à partir du répertoire racine personnel ($HOME) tous les chiers dont le nom est a.out ou
*.o (tous les chiers objets), et les supprime s'ils n'ont pas été utilisés depuis plus de 7 jours. On note
que les caractères susceptibles d'être interprétés par le shell (les parenthèses, `*' et `;') sont protégés
(précédé par le caractère spécial (cf. 1.2.3) \ ce qui empêche leur interprétation .

1.4.6 La commande tar


tar clef options fichierArchive

tar (Tape ARchiver ) permet de manipuler des archives de chiers. À l'origine il a été conçu pour
l'archivage sur bande magnétique. Aujourd'hui il sert particulièrement pour les transferts sur réseau.
clef détermine la fonction exécutée par tar, les plus utilisées sont : c (Créer), t (acher la lisTe) et x
(eXtraire).

Exemple
Pour créer une archive qui contient les sources (.c et .h) du répertoire courant :
1 tar cvf archive *.c *.h

Après un éventuel transfert, les deux commandes suivantes permettent respectivement de visualiser la
liste de contenus et d'extraire les chiers de l'archive :
1 tar tvf archive
2 tar xvf archive

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


16 Chapitre 1 Introduction àUnix

1.5 Fichiers texte


Un chier texte est un chier de caractères découpé en lignes. Une ligne est une suite de caractères
terminée par le caractère \n (retour chariot). Par exemple tout programme source en langage C (.c)
est un chier texte. Par contre les chiers produits par le compilateur (comme les .o) ou par l'éditeur
de lien (tel que a.out) ne sont pas des chiers texte.
Grâce à cette distinction, les chiers texte supportent des traitements spéciques. Par exemple la
plupart des commandes spéciques aux chiers dans le tableau 1.2 ne s'appliquent qu'à ce type de
chiers.
1.5.1 Les Expressions Régulières
Une expression régulière (ER) spécie un ensemble de chaînes de caractères. On dit d'un élément
décrit par une expression régulière qu'il est désigné ou mis en correspondance (matched ) par l'ER.
Dans une expression régulière certains caractères ont un sens spécial, les autres désignent le caractère
lui-même.
Expressions régulières à un seul caractère
Les ER suivantes désignent un seul caractère :
 Un caractère normal (par contraste aux caractères spéciaux discutés ci-après) est une ER à un
seul caractère qui désigne le caractère lui-même.
 Un backslash (\) suivi par un caractère spécial est une ER d'un seul caractère qui désigne le
caractère spécial lui-même. Les caractères spéciaux sont :
 ., *, [, et \ sont toujours spéciaux sauf quand ils appartiennent à un ensemble (c.à.d. quand
ils paraissent entre crochets ([]), voir ci-après)
 ^ (accent circonexe), qui a un sens spécique en début d'ER (voir ci-dessous), ou quand il
suit immédiatement le crochet gauche d'une paire de crochets ([]) (voir ci-dessous).
 $ est spécial en n d'ER (voir ci-dessous).
 Le caractère utilisé pour délimiter une ER entière est spécial pour cette ER. Par exemple
`/' est un caractère spécial lorsque est utilisé pour délimiter des ER dans les commandes de
substitution de texte sous ed et sed.
 un point `.' est une ER à un seul caractère qui désigne n'importe quel caractère sauf nouvelle-ligne
(ou retour-chariot ).
 Une chaîne de caractères non vide incluse entre crochets est une ER à un seul caractère qui désigne
un seul élément de la chaîne considérée comme un ensemble. De plus :
 Le symbole `^' en début de chaîne désigne le complément de l'ensemble des caractères du
reste de la chaîne : le caractère désigné est n'importe quel caractère (hormis nouvelle-ligne )
n'appartenant pas à la chaîne.
 Le signe moins `-' peut être utilisé pour désigner un intervalle de valeurs ; par exemple [0-9]
est équivalent à [0123456789].
 Pour inclure un des deux caractères `-' ou (]) dans l'ensemble, ce caractère doit être le premier
de la chaîne (après un éventuel `^'). `-' peut aussi être le dernier caractère de la chaîne.
Construction d'expressions régulières
Les règles suivantes expliquent comment construire des ERs à partir d'ERs à un seul caractère :
 Une ER à un seul caractère désigne ce que désigne le caractère.
 Une ER à un seul caractère suivie d'un asterisk `*' est une expression régulière qui désigne 0 ou
plus occurrence de l'ER. En cas d'ambiguïté c'est la chaîne la plus longue qui sera prise en compte.
 Une ER à un seul caractère suivie de \{m\}, (resp. \{m,\}, resp. \{m,n\}) est une expression
régulière qui désigne m (resp. m ou plus, resp. m à n) occurrences de l'ER à un seul caractère. m et
n doivent être compris entre 0 et 256. En cas d'ambiguïté c'est la chaîne la plus longue qui sera
prise en compte.
Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998
1.5 Fichiers texte 17

 La concaténation de deux ERs désigne les chaînes constituées de la concaténation des chaînes
désignées par les deux ERs.
 Une ER peut être entourée de \( et \) ; les chaînes désignées restent les mêmes.
 L'expression \n désigne la même chaîne de caractères que celle incluse entre la ne paire de \( et
\) à compter de la gauche. Par exemple ^\(.*\)\1$ désigne une ligne entière composée de deux
occurrences d'une même chaîne.
Contraindre les ER
Une ER peut être contrainte à désigner des mots :
 \< contraint une ER à désigner un début de chaîne (constituée de lettres, chires et sous-tirets).
 \> contraint une ER à désigner une n de chaîne.
Une ER peut être contrainte à désigner un segment initial et/ou un segment nal d'une ligne :
 Un accent circonexe `^' en début d'ER la contraint à désigner un segment initial d'une ligne.
 Un `$' en n d'ER la contraint à désigner un segment nal d'une ligne.
 La construction ^ER$ contraint l'ER à désigner une ligne entière.
L'ER nulle (par exemple //) est équivalente à la dernière expression régulière rencontrée.
1.5.2 La commande egrep
egrep [-bchilnsv] [patron] [fichier...]
egrep ache à l'écran toutes les lignes de fichier qui contiennent une chaîne désignée par patron.
Cette commande accepte les expressions régulières à l'exception de \( et \), et avec les ajouts suivants :
 Une ER suivie de + désigne une ou plus occurrence de l'ER.
 Une ER régulière suivie de ? désigne 0 ou 1 occurrence de l'ER.
 La barre verticale | et nouvelle-ligne jouent le rôle de ou entre deux ERs.
 Les parenthèses peuvent être utilisées pour grouper.
Il faut faire attention aux caractères qui ont un sens particulier pour les shells, en particulier : $, *,
[, , |, (, ) et \ . Il vaut mieux entourer toute l'ER par des apostrophes '...' pour éviter toute
interprétation par le shell.
L'ordre de précédence des opérateurs est le suivant : [], * ? +, la concaténation puis le ou.
Selon l'implantation egrep accepte des simplication d'écriture en dénissant des classes de carac-
tères . Par exemple [:alnum:] désigne la classe de tout les caractères alpha-numériques.
Exemples
Extraction des directives du préprocesseur (distinguée par #) :
1 Cmd 1 >egrep '#' etudiant.c
2 #include<stdio.h>
3 #include"etudiant.h" /* inclut personne.h */

Extraction des commentaires, premier essai :


1 Cmd 2 >egrep '\*' etudiant.c
2 /* Fichier : etudiant.c
3 * Description : module de traitement d'un enregistrement typeEtudiant.
4 ...
5 */
6 #include"etudiant.h" /* inclut personne.h */
7 /**************
8 * afficheEtudiant : affichage d'un ernregistrement de typeEtudiant.
9 ...

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


18 Chapitre 1 Introduction àUnix

10 */
11 saisiePersonne (&((*ptrEt).pers));
12 scanf("%d", &((*ptrEt).id));

ce n'est pas susant car certaines lignes contiennent des `*' sans être des commentaires.
Extraction des dates (n'importe quel chire) :
1 Cmd 3 >egrep '[0-9]' etudiant.c
2 * Historique : 10.12.96 : réalisation, test OK.

Extraction des commentaires, deuxième essai :


1 Cmd 4 >egrep '/\*' etudiant.c
2 /* Fichier : etudiant.c
3 #include"etudiant.h" /* inclut personne.h */
4 /**************
5 /**************

Toutes les lignes de commentaire n'ont pas la séquence  /*. Un meilleur résultat est obtenu si on
désigne (espace) ou / avant l'astérisk :
1 Cmd 5 >egrep '[ /]\*' etudiant.c
2 /* Fichier : etudiant.c
3 * Description : module de traitement d'un enregistrement typeEtudiant.
4 ...
5 */
6 #include"etudiant.h" /* inclut personne.h */
7 ...

Extraction des dates, la version suivante (une date est une succession de chires et de `.') :
1 Cmd 6 >egrep '[0-9.]*' etudiant.c

est inadéquate car elle comprend zéro répétition : toutes les lignes seront sélectionnées. Il faut donc forcer
une occurence au moins :
1 Cmd 7 >egrep '[0-9.][0-9.]*' etudiant.c

ou sa simplication (autorisée par egrep) :


1 Cmd 8 >egrep '[0-9.]+' etudiant.c

sélectionne toutes les lignes avec au moins un `.' ou un chire, y compris celle qui contiennent des
chaînes comme  .5 ou  3.14195.
Pour éviter une telle confusion, le cas échéant, la description, plus complexe et plus complète, doit
désigner clairement la forme exacte d'une date ; trois suites de 2 chires séparées par des `.' :
1 Cmd 9 >egrep '[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]' etudiant.c

Pour extraire les lignes de description (qui commencent par  /* ou  *) :
1 Cmd 10 >egrep '^[ /]\*' etudiant.c
2 /* Fichier : etudiant.c
3 * Description : module de traitement d'un enregistrement typeEtudiant.
4 ...
5 */

et pour extraire les lignes qui se terminent par un commentaire (éventuellement suivi d'espaces) :
1 Cmd 11 >egrep '\*/ *$' etudiant.c
2 */
3 #include"etudiant.h" /* inclut personne.h */
4 ...

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


1.5 Fichiers texte 19

Si on ne désire pas les lignes qui contiennent */ uniquement, l'expression suivante est insusante car
elle exclut complètement les espaces :
1 Cmd 12 >egrep '^[^ ]+\*/ *$' etudiant.c

par contre :
1 Cmd 13 >egrep '^.*[^ ]+.*\*/ *$' etudiant.c
2 #include"etudiant.h" /* inclut personne.h */

veut dire : une ligne où  quelque part  il y a  quelque chose  autre que (espace).

1.5.3 Les ltres


Un ltre est un programme (commande ou encore utilitaire) Unix qui lit une entrée, qui sera
considéré comme un ot composé de lignes de caractères et réalise une ou plusieurs transformations sur
chaque ligne pour produire un résultat.
Pour un ltre l'entrée provient d'un chier qui est, par défaut, l'entrée standard (le clavier). De
même le résultat est écrit sur un chier qui est, par défaut, la sortie standard (l'écran).
Dans le cas général (cf. g. 1.2) les transformations dépendent des instructions et sont contrôlées
par des options.
Instructions
fichier ou ligne de commande

Entrée Filtre Sortie

par defaut entrée commande ou utilitaire par défaut sortie


standard (clavier) standard (écran)

Options

Fig. 1.2  Présentation générale d'un ltre Unix .

Parmi les commandes qui jouent le rôle de ltres citons : grep (dont egrep (cf. 1.5.2) est une variante),
tail (achage d'une partie d'un chier), sort, wc, tr (traduction de caractères), sed (éditeur de texte
non interactif) et awk qui supporte un véritable langage de programmation, proche du C, pour la
manipulation des chiers texte.
Sortie1 Entrée2
Entrée 1 Filtre2 Sortie 2
Filtre
1 Tube
Entrée standard Entrée Sortie Sortie Standard
du tube du tube

Fig. 1.3  Utilisation des tubes avec les ltres Unix .

Les ltres sont particulièrement intéressants lorsqu'ils sont enchaînés à l'aide de tube s. La gure 1.3
schématise la commande composée : filtre1 | filtre2
Par exemple : ls | wc -w compte le nombre de chiers dans le répertoire courant (l'option -w
(Words ) spécie le comptage de mots uniquement). Notons que, dans ce cas-là la première commande
(ls) n'est pas un ltre ce qui ne change rien au fonctionnement du tube.
Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998
20 Chapitre 1 Introduction àUnix

La commande cat
La commande cat est un cas typique des ltres. Comme on peut le voir dans la version simpliée
proposé dans ce document (cf. 2.4.3), son fonctionnement de base est très simple : sans arguments il
ache à l'écran (sortie standard) ce qui est saisi au clavier (entrée standard). Avec un ou plusieurs
arguments, il ache les contenus des chiers à l'écran.
cat [ -nbsuvet ] [fichier...]

Quelques options
 -n Précéder chaque ligne par son numéro.
 -b Pareil que le précédent mais ne pas numéroter les lignes blanches (vides).
 -v Acher un code pour les caractères non imprimables.
L'exercice suivant illustre quelques unes des utilisations possibles de cette commande.
Exercice
Sachant que le caractère D (ctrl-D) signie  n de saisie  lors d'une saisie au clavier, commenter
la séquence de commandes qui suit.
1 <harpo.alissali: 1>set prompt = 'Cmd. no. ! > '
2 Cmd. no. 2 > mkdir Annuaire
3 Cmd. no. 3 > cd Annuaire
4 Cmd. no. 4 > ls -l
5 total 0
6 Cmd. no. 5 > cat > an1
7 Dupond 0123456
8 ^D
9 Cmd. no. 6 > cat an1
10 Dupond 0123456
11 Cmd. no. 7 > cat > an2
12 Durans d 9876549
13 Martin 1111222
14 Bertrand 9998887
15 ^D
16 Cmd. no. 8 > cat an1
17 Dupond 0123456
18 Cmd. no. 9 > cat  an1
19 Meyer 55544433
20 ^D
21 Cmd. no. 10 > cat an* > an
22 cat: input/output files 'an' identical
23 Cmd. no. 11 > cat an
24 Dupond 0123456
25 Meyer 5554433
26 Durand 9876549
27 Martin 1111222
28 Bertrand 9998887
29 Cmd. no. 12 > sort an
30 Bertrand 9998887
31 Dupond 0123456
32 Durand 9876549
33 Martin 1111222
34 Meyer 5554433
35 Cmd. no. 13 > sort an1 an2 > anTrie
36 Cmd. no. 14 > cd ..
37 Cmd. no. 15 > rmdir Annuaire
38 rmdir: directory "Annuaire": Directory not empty
39 Cmd. no. 16 > rm -r Annuaire

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


1.6 La programmation en C-Shell 21

1.6 La programmation en C-Shell


Un shell script est un chier texte qui contient une suite de commandes, dont certaines (parmi les
commandes internes) jouent le rôle de contrôle de ot d'exécution. Dans le cas du C-Shell ces dernières
ainsi que la forme des expressions autorisées sont largement inspirées du langage C d'où le nom de cet
interprète.
L'exemple suivant montre un petit script C Shell qui servira d'exemple par la suite. Ce script re-
cherche, à l'aide de la commande egrep, une liste de mots dans les chiers d'un ensemble de répertoires
prédénis.
1 #! / bin / csh
2 set r e p e r t o ir e s = ( $HOME/ Annuaire ~ a l i s s a l i / lo c a l / Annuaire )
3 foreach rep ( $ r e p e r t o ir e s )
4 cd $rep
5 echo Recherche dans le r e p e r t o ir e :a : $rep
6 foreach mot ( $  )
7 foreach f ic h ie r (  )
8 if ( ( f $ f i c h ie r ) && ( r $ f i c h i e r ) ) then
9 ( f i l e $ f i c h i e r j / usr /xpg4 / bin / grep Fq " text ")
10 if ( $status == 0 ) then
11 echo Recherche dans le f ic h ie r :a : $ f i c h i e r
12 grep $mot $ f i c h i e r
13 if ( $status != 0 ) echo Aucune correspondance dans ce f ic h ie r !
14 endif
15 endif
16 end
17 end
18 end

1.6.1 Substitution de nom de chier


Avant l'exécution d'une commande, le C-Shell constitue les chaînes de caractères et les noms des
chier en interprétant certains caractères (un sous-ensemble des expressions régulières). En plus de `?'
et `*' décrits dans l'introduction au C Shell (cf. 1.3), les formes suivantes sont interprétées :
 [...] a la même signication que dans les expressions régulières ;
 { ch1, ch2, ... } a le même sens que le précédent sauf que le résultat n'est pas trié ;
 utilisateur se réfère au répertoire racine de utilisateur.
1 cmd 1 >ls tabEtudiantsV?.c
2 tabEtudiantsV0.c tabEtudiantsV2.c tabEtudiantsV4.c
3 tabEtudiantsV1.c tabEtudiantsV3.c
4 cmd 2 >echo tabEtudiantsV[432].c
5 tabEtudiantsV2.c tabEtudiantsV3.c tabEtudiantsV4.c
6 cmd 3 >echo tabEtudiantsV{4,3,2}.c
7 tabEtudiantsV4.c tabEtudiantsV3.c tabEtudiantsV2.c
8 cmd 4 >ls ~alissali
9 Makefile app-defaults tmp

Dans le script de l'exemple : ~alissali désigne le répertoire racine de l'utilisateur alissali, la


variable d'environnement prédénie HOME contient la même valeur. L'expression de la boucle interne
foreach sera remplacée par la liste des noms de tous les chiers du répertoire courant.

1.6.2 Variables internes du C Shell


Une variable interne du C-Shell est constituée d'un nom et d'une valeur. La valeur est une suite de
mots (zéro ou plus) séparés par des espaces.
Une variable est dénie (et éventuellement initialisée) par la commande interne :
set [var [ = valeur ] ]

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


22 Chapitre 1 Introduction àUnix

Si valeur est composée de plusieurs mots elle doit être délimitée par des parenthèses. La valeur peut
être le résultat de l'expansion de nom de chier ou d'une commande, dans ce dernier cas la commande
doit être délimité par des guillemets simples (' ').
Le script annuRech.csh utilise la commande set une seule fois ; pour dénir la variable repertoires
et l'initialiser à la liste des répertoires où on veut eectuer la recherche.
La forme :

set var[n] = nouveauMot


remplace le mot numéro n de var par nouveauMot.
$var et ${var} permettent de récupérer la valeur de var. $var[ind] et ${var[ind]}, où ind est un
entier strictement positif, se réfèrent au mot d'indice ind. ind peut aussi désigner un intervalle. $#var
et ${#var} donnent le nombre de mots dans var.
La commande :

unset pattern
permet de supprimer toutes les variables dont le nom est mis en correspondance (d'après les règles
de substitution de nom de chier) avec pattern.
Exemples
1 (alissali@lola) ~>csh
2 (alissali@%m) %~>set prompt = 'cmd ! >'
3 cmd 2 >set message = (C-shell est un interprete de commandes)
4 cmd 3 >echo $message
5 C-shell est un interprete de commandes
6 cmd 4 >set message[3] = mon
7 cmd 5 >echo $message
8 C-shell est mon interprete de commandes
9 cmd 6 >echo $message[-3]
10 C-shell est mon
11 cmd 7 >echo $message[4-6]
12 interprete de commandes
13 cmd 8 >set fichPers = pers*
14 cmd 9 >echo $fichPers
15 personne.c personne.h personneTest.c
16 cmd 10 >set fichEtd = `ls etu*`
17 cmd 11 >echo $fichEtd
18 etudiant.c etudiant.h etudiantTest.c
19 cmd 12 >echo $#fichEtd
20 3
21 cmd 13 >echo $#message
22 6
23 cmd 14 >unset mes*
24 cmd 15 >echo $message
25 message: Undefined variable.

1.6.3 Rappel de commande et modicateurs de mots


Le C-Shell maintient une liste des dernières commandes exécutées. La taille de cette liste est déter-
minée par la valeur de la variable history, la commande du même nom, history, permet d'acher
cette liste.
Un rappel de commande commence par le caractère !, le(s) caractère(s) qui suivent celui-ci déter-
minent comment la commande sera rappelée :
 !! : rappelle la dernière commande ;
 !n : rappelle la commande numéro n ;
 !chaine : rappelle la commande la plus récente qui commence par chaine ;
 !?chaine? rappelle la commande la plus récente qui contient chaine ;
Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998
1.6 La programmation en C-Shell 23

 !{chaine1}chaine2 rappelle la commande la plus récente qui contient chaine, y ajouter chaine2.
Lors d'un rappel de commande, on peut eectuer des modications à l'aide de l'opérateur : sur une
variable ou un nom de chier. Un modicateur permet de déterminer la modication à eectuer, le
tableau 1.3 résume les modicateurs les plus intéressants.
Modificateur Signication
r Supprimer un suxe de la forme `.xxx', laissant le nom sans extension.
e Supprimer tout sauf le suxe, laissant l'extension.
s/l/r/ Substituer la chaîne `l'par la chaîne `r'.
& Répéter la dernière substitution.
g modication générale (toute occurrence), préxe un autre modicateur (p.e. gr).
p imprimer la nouvelle commande sans l'exécuter.
Tab. 1.3  Modicateurs de rappel de commande et de nom de chier
Sauf s'il est précédé de `g' un modicateur est appliqué une seule fois. Les modicateurs sont parti-
culièrement utiles dans les rappels de commandes (opérateur !!) et lorsqu'ils sont appliqués à des noms
de chiers.
1 (alissali@lola) ~>csh
2 (alissali@%m) %~>set prompt = 'Cmd ! >'
3 Cmd 2 >history
4 Cmd 3 >set history=15
5 Cmd 4 >history
6 3 set history=15
7 4 history
8 Cmd 5 >pwd
9 /export/home/ens/cuc/alissali
10 Cmd 6 >cd pub/BDU
11 Cmd 7 >!p
12 pwd
13 /export/home/ens/cuc/alissali/pub/BDU
14 Cmd 8 >!4
15 history
16 3 set history=15
17 4 history
18 5 pwd
19 6 cd pub/BDU
20 7 pwd
21 8 history
22 Cmd 9 >ls -l etudiant.c
23 -rw-r--r-- 1 alissali cuc 298 Dec 10 18:01 etudiant.c
24 Cmd 11 >set fichier="etudiant.c"
25 Cmd 12 >ls -l $fichier:r
26 UX:ls: ERROR: Cannot access etudiant: No such file or directory
27 Cmd 13 >ls -l $fichier:r.h
28 -rw-r--r-- 1 alissali cuc 240 Dec 10 18:23 etudiant.h
29 Cmd 15 >!ls:p
30 ls $fichier:r.h
31 Cmd 16 >ls -l etudiant.c
32 -rw-r--r-- 1 alissali cuc 298 Dec 10 18:01 etudiant.c
33 Cmd 18 >ls -l etu*.?
34 -rw-r--r-- 1 alissali cuc 298 Dec 10 18:01 etudiant.c
35 -rw-r--r-- 1 alissali cuc 240 Dec 10 18:23 etudiant.h
36 -rw-r--r-- 1 alissali cuc 110 Dec 10 18:01 etudiantTest.c
37 Cmd 19 >!!:s/etu/date/
38 ls -l date*.?
39 -rw-r--r-- 1 alissali cuc 1092 Dec 10 18:01 dates.c
40 -rw-r--r-- 1 alissali cuc 127 Dec 3 18:48 dates.h
41 -rw-r--r-- 1 alissali cuc 92 Dec 10 18:01 datesTest.c
42 Cmd 20 >ls -l etudiant.c etudiant.h

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


24 Chapitre 1 Introduction àUnix

43 -rw-r--r-- 1 alissali cuc 298 Dec 10 18:01 etudiant.c


44 -rw-r--r-- 1 alissali cuc 240 Dec 10 18:23 etudiant.h
45 Cmd 21 >!!:s/etudiant/dates/
46 ls -l dates.c etudiant.h
47 -rw-r--r-- 1 alissali cuc 1092 Dec 10 18:01 dates.c
48 -rw-r--r-- 1 alissali cuc 240 Dec 10 18:23 etudiant.h
49 Cmd 22 >!!:&
50 ls -l dates.c dates.h
51 -rw-r--r-- 1 alissali cuc 1092 Dec 10 18:01 dates.c
52 -rw-r--r-- 1 alissali cuc 127 Dec 3 18:48 dates.h
53 Cmd 23 >!20:gs/etudiant/dates/
54 ls -l dates.c dates.h
55 -rw-r--r-- 1 alissali cuc 1092 Dec 10 18:01 dates.c
56 -rw-r--r-- 1 alissali cuc 127 Dec 3 18:48 dates.h
57

le tableau 1.4 présente quelques expressions sur les variables particulièrement intéressantes pour les
scripts C-Shell.
$< expression remplacée par une ligne de l'entrée standard (le clavier).
$?var
${?var} une expression qui vaut 1 si var est déni, 0 sinon.
$n Trois expressions équivalentes.
${n} Désignent le ne argument (paramètre) de l'appel du script.
$argv[n] L'argument d'indice 0 est le nom du chier qui contient le script.
$* Deux expressions équivalentes.
$argv[*] Désignen tous les arguments (paramètres) du script.
Tab. 1.4  Expressions spéciques sur les varaibles en C Shell

1.6.4 Expressions et opérateurs


Certaines commandes internes du C-Shell (cf. par exemple le tableau 1.7) acceptent des expressions
qui utilisent des opérateurs semblables à ceux du langage C et ont la même précédence (ordre de priorité).
Typiquement les expressions paraissent dans les commandes @, exit, if, set et while. Les valeurs nulles
ou manquantes sont remplacées par 0. Le résultat d'une expression est une chaîne de caractères qui peut
représenter un nombre (après conversion, explicite ou implicite selon le cas).
Le tableau 1.5 présente les opérateurs du C Shell dans leur ordre de précédence.
Opérateur Opération
(...) groupement (force les priorités)
 complément à 1 (négation logique bit-à-bit)
! négation logique
* / % multiplication, division et reste
+ - addition et soustraction
  décalage à gauche, décalage à droite
< > <= >= inférieur, supérieur, inférieur ou égale, supérieur ou égale
== != = ! égale, diérent, désignation ou non d'un nom de chier (cf. commentaire ci-après)
& ET bit-à-bit
 OU exclusif bit-à-bit
| OU bit-à-bit
&& ET logique
|| OU logique
Tab. 1.5  Opérateurs du C Shell
Contrairement au langage C, les opérateurs de comparaison comparent des chaînes de caractères, les
autres opérateurs traitent leurs arguments comme des nombres.
L'opérateur = (resp. !) vérie si son premier argument (à gauche) correspond (resp. ne correspond
pas) à un nom de chier désigné par son deuxième argument (à droite).
Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998
1.6 La programmation en C-Shell 25

Dans annuRech.csh les opérateurs == et != sont utilisés pour tester la valeur de la variable prédénie
status . La valeur de cette variable est automatiquement mise à jour par le C shell pour indiquer l'état
de terminaison (c.à.d. la valeur de retour) de la dernière commande exécutée (voir par exemple la
commande exit dans le tableau 1.8 ci-après).
Les expressions du tableau 1.6 eectuent des tests sur chiers . Chaque expression retourne true (ou
1) si elle est vériée, false (ou 0) sinon.
Test Valeur vraie si...
-r nomFichier le chier est accessible en lecture.
-w nomFichier le chier est accessible en écriture.
-x nomFichier le chier est accessible en exécution
(ou en recherche pour un répertoire).
-e nomFichier nomFichier exists.
-o nomFichier nomFichier appartient à l'utilisateur.
-z nomFichier nomFichier est vide (taille 0).
-f nomFichier nomFichier est un chier ordinaire.
-d nomFichier nomFichier est un répertoire.

1.6  Tests sur les chiers en C Shell


Tab.

Si nomFichier n'existe pas ou est inaccessible tous ces tests retournent false.
Le premier if dans annuRech.csh teste si la valeur de la variable fichier est un nom de chier
ordinaire accessible en lecture.
1.6.5 Commandes internes (built-in )
Les deux tableaux suivants résument les commandes internes les plus importantes du C Shell : les
commandes de contrôle d'exécution sont groupées dans le tableau 1.7, et les autres commandes dans le
tableau 1.8.
Quelques restrictions syntaxiques s'appliquent aux commandes du tableau 1.7, en particulier chaque
occurrence de foreach, while et end doit paraître seule (ou avec expr le cas échéant) sur sa ligne.
Chaque occurrence de if...then, else et switch, doit être le premier mot (hormis les espaces blancs)
sur sa ligne.
1.6.6 Analyse du script annuRech.csh
Le script annuRech.csh recherche une liste de mots, donnés en paramètres à l'appel du script, dans
les chiers textes des répertoires désignés par la variable repertoires, dénie et initialisée en début du
script.
La boucle foreach est utilisée trois fois :
 rep prend les valeurs successives de la liste des répertoires (variable repertoires) ;
 mots prend les valeurs successives des paramètres d'appel du script (expression $*, cf. tableau 1.4),
ce sont les mots à rechercher ; et
 fichier prend successivement tous les noms des chiers du répertoire courant.
On remarque que la commande grep est référencée de deux manières diérentes : la première fois
par un chemin d'accès absolu et la deuxième fois simplement par son nom. L'explication est qu'il peut y
avoir plusieurs versions d'une même commande (ce qui est habituellement indiquées clairement dans la
man page), l'utilisation du chemin d'accès absolu permet d'imposer l'exécution du programme (version)
désigné au lieu de suivre le schéma habituel de recherche de commande (cf. 1.3). tel est le cas pour le
deuxième appel de grep, et où la version utilisée dépend de la valeur de la variable path (cf. 1.6.2).
la variable status est testeé après chaque exécution de grep ; une valeur diérente de 0 indique que
la recherche a échoué (cf. man page de grep). Après le deuxième test, on ache un message d'erreur
en cas d'échec, on pourrait aussi ajouter une commande exit mais dans ce cas-là il faut utiliser la
commande if...then puisqu'il ne s'agit plus d'une commande simple. C'est le cas pour les deux autres
tests qui portent chacun sur plusieurs commandes. Le premier teste si le chier existe et s'il est accessible
en lecture. Le deuxième teste la valeur de retour de la commande de la ligne précédente. Il s'agit d'une
commande composée à l'aide d'un tube qui permet de vérier que fichier est un chier texte.
L'ensemble peut donc se lire : pour chaque rep de la liste repertoires, pour chaque mot de la liste
d'arguments et pour chaque fichier (texte accessible en lecture) dans le répertoire courant (rep après
l'exécution de cd), acher les lignes qui contiennent le mot courant (commande grep).
Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998
26 Chapitre 1 Introduction àUnix

Commande Description
if (expr) commande commande est une commande simple, elle est exécutée si expr est vraie.
if (expr1) then Une seule séquence de commandes, qui apparaissent à la place des  ...
... est exécutée selon les valeurs des expri.
else if (expr2) then
... if doit être seul sur sa ligne, ou suivre un else.
else endif et else doivent être les premiers mots sur leurs lignes respectives.
...
endif
switch (chaine)
case label: Les labels sont des chaînes de caractères qui peuvent utiliser
... les méta-caractères de nom de chier *, ? et [...].
breaksw L'exécution commence au premier label qui se met en correspondace
... avec chaine et se termine par breaksw ou, à défaut, par endsw.
default: Si aucun label ne correspond à chaine c'est la séquence qui suit default
... (s'il est présent) qui est exécutée.
breaksw
endsw

while (expr) Boucle tant que expr est vraie (valeur diérente de zéro)
... break et continue peuvent aussi être utilisés pour terminer la boucle.
end
foreach var (listeMots) Les commandes contenues dans le corps de la boucle sont exécutées
... pour chaque mot de listeMots. La variable var prend
end pour valeur le mot courant pour chaque itération.
continue peut être utilisé pour interrompre l'itération en cours
break peut être utilisé pour terminer la boucle.
repeat nombre commande Répète commande nombre fois.
Les mêmes restrictions que pour if s'appliquent.
goto label Continue (ou reprend) l'exécution après label qui est une chaîne caractères
à laquelle s'appliquent les expansions de commande et de nom de chier.
break Continue l'exécution après la boucle while ou foreach la plus proche.
Les commandes restantes sur la même ligne que break sont exécutées.
continue Continue l'exécution avec la prochaine itération de la boucle while
ou foreach la plus proche.
Tab. 1.7  Commandes interne de contrôle du C Shell

Commande Description
@ [ var =expr ] Aectation du résultat de l'évaluation de expr à (resp. au ne mot de) var.
@ [ var[n] =expr ] Dans expr, les opérateurs du tableau 1.5 sont autorisés, mais ceux susceptible
d'être interprétés par le C-Shell (>, <, &, et |) doivent paraître dans
des parties parenthésées de l'expression.
cd [ dir ] Positionne le répertoire courant (ou répertoire de travail ) du shell à dir (HOME
chdir [ dir ] par défaut). Si dir est un chemin d'accès relatif et s'il n'est pas trouvé à partir du
répertoire courant, rechercher dans les répertoires désignés par la variable cdpath.
exit [ (expr) ] Termine le (script) shell et retourne la valeur de expr ou, à défaut, de status.
exec commande Exécute commande à la palce du shell courant qui se termine.
Tab. 1.8  Autres commandes interne du C Shell

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


1.7 Processus 27

1.6.7 Exercice
Les questions suivantes ont pour but d'écrire un script qui permet de tester si, pour un nom donné,
le chier correspondant a un autre lien dans le même rérertoire. La ou les commandes à utiliser (le
cas échéant) sont notées en début de ligne. Il faut pour chaque question trouver les arguments et les
options appropriées ainsi que l'enchaînement lorsqu'il s'agit d'une commande composée. Faire des essais
sur machine jusqu'à obtention du bon résultat.
1o ln : créer un lien, nouveau de l'un des chiers existants (par exemple combin.c).
2o ls : acher à l'écran la liste des chiers du répertoire courant avec le numéro de i-node de chaque
chier.
3o Répéter la question précédente pour obtenir le même résultat mais pour un seul chier.
4o cut : à l'aide d'un tube acheminer la sortie de la commande précédente vers l'entrée de la
commande cut de manière à obtenir le numéro de i-node seul.
5 set, opérateur `...` : modier la commande précédente pour aecter le résultat à la variable C
o
Shell noInode.
6o Répéter la question précédente pour sauvegarder le numéro de i-node du chier nouveau dans
la variable C Shell noInodeRech.
7o if, echo : écrire une instruction conditionnelle qui ache le message nouveau est un lien si
noInode est égal à noInodeRech.

8o foreach : écrire une boucle qui exécute les commandes obtenues en réponse aux questions 3, 4,
5 et 7 pour chacun des chiers du répertoire courant.

1.7 Processus
On appelle processus l'unité élémentaire d'exécution, c.à.d l'unité de traitement dans le sens dyna-
mique du terme. Unix supporte l'exécution simultanée d'un nombre théoriquement illimité de processus,
dont chacun est identié par un identicateur unique appelé PID (Processus IDentier ).
Un processus est une entité vivante qui exécute la tâche décrite par un programme, habituellement
sauvegardé dans un chier binaire exécutable. Un tel chier résulte de la compilation et de l'édition
de liens d'un programme écrit dans un langange de programmation quelconque. Il contient les instruc-
tions à exécuter ainsi que les descriptions des données statiques (allouées au préalable) et des données
dynamiques (allouées à l'exécution).

1.7.1 Caractéristiques des processus


Pour exécuter un programme, le noyau crée un processus et charge le programme en mémoire. Mais
avant de lancer l'exécution, il prépare les arguments d'appel , et une copie de l'environnement (la liste de
toutes les variables d'environnement (cf. 1.3.3)). On rappelle que le terme  variable  est abusif, puis-
qu'une variable d'environnement n'est qu'une chaîne de caractères de la forme : "variable=valeur\0".
Le chargement de programme permet de passer de l'état inerte (programme exécutable) à l'état actif
(processus), en construisant une image mémoire qui contient, en plus des informations précédentes, les
ressources nécessaires à l'exécution du programme telles que la pile d'appel de fonctions (cf. 3.9.1). Le
processus dispose aussi des ressources système telles que le temps CPU.
Un création de processus se fait par clonage d'un processus père . Entre autres, un processus ls hérite
des caractéristiques suivantes de son processus père :
 l'environnement courant (les variables d'environnement actuellement dénies) ;
 le terminal d'attache ;
 le groupe de processus ;
 les identicateurs, eectif et réel, du propriétaire et de son groupe ;
 la priorité d'exécution.
Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998
28 Chapitre 1 Introduction àUnix

1.7.2 Exemples
Démarrage du système Unix
Lors du démarrage de la machine, une procédure spéciale est appliquée pour créer un processus
spécial, nommé init et ayant comme identicateur 1, qui devient l'ancêtre de tous les autres processus.
Ce schéma permet au système de maintenir une structure hiérarchique unique pour tous les processus.
Par exemple, init crée un processus ls, appelé getty pour chaque terminal reconnu par la machine.
Ce processus attend les tentatives de connexion (login et mot de passe ) des utilisateurs. Lorsqu'un
utilisateur est admis, le processus getty est remplacé par un processus shell. Celui-ci appartient à
l'utilisateur, il sera l'ancêtre de tous les processus créés par l'utilisateur durant la session.
Le programme afficheId
Ce programme, donné en exemple pour illustrer la compilation séparée (cf. 2.5.3), ache le PID du
processus qui exécute le programme ainsi que celui de son père. Il ache aussi l'identité de l'utilisateur
et celle de son groupe. On remarque que seul le PID du processus lui-même est modié, son père étant
le shell interactif à partir duquel toutes les exécutions sont lancées.
1.7.3 Processus et langage C
Préparation des arguments d'appel
Dans un programme en langage C la fonction main peut accepter deux paramètres, dans ce cas-là
son prototype (ou signature) est le suivant :
1 int main(int argc, char *argv[]);

argv désigne les arguments d'appel du programme à l'exécution, c.à.d la liste des mots utilisée pour
invoquer le programme, y compris le nom du programme lui même. argc est le nombre des éléments de
cette liste, chaque entrée de argv pointe sur un de ces arguments (sous forme de chaîne de caractères).
Exemple
Le programme suivant ache à l'écran son nom d'appel puis, dans une boucle, ses arguments.
argProg.c

1 #include<stdio . h>
2
3 int main( int argc , char  argv [ ])
4 f
5 int i ;
6
7 p r in t f ( "Programme : %s , nombre d ' arguments : %d . n n" , argv [ 0 ] , argc ) ;
8 for ( i = 1 ; i < argc ; i ++)
9 p r in t f ( "argument no. %d : %s n n" , i , argv [ i ] ) ;
10
11 return ( 0 ) ;
12 g
Et voici quelques résultats d'exécution, notons en particulier la création et l'appel du programme à

l'aide d'un nouveau lien (lienArgProg) :


1 Cmd. no. 66 > cc argProg.c
2 Cmd. no. 67 > a.out
3 Programme : a.out, nombre d'arguments : 1.
4 Cmd. no. 68 > a.out arg1 arg2 bonjour bye
5 Programme : a.out, nombre d'arguments : 5.
6 argument no. 1 : arg1
7 argument no. 2 : arg2
8 argument no. 3 : bonjour

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


1.7 Processus 29

9 argument no. 4 : bye


10 Cmd. no. 69 > cc -o argProg argProg.c
11 Cmd. no. 70 > argProg arg1 arg2
12 Programme : argProg, nombre d'arguments : 3.
13 argument no. 1 : arg1
14 argument no. 2 : arg2
15 Cmd. no. 71 > ln argProg lienArgProg
16 Cmd. no. 72 > lienArgProg bonjour bye
17 Programme : lienArgProg, nombre d'arguments : 3.
18 argument no. 1 : bonjour
19 argument no. 2 : bye

Accès aux variables d'environnement


Il existe des moyens (fonctions et variables globales), pour permettre à un programme C d'accéder
en lecture et/ou en modication à l'environnement.
1.7.4 Processus et shell
Lorsqu'un shell exécute une commande autre que les commandes internes, il crée un nouveau pro-
cessus dans lequel le programme correspondant à la commande est exécutée. Le ls peut ainsi accéder
à sa copie des variables d'environnement s'il en a besoin. Par exemple, la commande man accède à la
variable d'environnement MANPATH pour récupérer la liste des répertoires dans lesquels sera eectuée la
recherche de la documentation (les man pages).
Exemple
1 Cmd. no. 1 > setenv NOUVEAU "Variable d'environnement"
2 Cmd. no. 2 > csh
3 <harpo.alissali: 1>setenv
4 ...
5 MANPATH=/usr/man:/usr/local/man
6 NOUVEAU=Variable d'environnement
7 <harpo.alissali: 2>whereis ps
8 ps: /usr/bin/ps /usr/ucb/ps /usr/man/man1/ps.1 /usr/man/man1b/ps.1b
9 <harpo.alissali: 3>setenv MANPATH
10 <harpo.alissali: 4>setenv
11 ...
12 MANPATH=
13 <harpo.alissali: 5>man ps
14 No manual entry for ps.
15 <harpo.alissali: 6>exit
16 <harpo.alissali: 7>Cmd. no. 3 > setenv
17 ...
18 MANPATH=/usr/man:/usr/local/man
19 Cmd. no. 4 > man ps
20 ...

1.7.5 Commandes de manipulation des processus


La commande ps
ps [ -af ... ] [ -p proclist ] [ -u uidlist ] ...
Cette commande ache des informations sur les processus actifs. Par défaut elle ache un minimum
d'informations sur le processus appelant et sur ses ls. Les options, dont une partie seulement gure ici,
permettent de mieux gérer la sortie de la commande et son format.
Quelques options
-a acher des informations sur tous les processus les plus fréquemment activés.
-f (emphFull) achage complet.
Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998
30 Chapitre 1 Introduction àUnix

-p proclist acher des informations sur les processus dont les PIDs sont donnés dans proclist.
-u uidlist acher des informations sur les processus dont les UIDs eectifs sont donnés dans uidlist.

La commande kill
kill [ -signal ] pid...

kill -l
La commande kill fait partie des commandes standards d'Unix, mais elle est aussi implantée
(comme commande interne) par les diérents shells. Elle permet d'envoyer un signal à un processus.
Les signaux disponibles peuvent être achés à l'écran avec l'option -l. Un signal est identié par son
nom ou par son numéro. Parmi les signaux les plus utilisés notons KILL, BUS et SEGV (respectivement
numéros 9, 10 et 11). Le premier permet de  tuer  le processus numéro pid. Les deux autres sont
souvent rencontrés lors d'une erreur d'exécution de programme : dans ce cas-là un tel signal est envoyé
par le noyau pour tuer le processus en achant un message (respectivement Bus error et Segmentation
fault).

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


Chapitre 2

Le langage C
2.1 Le langage C en bref (Rappels)
2.1.1 Variables
Une variable est dénie par un triplet : nom, type (cf. 2.1.2) et valeur. Le nom et le type sont indis-
pensables, ils sont fournis par une dénition de variable (et rappelés si nécessaire par une déclaration).
Une variable sert à stocker et à récupérer des valeurs constantes (cf. 2.1.3) de son même type. Le
langage C n'impose pas d'attribuer une valeur à une variable, mais une variable dont on ne fait pas
varier la valeur ne sert pas à grand-chose. La valeur d'une variable est initialement indénie, elle peut
varier au cours de l'exécution : l'opérateur d'aectation permet l'attribution d'une nouvelle valeur à une
variable.
Une aectation qui a lieu à la dénition de la variable est appelée initialisation).
L'utilisation (l'accès ou la référence) permet de récupérer sa valeur (par exemple dans la partie droite
d'une aectation). Le résultat d'une référence à une variable dont la valeur est indénie est imprévisible.
2.1.2 Types
types simples
Un type simple est déni par le langage. Chaque type peut être accompagné d'un ou plusieurs
qualicatifs de type qui en modie la nature (taille, signe, type de stockage, etc.).
Type mot-clef signe taille défaut
entier int signed/unsigned short/long signé >= 16 bits
réel float double/long double
caractère char signed/unsigned 8 bits signé ou non
Tab. 2.1  Types simples du langage C.
Il n'existe pas de type booléen en C. Une expression booléenne (logique) est évaluée en type entier,
la valeur est traitée comme la valeur logique FAUX, toute autre valeur (diérentes de 0), elle est traitée
comme la valeur logique VRAI.
Types composés
Un type composé (tableau (cf. 2.3.1), enregistrement (cf. 2.3.3), etc.) est créé par le regroupement
d'éléments de type simple ou composé. Les type composés seront discutés plus en détails plus loin
(cf. 2.3.4).
2.1.3 Valeurs constantes
En langage C les constantes sont typées, on déduit le type d'une constante d'après sa forme ou son
utilisation :
 de type entier :
qualication/type constante commentaire
int 12234 entier  normal .
long int 123456789L une grande valeur (se termine par 'L').
unsigned int 456U un entier non signé (se termine par 'U').
31
32 Chapitre2. Le langage C

 de type caractère :
constante description
'c' caractère  normal .
'\n' caractère  spécial  (commence par \) ayant un sens spécique : ici le retour-chariot.
'\013' caractère déni par son code ASCII en octal (commence par \0).
'\xb0f1' caractère déni par son code ASCII en hexadécimal (commence par \x)
Vu que la taille du stockage est ni, les valeurs numériques autorisées ont des limites inférieure et
supérieure. Ces limites sont dépendantes du compilateur et peuvent donc varier d'une machine à l'autre.
Elles sont dénies dans les chiers limit.h et float.h (sous Unix normalement dans le répertoire
/usr/include).
Les caractères sont codés par des valeurs entières et dénis par une table de codage (appelé table
ASCII ) qui dénit la correspondance caractère-code.

2.1.4 Aectation
 Opérateur simple : =
 Opérateurs composés : += -= *= /= etc.
Exemple : a += b est équivalent à a = a + b

2.1.5 Opérateurs
Un opérateur permet d'eectuer une opération sur un type donné. Les opérations suivantes s'ap-
pliquent à tous les types simples (y compris les caractères même si cela peut paraître absurde). D'autres
opérateurs ont des fonctions plus spéciques en fonction du type de donnée (l'indexage pour les tableaux,
l'indirection pour les pointeurs, la sélection pour les enregistrements, etc.), ils seront présentés lorsque
nous parlerons de ces constructions.
Arithmétiques
Les opérateurs arithmétiques (+, *, -, /, ...) habituels sont reconnus du langage C. Cependant,
puisqu'il s'agit d'un langage typé il faut bien noter que une division entière, par exemple, est diérente
d'une division réelle. Dans les expressions mixtes (entiers et réel par exemple), une conversion de type
est opérée avant de déterminer le type de l'opération.
Comparaisons
Les opérateurs de comparaison sont : == != >= <= >< .
Logiques
 Et logique : &&.
 Ou logique : ||.
 Négation : !.
Les opérateurs de comparaison et les opérateurs logiques rendent une valeur entière selon la règle de
simulation des booléens par des entiers (cf. 2.1.2). Cette valeur est 0 si le résultat de la comparaison ou
de l'expression logique est FAUX, et diérent de 0 sinon. Cette valeur est directement utilisable dans les
instructions conditionnelles (cf. 2.1.7) et les boucles (cf. 2.1.7).

2.1.6 Expressions
Une expression est une construction qui met en ÷uvre des opérateurs, des variables, des valeurs
(constantes) et des appels de fonctions. Les parenthèses peuvent être utilisées pour forcer les priorités
des opérateurs. Par exemple :
1 ( i 3 ) && ( j  3 somme( k, l ) )
On remarque le mélange d'opérations arithmétiques et logiques, ce qui est parfaitement correct en
C puisque les valeurs logiques sont simulées par les entiers. Quant au sens ou à l'utilité d'une telle
expression...
Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998
2.1 Le langage C en bref (Rappels) 33

L'évaluation d'une expression consiste à calculer sa valeur. Dans le cas de l'exemple, en supposant que
la fonction somme calcule la somme de ses arguments et que les variables i, j, k et l ont respectivement
les valeurs 2, 3, 4 et 5, cette expression s'évalue comme suit (en respectant les priorités) :
1 (i-3) -> -1
2 j*3 -> 9
3 somme(j,k) -> 9
4 j*3 - somme(k,l) -> 0
5 -1 && 0 -> 0

La valeur de l'expression est donc 0. Notons que la dernière étape est interprétée comme VRAI ET FAUX,
puisque -1 est diérent de 0 même s'il s'agit d'une valeur négative, d'où la valeur FAUX (0). Dans le cas
contraire, si la valeur était VRAI, la seule chose qu'on aurait pu armer est que la valeur de l'expression
est diérente de 0.
Il existe une forme spéciale des expression : l'expression conditionnelle :
expr_bool ? expr_vrai : expr_faux
Si le résultat de l'évaluation de l'expression expr_bool est égale à (resp. diérente de) 0, la valeur
de l'expression conditionnelle est celle de expr_faux (resp. expr_vrai).
Malgré l'attrait que peut représenter ce type d'expression dans certain cas(éviter une instruction
conditionnelle) , son utilisation est fortement déconseillée.

2.1.7 Instructions
 Une instruction simple est une expression se terminant par un ';'. Par exemple :
1 i 3;
2 j;
3 f ();
4 somme( k, 4 ) ;
Les deux premières instructions sont correctes mais complètement inutiles car elle rendent des
valeurs qui ne sont pas utilisées. La troisième instruction est un appel de fonction (cf. 2.1.9) qui
ne rend pas de valeur (ou qui rend une valeur qu'on n'exploite pas). Un tel appel est utile s'il
a un eet de bord , comme la modication de la valeur d'une variable globale ou l'achage d'un
message à l'écran. En supposant que la fonction somme n'a pas d'eet de bord, l'appel de la ligne
4 est aussi inutiles que les deux premières instructions.
 Une instruction composée est une séquence d'instructions entourée d'accolades ({...}) qui en
déterminent le début et la n.
Instructions conditionnelles
if (expr) instruction [else instruction]
expr est une expression entière traitée comme si elle était booléenne : la valeur 0 simule la valeur
booléenne FAUX, tout autre valeur simule VRAI.
Boucles
Une boucle est une répétition d'une instruction (simple ou composée) qui s'arrête lorsque une
condition donnée est satisfaite. Il y a trois formes de boucles en C :
while (expression)
instruction
Dans une boucle while, pour chaque itération, expression est évaluée, si sa valeur est diérente de
0 instruction est exécutée avant de commencer l'itération suivante. Il est important de s'assurer que
les variables utilisées dans expression sont bien initialisées avant la boucle et qu'elles sont mises à jour
dans la boucle de telle manière que la condition d'arrêt (expression == 0) nisse par se réaliser.
do
instruction
while (expression);

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


34 Chapitre2. Le langage C

Dans le cas de la boucle do, instruction est exécutée avant d'évaluer expression. comme le cas
précédent, on passe à l'itération suivante si la valeur de expression est diérente de 0. Dans certain
cas les variables impliquées dans cette évaluation peuvent ne pas être initialisées avant la boucle, par
exemple lorsqu'elles sont saisies au clavier.
for (expr_init; expr_cond; expr_maj)
instruction
La boucle for est la plus utilisée en langage C. Elle équivaut à une boucle while avec initialisation
(expr_init) et mise à jour (expr_maj), c'à.d. :
1 expr_init ;
2
3 while ( expr_cond )
4 f
5 in s t r u c t io n
6 expr_maj
7 g
2.1.8 Lecture du langage C
Dans les cas relativement simple, la lecture d'une déclaration ou d'une instruction ne devrait pas
poser de problème. Cependant il faut s'assurer de la bonne lecture de tous les éléments. Par exemple,
en se référant à la dénition de variable, une lecture complète doit préciser le nom, le type et la valeur
de la variable, comme suit :
1 float x; /*
définition de variable ; nom : x, type float,
2 valeur non initialisée */
3 int i = 10; /* définition de variable ; nom : i, type int, valeur
4 initialisée : 10 */

Dans le cas d'une instruction ou d'une expression il faut décomposer jusqu'au niveau le plus bas. Par
exemple :
1 x = i + 1; /* 1. expression : addition (entière) de i et de 1, résultat : 11.
2 2. expression : affectation (réelle -- implique la
3 conversion du type) du résultat à x.
4 3. Le tout est une instruction (expression suivie de ';').
5 */

Dans certains cas la lecture peut ne pas être immédiate. Sachant que les constructeurs [] et () ont
une priorité égale et supérieure à celle de *, la règle suivante permet de lire les déclarations complexes :

En partant du nom de l'objet déclaré, la lecture se fait de gauche à droite sauf si, parmi les constructeurs
non encore lus, celui de gauche est prioritaire à celui de droite. Les parenthèses permettent de forcer la
priorité

Exercices
Appliquer la règle de lecture pour obtenir les résultats suivants :
1o char *t[] : t est un tableau de pointeurs de caractères.
2o int *f() : f est une fonction retournant un pointeur sur un entier.
3o int *(*f)[]() f est un pointeur sur un tableau de fonctions retournant chacune un pointeur
sur entier. Cet exercice est très complexe et mérite d'être détaillé 1 :
f est l'objet déclaré.
(*f) : à lire avant le reste car la priorité est forcée par les parenthèses ; '*' se lit  pointeur  :
f est un pointeur.
(*f)[] : poursuite de la lecture de gauche à droite car '[]' est prioritaire sur '*' ; '[]' se lit
 tableau  : f est un pointeur de tableau.
1. Nous nous intéressons ici uniquement à la lecture et non pas à l'exactitude ou l'utilité d'une telle déclaration.

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


2.1 Le langage C en bref (Rappels) 35

(*f)[]() : poursuite de la lecture de gauche à droite car '()' est prioritaire sur '*' ; '()' se lit
 fonction  : f est un pointeur de tableau de fonction.
(*f)[](); : n de la déclaration à gauche (';') mais il reste des choses à droite.
*(*f)[](); : f est un pointeur de tableau de fonction de pointeur.
int *(*f)[](); : f est un pointeur de tableau de fonction de pointeur de int.
2.1.9 Fonctions
Dénition et utilisation des fonctions
 Une dénition de fonction comprend une en-tête (ou signature) et un corps.
 L'en-tête (ou signature) dénit la  nature  de la fonction, elle se compose de :
 type : c'est le type de la valeur qu'elle retourne;
 nom : qui permet l'appel (l'utilisation) de la fonction.
 paramètres : suite de variables typés séparées par virgules et entourée de parenthèses
'(...)'.
 Le corps est une instruction composée qui comprend les déclarations de variables et la sé-
quence des instructions exécutées par la fonction.
 Une fonction peut être utilisée avant d'être dénie, c'est souvent le cas lorsqu'une utilise la compi-
lation séparée (cf. 2.5). Dans d'autres cas on ne dispose pas du code source (en C) de la fonction
comme c'est le cas lorsqu'on utilise les bibliothèques de fonction (cf. 2.1.10). Dans ces deux cas-là,
et à défaut d'être dénie, la fonction doit être déclarée.
Une déclaration de fonction (ou prototype) est simplement son en-tête, suivie de `;'. Elle peut
être placée dans n'importe quel bloc de déclaration de la même manière qu'une variable.
 Si à l'appel le type des valeurs passées ne correspond pas au prototype, le compilateur opère une
conversion implicite des types, par exemple la fonction  racine carrée  de la bibliothèque math
est déclarée comme suit :

double sqrt(double x);

lors de l'appel :
1 int n ;
2 sqrt ( n ) ;
l'instruction réellement exécutée correspond à :
1 sqrt ( ( double ) n ) ;

2.1.10 Bibliothèques et utilisation des fonctions prédénies


Une bibliothèque est un ensemble de fonctions, de variables et de constantes précompilées que l'on
peut inclure dans un programme. Pour ce faire il faut :
 Déclarer (une partie de) la bibliothèque par l'inclusion d'un chier d'en-tête (header le ).
 Inclure la bibliothèque proprement dite lors de l'édition de liens.
Exemple
Les fonctions d'entrée/sortie (getc, printf, scanf, etc.) sont déclarées dans le chier stdio.h. Elles
appartiennent à la bibliothèque standard qui est incluse automatiquement dans chaque programme (donc
il n'y a pas besoin d'eectuer explicitement la deuxième étape ci-dessus).
Chaque programme utilisant une ou plusieurs de ces fonctions doit contenir la directive suivante :
#include <stdio.h>

Pour savoir quel chier il faut inclure (et pour obtenir toutes les informations nécessaires) pour
utiliser une fonction : utiliser la documentation en ligne, commande man. Par exemple :
Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998
36 Chapitre2. Le langage C

man getc
produit à l'écran :
1 getc(3S) Standard I/O Functions getc(3S)
2
3 NAME
4 getc, getc_unlocked, getchar, getchar_unlocked, fgetc, getw
5 - get character or word from a stream
6
7 SYNOPSIS
8 #include <stdio.h>
9
10 int getc(FILE *stream);
11
12 int getc_unlocked(FILE *stream);
13 ....
14
15 DESCRIPTION
16 ...
17
18 RETURN VALUES
19 ...
20
21 SEE ALSO
22
23 intro(3), fclose(3S), ferror(3S), flockfile(3S), fopen(3S),
24 fread(3S), gets(3S), putc(3S), scanf(3S), stdio(3S),
25 ungetc(3S)
26

La documentation est organisée en sections, par exemple la documentation de getc appartient à la


section 3S. Parfois il est nécessaire de préciser la section désirée à l'aide de l'option -s, par exemple :
man -s 3S getc

2.2 De l'applicatif à l'impératif: de CAML à C


Les ressemblances
 les types (cf. 2.1.2) ;
 les fonctions (cf. 2.1.9) ;
 les opérateurs (cf. 2.1.5) ;
 la conditionnelle (cf. 2.1.7) , à peu près.
Les diérences
 les variables (cf. 2.1.1) ;
 l'aectation (cf. 2.1.4) ;
 la séquence d'instructions (cf. 2.1.7) ;
 la boucle (cf. 2.1.7).

2.3 Structure de données en C


2.3.1 Tableaux
Dénition
Un tableau est une suite adjacente de variables (éléments du tableau) d'un type donné. Les éléments
sont accessibles uniquement par le mécanisme d'indexage ou accès indexé .
Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998
2.3 Structure de données en C 37

Syntaxe
type nom[taille];

Dénit un tableau de type type et de taille taille.


type nom [nLignes][nColonnes];

Dénit un tableau à deux dimensions. Cette déntion peut être généralisée davantage pour repré-
senter des tableaux multi-dimensionnels.

Exemples
1 /* Definitions */
2 /* tableau de 10 entiers*/
3 int tabEnt[10];
4
5 /* matrice de reels */
6 float matrice[5][5];
7
8 /* tableau de caracteres initialise, la taille est calcule
9 automatiquement */
10 char tabCar[] = "universite du Maine" ;
11 ...
12
13 /* Instructions */
14 /* Affectation au 1er element (indice 0 !) */
15 tabCar[0] = 'U';
16
17 /* transposition de matrice */
18
19 for(i=0, j=0; ...)
20 {
21 matrice[i][j] = matrice[j][i];
22 }
23
24 /* Permutation de deux elements : Utiliser une variable temporaire
25 pour ne pas ecraser l'ancienne valeur */
26 sauveElt = tabEnt[5];
27 tabEnt[5] = tabEnt[8];
28 tabEnt[8] = sauveElt;

Caractéristiques des tableaux


 La taille est un entier constant qu'il vaut mieux dénir à l'aide de #define ;
 l'indice doit être de type entier ;
 les éléments d'un tableau de taille N sont indexé de 0 à N-1 ;
 pour parcourir un tableau utiliser une boucle (for de préférence), utiliser le compteur de boucle
comme indice ;
 il n'y a pas de type chaîne de caractères en C. Par convention on utilise les tableaux de caractères,
en plaçant le caractère de n de chaîne '\0' (pour lequel il faut prévoir un élément supplémentaire)
après le dernier caractère de la chaîne ;
 il faut utiliser les fonctions appropriées de la bibliothèque standard , telles que strcpy, strcmp,
etc., déclarées dans le chier d'en-tête string.h, pour manipluer les chaînes de caractères.
Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998
38 Chapitre2. Le langage C

Exemple
explTableau.c

1 #include<stdio . h>
2 #include<s t r in g . h > /  Manipulation des chaines de caracter e s  /
3 #define N10
4 int main( void )
5 f
6 int tabEnt [N] , i ;
7 char message [ 8 ] ; /  t a i l l e du message + 1 pour le ' n 0 '  /
8 for ( i=0 ; i <N; i ++) f
9 p r in t f ( " Entrez tabEnt[%d]= n n" , i ) ;
10 scanf ("%d",&tabEnt [ i ]) ;
11 g
12 /  Copier une chaine constante dans le tableau message  /
13 strcpy ( message , " Valeurs " ) ;
14 for ( i=N 1 ; i >=0 ; i ) f
15 p r in t f ("%s n n" , message ) ;
16 p r in t f ( " tabEnt[%d] = %d" , i , tabEnt [ i ] ) ;
17 g
18 g

2.3.2 Pointeurs
Dénition
Un pointeur est une variable qui permet de désigner (pointer sur) d'autres objets d'un type donné.
Un pointeur permet d'avoir un accès indirect à la variable pointée. Le type du pointeur est  pointeur
sur le type de la variable pointée .
Syntaxe
type *nom;
Dénit un pointeur de type pointeur sur type .
Exemples
1 /* Defintions */
2 int ent1 = 4, ent2=123;
3 char car1='z', car2='w';
4
5 /* 2 pointeurs sur entier */
6 int *ptrEnt1, *ptrEnt2;
7
8 /* Def. et init. de 2 pointeurs sur caractere */
9 char *ptrCar1=&car1,
10 *ptrCar2=&car2;
11
12 /* Instructions */
13 /* ptrEnt1 pointe sur ent1 */
14 ptrEnt1 = &ent1;
15
16 /* ptrEnt2 pointe sur ent2 */
17 ptrEnt2 = &ent2;
18
19 /* ent2 prend la valeur de la variable pointee par ptrEnt1 (donc de ent1) */
20 ent2 = *ptrEnt1;
21

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


2.3 Structure de données en C 39

22 /* ptrEnt2 a la valeur que ptrEnt2 il pointe donc sur ent2 aussi */


23 ptrEnt1 = ptrEnt2;
24
25 /* la variable pointee par ptrCar2 prend la valeur de celle pointee
26 par ptrCar1 */
27 *ptrCar2 = *ptrCar1;

Caractéristiques des pointeurs


 Un pointeur qui ne pointe sur rien ne sert à rien !
 la valeur du pointeur est l'adresse (ou la référence ) de l'objet pointé ;
 l'opérateur `&', appliqué à un objet, retourne l'adresse de l'objet ;
 dans un bloc de déclarations l'opérateur `*' sert à dénir/déclarer un pointeur. Dans un bloc
d'instructions il sert à l'accès indirect à l'objet pointé ;
 il est possible d'attribuer à un pointeur de la mémoire à l'aide de fonctions de la bibliothèque
standard telles que malloc et calloc. Une allocation dynamique est eectuée par le programme
en cours d'exécution, contrairement à l'allocation statique faite par le compilateur pour toutes
variables dénies dans le programme (cf. exemple ci-après) ;
 les opérations arithmétiques sont autorisées sur les pointeurs ;
 un tableau est un pointeur constant auquel est associée un segement de mémoire.

IMPORTANT : ne pas confondre les opérations sur les pointeurs avec les opérations sur les objets
pointés.
explPointeur.c

1 #include<stdio . h>
2 #include<s t r in g . h> /  Manipulation des chaines de caracte r es  /
3 #include<malloc . h> /  Manipulation de la memoire dynamique  /
4 #define TAILLE_CHAINE
5 int main( void )
6 f
7 char typeEtst [TAILLE_CHAINE],  complement ,  nomComplet ;
8 int tailleNom ;
9
10 p r in t f ( "Type d ' etablissement ? n n" ) ;
11 scanf ("%s " , typeEtst ) ; /  Pas besoin de l ' operateur &  /
12 complement = c a llo c (TAILLE_CHAINE, sizeof ( char ) ) ;
13 p r in t f ( "Complement du nom ? n n" ) ;
14 scanf ("%s " , complement ) ; /  Pas besoin de l ' operateur &  /
15 tailleType = s t r le n ( typeEtst )
16 tailleNom = tailleType + s t r le n ( complement ) + 2 ;
17 nomComplet= c a llo c ( tailleNom , sizeof ( char ) ) ;
18 strcpy ( nomComplet , typeEtst ) ;
19  ( nomComplet+ tailleType ) = ' ' ; /  ecrase le ' n 0 '  /
20  ( nomComplet+ tailleType + 1 ) = ' n 0 ' ; /  pour le r e t a b l i r !  /
21 s t r c a t ( nomComplet , complement ) ;
22 p r in t f ( "Le nom complet est : %s n n" , nomComplet ) ;
23 g

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


40 Chapitre2. Le langage C

Trace de l'exécution
typeEtst complement nomComplet
Instruction taille valeur taille valeur taille valeur
all/e all/e all/e
déclaration 11(Cst)/0 ? 0/0 NULL 0/0 NULL
scanf (1 ) 11/11 "Universite" 0/0 NULL 0/0 NULL
calloc (1) 11/11 "Universite" 11/0 ? 0/0 NULL
scanf (2) 11/11 "Universite" 11/9 "du Maine" 0/0 NULL
calloc (2) 11/11 "Universite" 11/9 "du Maine" 22/0 ?
strcpy 11/11 "Universite" 11/9 "du Maine" 22/11 "Universite"
aectations 11/11 "Universite" 11/9 "du Maine" 22/12 "Universite "
strcat 11/11 "Universite" 11/9 "du Maine" 22/22 "Universite du Maine"

Remarques

 typeEtst est un tableau (allocation statique) ;

 complement et nomComplet sont des pointeurs, il faut leur allouer de la mémoire dynamiquement ;

 la valeur par défaut d'un pointeur est NULL, elle signie que le pointeur ne pointe sur rien ;

 pour ces trois variables il n'y a pas besoin de l'opérateur & lors des appels à scanf (cf. 2.3.2) ;

 la taille de nomComplet est calculée en fonction des tailles eectives des deux sous chaines (fonction
strlen) ;

 les fonctions de manipulation de chaînes de caractères de la bibliothèque standard tiennent compte


du `\0', par contre il faut bien faire attention lors d'une manipulation directe.

Modication des paramètres des fonctions à l'aide des pointeurs


Lors de l'appel d'une fonction en C, le passage de paramètre se fait  par valeur , c'est en fait
une copie du paramètre, ayant la même valeur que celui-ci, qui est passée à la fonction. Par conséquent
toute modication d'une valeur de paramètre reste  locale  à la fonction, car elle porte sur la copie, la
valeur originale n'est pas modiée. Pour pouvoir eectuer et récupérer une modication il faut utiliser
l'accès indirect .
Dans ce cas-là il faut :

 dans de la dénition de la fonction : au lieu d'utiliser une variable de type T, utiliser une variable
de type  pointeur de T , et modier le corps de la fonction pour utiliser l'accès indirect à la
variable ;

 à l'appel de la fonction utiliser l'adresse de (ou un pointeur sur) le paramètre à modier. Toute
modication sur le pointeur restera locale, mais, grâce à l'accès indirect, la modication de la
variable pointée sera récupérée par l'appelant.
Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998
2.3 Structure de données en C 41

Exemple
explMdfParFct.c

1 #include<stdio . h>
2
3 void ajouter5 ( int  ptrEnt )
4 f
5  ptrEnt += 5 ;
6 g
7
8 int main( void )
9 f
10 int i = 10 , ptrEnt = & i ;
11
12 ajouter5 ( ptrEnt ) ;
13 p r in t f ( " Nouvelle valeur : %d ( acces d ir e c t ), %d ( acces in d ir e c t ) n n" , i ,  ptrEnt ) ;
14
15 /  plus simple : u t i l i s e r l ' adresse de i ( pointeur sur i )  /
16 ajouter5 (& i ) ;
17 p r in t f ( " Nouvelle valeur : %d n n" , i ) ;
18 g

2.3.3 Enregistrements
Dénition
Un enregistrement est un regroupement de variables de types simples (int, char, float, etc.) ou
composés (tableau, enregistrement, etc.).
Syntaxe
struct {
type1 nom1;
type2 nom2;
...
typen nomn;} nomEnr;
Dénit un enregistrement nomEnr dont chaque membre (ou champ ) nomi est de type typei.
L'opérateur `.' permet d'accéder à un membre de l'enregistrement :
nomEnr.nomi
désigne le membre nomi (de type typei) de l'enregistrement nomEnr.
1 struct f
2 char nom[ 30 ] ; /  imbrication de types composés  /
3 int age ;
4 float poids ;
5 g personne1 ;
6
7 struct f
8 char nom[ 30 ] ;
9 int age ;
10 float poids ;
11 g personne2 ;
12 ...
13 strcpy ( personne1 . nom , ` ` Dupont ' ' ) ; /  a t t e n t i o n au type de la données manipulée :  /
14 /  nom de type char [ 30 ]  /
15 personne1 . age = 42 ;
Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998
42 Chapitre2. Le langage C

16 strcpy ( personne2 . nom, personne1 . nom) ;


17 personne2 . age = 18 ;
Exemple
Modèle d'enregistrement
Pour ne pas avoir à répéter la déclaration pour tout enregistrement semblable on peut utiliser un
modèle d'enregistrement ou, mieux, la dénition de type (cf. 2.3.4). Une déclaration de la forme :

struct modeleEnr {
type1 nom1;
...
typen nomn;};
dénit un modèle modeleEnr qui sert à dénir/déclarer des instances (variables) de l'enregistrement
avec une syntaxe semblable à celle de la dénition/déclaration d'une variable de type simple :

struct modeleEnr nomEnr [, nomEnr];

2.3.4 Types et dénition de type


En plus de la notation syntaxique (cf. 2.1.2), un type est déni par le domaine des valeurs et les
opérations applicables aux valeurs et aux variables du type. De ce point de vue :
 un type simple est l'un des types dénis par le langage (int, char, float, etc.) ;
 un type composé (tableau, enregistrement, etc.) est déni par combinaison de variables de types
simples ou composés.
Pour simplier on peut dire qu'un type simple est un type dont les opérations sont dénies par le
langage. La composition utilise un constructeur parmi les suivants :
 * pour les pointeurs ;
 [ ] pour les tableaux ;
 ( ) pour les fonctions ;
 struct pour les structures ;
 union pour les unions.
Une composition (ou un constructeur) introduit des opérations permettant de retrouver les com-
posants, comme l'indirection pour les pointeurs, l'indexage pour les tableaux et la sélection pour les
enregistrements et les unions. Mais, dans le cas général elle ne dénit aucune autre opération sur le
type. Par exemple la dénition d'un tableau d'entiers ne donne pas lieu à la dénition d'une opération
d'addition de tableau d'entiers.
Une dénition de type permet d'alléger l'écriture et améliorer la lisibilté du code en dénissant une
sorte de raccourci pour des compositions plus ou moins complexes.

Syntaxe
typedef defType nomType
Permet de dénir un nouveau type nomType dont le domaine de valeurs est celui de defType qui
peut être simple ou composé. On peut distinguer deux cas de gure :
 defType est un type simple : le nouveau type possède les mêmes opérations, mais c'est au déve-
loppeur de s'assurer de leurs bon usage. Par exemple après la déclaration :
typedef int Bool;
on peut additionner des booléens, ce qui ne correspond pas à la dénition habituelle de ce type.
 defType est un type composé : on dispose des opérations sur les membres (si elles sont dénies)
mais pas nécessairement sur le nouveau type. Par exemple on peut eectuer des aectations d'enre-
gistrements mais pas de comparaisons. Dans le cas des tableaux ni l'aectation ni les comparaisons
ne sont autorisées. C'est donc au programmeur de dénir ses propres opérations.
Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998
2.3 Structure de données en C 43

Exemple
1 / D é f i n i t i o n s /
2 /  D é f i n it io n du type ( enregistrement ) pour l e s nombres complexes  /
3 typedef struct f
4 float r e e l , imag ;
5 g complexe ;
6
7 /  D é f i n it io n et i n i t i a l i s a t i o n de deux complexes  /
8 complexe z , z1 = f 1 . , 1 . g , z2 = f 1 ., 1 . g ;
9
10 /  Pour additionner deux complexes i l faut opérer sur l e s deux
11 membres de la s t r u c t u r e  /
12
13 /  I n s t r u c t i o n s  /
14 /  Addition  d i r e c t e   /
15 z . r e e l = z1 . r e e l + z2 . r e e l ;
16 z . imag = z1 . imag + z2 . imag ;
17
18 /  opération d ' addition d é f i n i r une fonction  /
19
20
21 complexe addition ( complexe z1 , complexe z2 )
22 f
23 complexe res ;
24
25 res . r e e l = z1 . r e e l + z2 . r e e l ;
26 res . imag = z1 . imag + z2 . imag ;
27
28 return ( res ) ;
29 g
30 ...
31 z = addition ( z1 , z2 ) ;
2.3.5 Structures autoréférentielles
Une structure autoréférentielle (ou structure récursive ) est une structure de données 2 qui permet
de faire référence à une autre structure de même type (voir gures 2.1 et 2.2).
Comme les tableaux d'enregistrements, ce type de structure est utilisé pour l'organisation de données
de même nature. Il présente des avantages dont la facilité d'insertion et de supression d'éléments (cf.
gure 2.3) ainsi que la possibilité de référencer plus d'un élément, comme dans le cas des arbres bi-
naires (cf. 3.10)). Par contre, toujours comparativement aux tableaux, il ne supporte pas de mécanisme
équivalent à l'indexage .
11111
00000 11111
00000
00000
11111 00000
11111
00000
11111 00000
11111
00000
11111 00000
11111
00000
11111 00000
11111
00000
11111 00000
11111
T 00000
11111 00000
11111
00000
11111 00000
11111
00000
11111 00000
11111
00000
11111
&enr2 00000
11111
NULL
00000
11111 00000
11111
T* 00000
11111 00000
11111
T enr1 T enr2
Fig. 2.1  Représentation schématique d'une
Fig. 2.2  Enchaînement de structures autoré-
structure autoréférentielle férentielles
Le programme suivant dénit la structure autoréférentielle struct compteMot qui, en plus du poin-
teur, contient deux chmaps mot et cpt. Un tel enregistrement peut servir par exemple au comptage des
mots dans un texte non connu à l'avance : un nouvel enregistrement est créé, initialisé et inséré dans la
liste. Sinon il sut d'incrémenter le compteur de l'enregistrement correspondant au mot.
L'exemple utilise une fonction d'achage et montre les opérations d'enchaînement et les deux modes
d'accès (équivalents !), direct et indirect, à un enregistrement de la liste. Des manipulations plus avancées
2. Les enregistrements, appelés  structures  en C, sont le meilleur (le seul?) moyen pour implanter les structures
autoréférentielle, mais il ne faut pas les confondre avec la notion générale de structure de données qui désigne toute
entités permettant une organisation particulière des données, comme les tableaux d'enregistrements et les structures
autoréférentielles.

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


44 Chapitre2. Le langage C
11111
00000 11111
00000 11111
00000 11111
00000
00000
11111 00000
11111 00000
11111 00000
11111
00000
11111 00000
11111 00000
11111 00000
11111
00000
11111 00000
11111 00000
11111 00000
11111
00000
11111 00000
11111 00000
11111 00000
11111
00000
11111 00000
11111 00000
11111 00000
11111
00000
11111 00000
11111 00000
11111 00000
11111
00000
11111 00000
11111 00000
11111 00000
11111
00000
11111 00000
11111 00000
11111 00000
11111
00000
11111
&enr2 00000
11111
NULL 00000
11111
&enr3 00000
11111
NULL
00000
11111 00000
11111 00000
11111 00000
11111
00000
11111 00000
11111 00000
11111 00000
11111
T enr1 T enr2 T enr1 T enr2
11111
00000 11111
00000
00000
11111 00000
11111
00000
11111 00000
11111
00000
11111 00000
11111
00000
11111 00000
11111
00000
11111 00000
11111
00000
11111 00000
11111
00000
11111 00000
11111
00000
11111 00000
11111
00000
11111
NULL 00000
11111
&enr2
00000
11111 00000
11111
00000
11111 00000
11111
T enr3 T enr3

Avant Après

Fig. 2.3  Insertion d'un élément dans une liste chaînée.

sont présentées dans les sections sur les listes chaînées (cf. 3.8) et les arbres binaires (cf. 3.10).

strucRcrsv.c

1 #include < stdio . h>


2
3 struct compteMot f
4 char  mot;
5 int cpt ;
6 struct compteMot  motSuivant ;
7 g;
8
9 struct compteMot cm1=f" Bonjour " , 1 , NULLg , cm2 = f "Monde" , 1 , NULLg , cm3;
10
11 int main( void )
12 f
13 void afficheCompteMot ( struct compteMot cm) ; /  d e c l a r a t i o n l o c a l e  /
14
15 cm1. motSuivant = &cm2; /  enchaine cm2 a cm1 /
16 cm2. motSuivant = &cm3; /  enchaine cm3 a cm2 /
17
18 afficheCompteMot ( cm1) ;
19 afficheCompteMot ( cm2) ;
20 cm3. mot = ( char  ) malloc ( 10  sizeof ( char ) ) ; /  acces d i r e c t a cm3. mot  /
21 strcpy ( cm3. mot, "Au r e vo ir " ) ;
22 cm2. motSuivant >cpt = 1 ; /  ou  ( cm2. motSuivant ). cpt : /
23 / acces i n d i r e c t a cm3. cpt . /
24 afficheCompteMot (  ( cm2. motSuivant ) ) ; /  element enchaine a cm2 : cm3  /
25 g
26
27 void afficheCompteMot ( struct compteMot cm)
28 f
29 p r in t f ( " Nombre d ' occurrences de %s : %d n n" , cm. mot, cm. cpt ) ;
30 g

Comme on l'a déjà vu dans d'autres cas, une dénition de type permet de simplier l'écriture. Une
version améliorée du programme précédent peut par exemple avoir le chier d'en-tête suivant.
Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998
2.4 Accès aux chiers 45
strucRcrsvType.h

1 typedef struct comptMot f


2 char  mot;
3 int cpt ;
4 struct comptMot  motSuivant ;
5 g typeCompteMot;
6
7 /  Permet d ' u t i l i s e r typeCompteMot au l i e u de s t r u c t comptMot , par exemple :
8 typeCompteMot cm1=f"Bonjour ", 1 , NULLg , cm2 = f " Monde ", 1 , NULLg , cm3;
9
10 Voir aussi la d e c l a r a t i on suivante .
11 /
12
13 void afficheCompteMot ( typeCompteMot cm) ;

2.3.6 Unions
2.4 Accès aux chiers
2.4.1 Introduction
À l'exécution d'un programme le noyau d'Unix associe au processus (cf. 1.7) correspondant deux
chiers : l'entrée standard (par défaut le clavier) et la sortie standard (par défaut l'écran). Les ltres
(cf. 1.5.3) sont l'illustration typique de l'utilisation de ces deux chiers.
Tous les programmes C présentés jusqu'à présent n'utilisent que ces deux chiers. Cette section
présente la manipulation des chiers normaux (cf. 1.4.2).
2.4.2 Fonctions de manipulation de chiers
Un chier normal (ou ordinaire) est l'unité minimal de stockage sur un support permanent. Les
chiers sont gérés par le système d'exploitation (cf. 1.4) auquel il faut faire appel pour manipuler les
chiers dans un programme.
Pour accéder à un chier un programme doit d'abord l'ouvrir à l'aide de la fonction de la bibliothèque
standard fopen :
#include <stdio.h>
FILE *fopen(const char *nomFichier, const char *modAcces);

Un appel à cette fonction établit une liaison entre le nom externe (nomFichier, connu par le système)
et le programme grâce au pointeur de chier qu'elle retourne et qui doit être utilisé pour tout accès
au chier. En eet le pointeur pointe une structure de données (de type FILE, déni dans stdio.h),
dérivée de l'i-node (cf. 1.4.1) du chier, qui contient les informations nécessaires à sa manipulation.
modAcces est une chaîne de caractères qui indique les autorisations d'accès demandées : r pour la
lecture, w pour l'écriture et a pour l'ajout (écriture en n de chier sans écraser le début).
En cas d'erreur (chier inexistant, autorisations refusée, etc.) la fonction retourne NULL.
Il existe plusieurs groupes de fonctions de la bibliothèque standard pour lire ou écrire dans un chier
en C 3. Les deux fonctions fscanf et fprintf sont identiques à scanf et printf sauf qu'elles prennent
un pointeur de chier comme premier argument :
int fscanf(FILE *ptrFich, const char *format, ...);

int fprintf(FILE *ptrFich, const char *format, ...);

En eet l'appel scanf("...", ...) est équivalent à fscanf(stdin, "...", ...), stdin étant un
pointeur constant de type FILE *, déni dans stdio.h et qui désigne le chier entrée standard . De
3. Toutes les fonctions décrites ici sont déclarées dans le chier stdio.h.

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


46 Chapitre2. Le langage C

la même manière, printf("...", ...) est équivalent à fprintf(stdout, "...", ...), où stdout
désigne la sortie standard .
Les deux fonctions suivantes permettent respectivement de lire et d'écrire un seul caractère à la fois :
int getc(FILE *ptrFich);

int putc(int c, FILE *ptrFich);

getc retourne la valeur constante EOF, dénie dans stdio.h, lorsque la n de chier est atteinte ou en
cas d'erreur.
2.4.3 Exemple
Le programme suivant simule la commande cat qui ache à l'écran (stdout) les contenus des chiers
donnés en arguments (stdin par défaut).
mCat.c

1 #include < stdio . h>


2
3 int main ( int argc , char  argv [ ])
4 f
5 FILE  ptrFich ;
6 void copierFich ( FILE  pfsrc , FILE  pfdst ) ;
7
8 if ( argc == 1 ) /  pas d ' args : copie de l ' entree standard  /
9 copierFich ( stdin , stdout ) ;
10 else
11 while ( argc > 0 )
12 if ( ( ptrFich = fopen (++ argv , " r " )) == NULL)
13 f
14 p r in t f ("%s : impossible d ' ouvrir %s n n" ,  argv ) ;
15 return ( 1 ) ;
16 g
17 else
18 f
19 copierFich ( ptrFich , stdout ) ;
20 f c lo s e ( ptrFich ) ;
21 g
22 g
23
24 void copierFich ( FILE  pfsrc , FILE  pfdst )
25 f
26 int c ;
27
28 while ( ( c = getc ( pfsrc ) ) != EOF)
29 putc ( c , pfdst ) ;
30 g

2.5 La compilation Séparée


2.5.1 Production de programme exécutable
La production d'un programme exécutable à partir d'un programme source passe par plusieurs étapes :
Pré-traitement: (spécique au langage C) exécution des directives du pré-processeurs (#include,
#define, etc.). Il s'agit d'un simple traitement de texte, presque aucune vérication n'est eectuée.

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


2.5 La compilation Séparée 47

Compilation: comporte deux sous-phases principales :

 vérication de la syntaxe : mots-clefs, instruction du langage, bonnes déclarations et utilisa-


tions des variables et des fonctions, etc. ;
 génération du code objet (code en langage machine non exécutable puisqu'incomplet, noram-
lement ces chiers ont le suxe .o) ;

Édition des liens (link ): assemblages des morceaux du programme (les codes objets), y compris les
fonctions utilisées de la bibliothèque standard , et résolution des références.

stdio.h prog.c
#define ... #include<stdio.h>
.... #include"mesFoncs.h"
#define N 10
....
i = N;

Précompilateur (cpp)

int printf(...);
....
i = 10;

Compilateur
"stdio"
Code Objet

Éditeur de liens

Exécutable

Fig. 2.4  Phases de production d'un programme exécutable

2.5.2 Utilisation de la compilation Séparée


Il est possible (recommandé ou impératif, selon la taille du logiciel) de découper un programme en
plusieurs morceaux. Conceptuellement ce découpage doit être modulaire (cf. 4.4). En C un module doit
être implanté à l'aide de deux chiers :

 les dénitions dans un chier source (.c) ;

 les déclarations des variables et fonctions exportées (utilisables par d'autres modules) dans un
chier d'en-tête (.h).

Dans la pratique :

 un module utilisant les fonctions et/ou les variables d'un autre module doit  inclure  le chier
d'en-tête de celui-ci (pour avoir les déclarations) ;

 les modules peuvent être compilés séparément. L'option -c du compilateur permet de s'arrêter
après la phase de compilation en générant le chier objet (.o) correspondant ;

 pour obtenir l'exécutable il faut assembler l'ensembles des chiers objets (.o) par l'édition des
liens ;
Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998
48 Chapitre2. Le langage C

2.5.3 Exemple

Code source  implantations (*.c)

identite.c

1 /  Fichier : i d e n t i t e . c
2  Description : contient une seule fonction , a f f i c h a g e d ' un message d ' i d e n t i f i c a t i o n .
3  Auteur : Mamoun ALISSALI
4  Historique :
5  Creation : Tue Feb 08 15 : 48 : 43 WET 1994
6 /
7 #include < stdio . h>
8 #include " id e n t it e . h"
9
10 int a f f ic h e Id ( const char  message , int id )
11 / 
12  afficheIdimprimeMessage : imprime ses deux argument sur la s o r t i e standard .
13  Entree : l e s arguments a imprimer : un tableau de char , et un int .
14  Retour : TRUE si OK, FALSE sinon .
15  /
16 f
17 if ( f p r i n t f ( stdout , "%s : %dn n" , message , id ) < 0 ) return (FALSE) ;
18 return (TRUE) ;
19 g /  END a f f i c h e I d  /
20

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


2.5 La compilation Séparée 49
principal.c

1 /  Fichier : p r i n c i p a l . c
2  Description : module p r i n i c i p a l de progC qui a f f i c h e d i v e r s e s
3  i d e n t i f i c a t i o n s . progC sert d ' exemple a la creation d ' un programme C
4  sous Unix .
5  Auteur : Mamoun ALISSALI
6  Historique : Creation . Tue Feb 08 15 : 40 : 52 WET 1994
7  A FAIRE : Completer traitement des erreurs .
8 /
9 #include < unistd . h>
10 #include < sys / types . h>
11 #include < s t d lib . h>
12 #include < stdio . h>
13 #include " id e n t it e . h"
14 #include " p r in c ip a l . h"
15
16 int main( int argc , char  argv [ ])
17 / 
18  main : a p p e l l e a f f i c h e I d pour i d e n t i f i e r l ' u t i l i s a t e u r , son groupe ,
19  le processus courant et son pere .
20  Retour : 0 si OK, 1 si erreur d ' imperssion , 10 argc i n c o r r e c t .
21  /
22 f
23 if ( argc != 1)
24 f
25 f p r i n t f ( stderr , " U t ilis a t io n : %s n n" , argv [ 0 ] ) ;
26 exit ( 10 ) ;
27 g /  END IF  /
28
29 f p r i n t f ( stdout , "Programme : %s n n" , argv [ 0 ]) ;
30
31 if ( ! a f f ic h e Id ( " je suis l ' u t i l i s a t e u r " , getuid ( ) ) ) exit ( 1 ) ;
32 if ( ! a f f ic h e Id ( "mon groupe est " , getgid ( ) ) ) exit ( 1 ) ;
33 if ( ! a f f ic h e Id ( " je suis le processus " , getpid ( ) ) ) exit ( 1 ) ;
34 if ( ! a f f ic h e Id ( "mon pere est le processus " , getppid ( ) ) ) exit ( 1 ) ;
35
36 exit ( 0 ) ;
37 g /  END main  /
38
39 /  __EOF__  /
40

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


50 Chapitre2. Le langage C

Code source  interfaces (*.h)

identite.h

1 #ifndef IDENTITE_H
2 #define IDENTITE_H
3
4 #define FALSE 0
5 #define TRUE 1
6
7 extern int a f f ic h e Id ( const char  msg, int id ) ;
8
9 #endif /  IDENTITE_H  /
10

principal.h

1 #ifndef PRINCIPAL_H
2 #define PRINCIPAL_H
3
4 #endif /  PRINCIPAL_H  /
5

Production de l'exécutable
Précompilation
1 {61} : cpp src/identite.c > src/tmp.c
2 cpp: Error: src/identite.c: 8: Cannot open file identite.h for #include
3 {62} : cpp -Iinclude src/identite.c > src/tmp.c
4 {63} : ls -l src
5 total 10
6 -rw-r--r-- 1 alissali thesardls 617 Feb 11 11:41 identite.c
7 -rw-r--r-- 1 alissali thesardls 1112 Feb 11 11:39 principal.c
8 -rw-r----- 1 alissali thesardls 6990 Feb 11 11:49 tmp.c
9
10 {64} : cat src/tmp.c
11 [...]
12 extern FILE _iob[8];
13 [...]
14 extern int fprintf();
15 [...]
16 # 8 "src/identite.c"
17 # 1 "include/identite.h"
18 [...]
19 extern int afficheId(const char *msg, int id);
20 [...]
21 # 9 "src/identite.c"
22
23 int
24 afficheId(const char *message, int id)
25
26 {
27 if(fprintf((&_iob[1]),"%s : %d\n", message,id) < 0 ) return(0);
28 return(1)

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


2.5 La compilation Séparée 51

29 }
30
31 {65} : grep stdout /usr/include/stdio.h
32 #define stdout (&_iob[1])
33 [...]
34 {66} : !cpp:p
35 cpp -Iinclude src/identite.c > src/tmp.c
36 {67} : !!:s/-I/-D__STDC__ -D_POSIX_SOURCE -I/
37 cpp -D__STDC__ -D_POSIX_SOURCE -Iinclude src/identite.c > src/tmp.c
38 {68} : ls -l src
39 total 11
40 -rw-r--r-- 1 alissali thesardls 617 Feb 11 11:41 identite.c
41 -rw-r--r-- 1 alissali thesardls 1112 Feb 11 11:39 principal.c
42 -rw-r----- 1 alissali thesardls 4881 Feb 11 12:20 tmp.c
43
44 {69} : cat src/tmp.c
45 [...]
46 extern int fprintf(FILE *, const char *, ...);
47 [...]

Compilation
A. Vérication de la syntaxe

1 {94} ~/Unix/Compilation/src : cc -c tmp.c


2 /usr/lib/cmplrs/cc/cfe: Error: identite.c, line 19: Syntax Error
3 return(1);
4 --^

B. Génération du code  objet 

1 On relance la compilation apres la correction de l'erreur de syntaxe


2
3 {96} ~/Unix/Compilation/src : cc -c tmp.c
4 {97} ~/Unix/Compilation/src : ls -l
5 -rw-r--r-- 1 alissali thesardls 24821 Feb 08 16:47 a.out
6 -rw-r--r-- 1 alissali thesardls 618 Feb 08 16:44 identite.c
7 -rw-r--r-- 1 alissali thesardls 1011 Feb 08 16:26 principal.c
8 -rw-r--r-- 1 alissali thesardls 7272 Feb 08 16:46 tmp.c
9 -rw-r--r-- 1 alissali thesardls 2768 Feb 08 16:46 tmp.o

Édition des liens


1 {98} ~/Unix/Compilation/src : cc tmp.o
2 ld:
3 Unresolved:
4 main
5 {99} ~/Unix/Compilation/src : cc -c -I../include principal.c
6 {100} ~/Unix/Compilation/src : ls -l
7 total 47
8 -rw-r--r-- 1 alissali thesardls 24821 Feb 08 16:47 a.out
9 -rw-r--r-- 1 alissali thesardls 618 Feb 08 16:44 identite.c
10 -rw-r--r-- 1 alissali thesardls 1011 Feb 08 16:26 principal.c
11 -rw-r--r-- 1 alissali thesardls 6008 Feb 08 16:50 principal.o
12 -rw-r--r-- 1 alissali thesardls 7272 Feb 08 16:46 tmp.c
13 -rw-r--r-- 1 alissali thesardls 2768 Feb 08 16:46 tmp.o
14
15 {101} ~/Unix/Compilation/src : cc principal.o tmp.o
16 {102} ~/Unix/Compilation/src : ls -l

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


52 Chapitre2. Le langage C

Module principal Module identite

principal.h identite.h
#ifndef ... #ifndef ...
#define #define

include int afficheId(...);

#endif #endif
principal.c identite.c

#include"identite.h" #include"identite.h"
#include"principal.h"
src
int main(...)
{ int afficheId(...)
... {
afficheId(...); ...
... }
}

Précompilation

int afficheId(...); int afficheId(...);


...
int main(...)
{ fichiers
temporaires int afficheId(...)
... {
afficheId(...); ...
... }
}

Fig. 2.5  Précompilation des deux modules de l'exemple.

17 total 49
18 -rwxr-xr-x 1 alissali thesardls 26720 Feb 08 16:51 a.out
19 -rw-r--r-- 1 alissali thesardls 618 Feb 08 16:44 identite.c
20 -rw-r--r-- 1 alissali thesardls 1011 Feb 08 16:26 principal.c
21 -rw-r--r-- 1 alissali thesardls 6008 Feb 08 16:50 principal.o
22 -rw-r--r-- 1 alissali thesardls 7272 Feb 08 16:46 tmp.c
23 -rw-r--r-- 1 alissali thesardls 2768 Feb 08 16:46 tmp.o

Exemples d'exécution
1 {97} bin/progC
2 Programme : bin/progC
3 je suis l'utilisateur : 10396
4 mon groupe est : 1010
5 je suis le processus : 1633
6 mon pere est le processus : 1210
7 {98} !!
8 bin/progC
9 Programme : bin/progC
10 je suis l'utilisateur : 10396
11 mon groupe est : 1010
12 je suis le processus : 1634
13 mon pere est le processus : 1210
14 {99} bin/progC1
15 Programme : bin/progC1
16 je suis l'utilisateur : 10396
17 mon groupe est : 1010
18 je suis le processus : 1635
19 mon pere est le processus : 1210

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


2.5 La compilation Séparée 53

Compilation

Vérification correction
de la syntaxe des erreurs

Référence/appel Code « objet »


de « afficheId » fichiers de « afficheId »
temporaires
ou
permanents

Édition des liens

Exécutable

Fig. 2.6  Compilation et d'édition des lien des deux modules de l'exemple.

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


54 Chapitre2. Le langage C

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


Chapitre 3

Algorithmique et structures de données


avancées
3.1 Fondements et principes de l'algorithmique
Dénition 3.1.1 Un algorithme est une séquence bien dénie d'opérations (calcul, manipulation de
données, etc.) permettant d'accomplir une tâche en un nombre ni de pas.
En principe un algorithme est indépendant de toute implantation. Cependant dans la pratique de
la programmation il s'avère indispensable de tenir compte des capacités du langage de programmation
utilisé.

3.1.1 Éléments de conception d'algorithmes


La conception (et la vérication) d'un algorithme passe par les étapes suivantes :
Analyse: dénition du problème en termes de séquences d'opérations de calcul de stockage de données,
etc.;
Conception: dénition précise (proche du langage de programmation) des données, des traitements
et de leur séquencement ;
Implantation: traduction et réalisation de l'algorithme dans le langage cible ;
Test : vérication du bon fonctionnement de l'algorithme.

3.2 Exemple: calcul de la somme des N premiers entiers positifs


3.2.1 Analyse
1 Determiner N
2 Calculer la somme des N premiers entiers positifs
3 Renvoyer du résultat
Premier ranement :
1 lire N
2 boucle sur les N premiers entiers positifs
calcul de la somme
3 acher somme
Deuxième ranement
2 somme < 0
pour i < 1 à N
somme < somme + i
55
56 Chapitre3. Algorithmique et structures de données avancées

3.2.2 Conception
1 entier N, i , somme
2 écrire " Donner N"
3 lire somme
4
5 si N $ n leq$ 0 alors ERREUR
6 pour i < 1 à N faire
7 somme < somme + i
8 écrire " La somme est :a : " somme
9

3.2.3 Implantation

sommeNentiers.c

1 #include<stdio . h>
2
3 int main( void )
4 f
5 int n , i , somme = 0 ;
6
7 p r in t f ( "Donner n : n n" ) ;
8 scanf ("%d" , & n ) ;
9 if ( n <= 0 )
10 f
11 p r in t f ( " n doit etre > 0 ! n n" ) ;
12 return ( 1 ) ; /  code erreur  /
13 g
14 for ( i = 1 ; i <=n ; i ++)
15 somme += i ;
16 p r in t f ( "Somme : %d n n" , somme) ;
17 return ( 0 ) ; /  bon fonctionnement  /
18 g
19

3.2.4 Test
<harpo.alissali: 63>sommeNentiers
Donner n :
-1
n doit etre > 0 !
<harpo.alissali: 64>!!
sommeNentiers
Donner n :
7845
Somme : 30775935
<harpo.alissali: 65>!!
sommeNentiers
Donner n :
1
Somme : 1

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


3.3 Pratique du développement d'algorithmes 57

3.3 Pratique du développement d'algorithmes


 Procéder par ranements successifs, en particulier pour la phase d'analyse, en précisant les élé-
ments manquants ou ambigus de l'énoncé. Dans le cas de l'exemple :
 s'agit-il d'une interaction avec l'utilisateur ou d'une fonction?
 peut-on utiliser le théorème permettant d'obtenir directement le résultat?
 à cause de l'éventuelle complexité du processus, il est souvent nécessaire de faire des retours en
arrière pour corriger ou compléter la phase en cours ou une phase précédente. Dans tous les cas
de gure il faut veiller à bien maintenir la cohérence ;
 prévoir les erreurs de calcul et d'utilisation (ne fait pas vraiment partie de l'algorithme)
 il faut vérier le bon fonctionnement de l'algorithme dans tous les cas de gure. Il existe plusieurs
façons de procéder :
 preuve mathématique : moyen le plus sûr mais assez dicile à mettre en ÷uvre ;
 test de tous les cas de gure : preuve  pratique  du bon fonctionnement, mais trop long
(voire impossible) à mettre en ÷uvre ;
 test de tous les chemins logiques, des conditions limites et des cas d'erreur. Dans le cas de
l'exemple :
 N  0;
 plusieurs valeurs  valables  de N ;
 N =1 ;
 N = INT_MAX.

3.4 Notion de complexité d'algorithme


Dénition 3.4.1 La complexité d'un algorithme exprime ce dont il a besoin en ressources pour aboutir
au résultat. Elle est normalement fonction de la taille des données manipulées et se chire en nombre
d'opérations (temps de calcul), en taille des données (mémoire vive) et éventuellement mémoire morte
(stockage secondaire : disque, etc.) ;
Dans l'exemple précédent les ressources nécessaires sont :
Données : 3 entiers
Opérations (en cas de bon fonctionnement) :
avant la boucle 1 opération de test
dans la boucle (N fois) : 1 incrémentation, 1 addition, 1 aectation
pour terminer la boucle : 1 test
total : N+2 tests, N incrémentations, N additions et N aectations.
Dans la pratique :
 seul l'ordre de grandeur du nombre d'opérations, noté O(.), est utilisé pour exprimer la complexité.
On dira que l'algorithme de l'exemple est de complexité O(N).
 les opérations qui, relativemnt aux autres, consomment peu de temps, telles que les tests, les
aectations et les incrémentations ne sont pas comptabilisées ;
 les opérations ne faisant pas partie de l'algorithme, comme les E/S (scanf et printf) ne sont pas
comptabilisées ;
 selon l'algorithme la complexité peut varier en fonction des données. Dans ce cas il faut calculer
la complexité minimale, maximale et moyenne (somme de tous les cas possibles/nombre des cas).

3.5 Algorithmes de recherche dans un tableau


Objectif: recherche d'un élément dans un tableau.
Les algorithme qui suivent portent sur les entiers. Ils sont généralisables aux autres types de données
simples (réels, caractères, etc.), mais nécessitent des modications pour les types complexs (chaînes de
caractères, enregistrements, etc.).
Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998
58 Chapitre3. Algorithmique et structures de données avancées

3.5.1 Recherche Séquentielle


Analyse
1 parcours s é qu e n t ie l du tableau
2 arrêt lorsque la valeur est trouvé
3 retour l ' indice correspondant
4 la valeur n ' est pas trouvée
5 retour d ' une valeur s p é c ia le
Ranement :
1 Recherche d ' un élément valRech dans un tableau d ' entier tabEnt de t a i l l e N
2 début
3 i< 0
4 tant que i <= N 1 et tabEnt [ i ] != valRech
5 increment i
6 retour ( i )
Conception
1 entier recherch er ( entier valRech , entier tabEnt [ ] , entier tailleTab )
2 entier i = 0
3 début
4 tant que i <= N 1 et tabEnt [ i ] != valRech
5 increment i
6 retour ( i )
7 fin

Implantation et tests
Exercice
Complexité
 données : un tableau de N entiers + 3 entiers
 nombre d'opérations : dépend des données (on considère uniquement les comparaisons)
 meilleur cas : 1 comparaison (complexité O(1)) ;
 pire cas : N comparaisons (complexité O(N)) ;
 moyenne : (1 + 2 + .... + N)/N = N(N+1)/2N = (N+1)/2 (complexite O(N/2)).

3.5.2 Recherche Dichotomique


Principe
 rechercher récursivement dans une moitié du tableau.
 les éléments du tableau sont deux à deux distincts ;
 les éléments du tableau sont rangés dans l'ordre croissant ;
Analyse
1 el :a : élément recherché ,
2 tab :a : tableau ordonné , sans duplicat ion ,
3 mil:a : indice du milieu du tableau ,
4 si el = tab [ mil ] alors trouvé
5 sinon
6 si el < tab [ mil ] alors
7 recherch er dans la $1^f re g $ moitié ( tabEnt [ deb . . mil 1 ])
8 sinon
9 recherch er dans la $2^f e g $ moitié ( tabEnt [ mil+1 . . fin ])
Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998
3.5 Algorithmes de recherche dans un tableau 59

Ranement :
 condition d'arrêt : taille du tableau  1, deux cas :
taille = 0 ) non trouve, taille = 1 ) tester ;
 les limites du tableau (deb et n) sont des arguments de la fonction.
Conception
1 entier rechDicho ( entier valRech , entier tabEnt [ ] , entier deb , entier fin )
2 entier mil = ( deb+fin )/ 2
3 début
4 si deb > fin alors
5 retour NONn_TROUVE
6 si valRech = tabEnt [ mil ] alors
7 retour mil
8 si valRech < tabEnt [ mil ] alors
9 retour rechDicho ( valRech , tabEnt , deb , mil 1 )
10 sinon
11 retour rechDicho ( valRech , tabEnt , mil+1 , fin )
12 fin

Complexité
À chaque étape :
 1 addition, 1 division, entre 1 et 3 tests et un appel récursif.
 division par 2 de de la taille du tableau ) log2 (n) étapes.
Ordre de complexité : O(log2 (n)).
Coût en nombre d'opérations
taille recherche séquentielle recherhce dichotomique
16 8 4
1024 512 10
220 219 20
Implantation

rechDichRec.c

1 int rechDichRec ( int valRech , int tabEnt [ ] , int deb , int fin )
2 f
3 int mil = ( deb+fin )/ 2 ;
4
5 if ( deb > fin ) return ( 1 ) ;
6 if ( valRech == tabEnt [ mil ] ) return mil ;
7 if ( valRech < tabEnt [ mil ])
8 return rechDichRec ( valRech , tabEnt , deb , mil 1 ) ;
9 return rechDichRec ( valRech , tabEnt , mil+1 , fin ) ;
10 g

rechDichRec.h

1 int rechDichRec ( int valRech , int tabEnt [ ] , int deb , int fin ) ;

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


60 Chapitre3. Algorithmique et structures de données avancées
rechDichIt.c

1 int rechDichIt ( int valRech , int tabEnt [ ] , int t a i l l e )


2 f
3 int deb = 0 , fin = t a i l le 1 , mil ;
4
5 while ( deb <= fin )
6 f
7 mil = ( deb+fin )/ 2 ;
8 if ( valRech == tabEnt [ mil ] ) return mil ;
9 if ( valRech < tabEnt [ mil ] ) fin = mil 1 ;
10 else deb = mil+1 ;
11 g
12 return ( 1 ) ;
13 g

rechDichIt.h

1 int rechDichIt ( int valRech , int tabEnt [ ] , int t a i l l e ) ;

Tests
rechDichTest.c

1 #include<stdio . h>
2 #include " rechDichRec . h"
3 #include " rechDichIt . h"
4 int main( void )
5 f
6 int valRech , mil , indice , tabEnt []= f 2 , 6 , 8 , 11 , 17 , 18 , 22 , 45 , 102 g ;
7 do f
8 p r in t f ( " valeur recherhcee ? n n" ) ;
9 scanf ("%d" , & valRech ) ;
10 if ( valRech != 1 ) f
11 p r in t f ( " rechDichRec :" ) ;
12 indice = rechDichRec ( valRech , tabEnt , 0 , 8 ) ;
13 if ( indice == 1 ) p r in t f ( " valeur non trouvee n n" ) ;
14 else p r in t f ( " valeur trouvee a l ' indice %d n n" , indice ) ;
15 p r in t f ( " rechDichIt :" ) ;
16 indice = rechDichIt ( valRech , tabEnt , 9 ) ;
17 if ( indice == 1 ) p r in t f ( " valeur non trouvee n n" ) ;
18 else p r in t f ( " valeur trouvee a l ' indice %d n n" , indice ) ;
19
20 g
21 g while ( valRech != 1 ) ;
22 g
Pour une validation minimale de l'algorithme, on peut par exemple eectuer le test dans les cas

suivants :
 limites du tableau : 2 et 102 ;
 milieu du tableau : 11, 17, 18 ;
Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998
3.6 Algorithmes de tri de tableau 61

 valeurs n'appartenant pas au tableau.

3.6 Algorithmes de tri de tableau


Objectif: réarranger les éléments d'un tableau dans l'ordre croissant ou décroissant pour rendre
plus ecaces les opérations de recherche et, par conséquent, d'insertion, de suppression, etc.

3.6.1 Tri direct

Principe
1 Ranger le premier élément
2 Trier le r e s t e du tableau
Analyse
1.1. Rechercher le plus petit élément : ppe
1.2. Permuter avec le premier élément du tableau
2. Trier le tableau à partir de l'élément suivant Données:
1 Entrées :a : tableau à t r i e r tabEnt ,
2 t a il l e du tableau ,
3 indice du premier élément à t r a i t e r .
4 S o r t ie s :a : tableau t r ié
5 Locales :a : plus p e t it élément et son indice
Traitement:
1 1 . 1 . boucle :a : trouver ppe
2 1 . 2 . permuter ppe et 1er élément
3 2 . t r i e r à p a r t ir de l ' élément suivant

Conception
1 n la b e l f :a a l g :triDirect :triDirectg
2 entier t r iDir e c t ( entier tabEnt [ ] , entier t a i l l e , entier indDeb )
3 entier ppe , indppe , ;a i ; ;
4 début
5 ppe < tabEnt [ indDeb ]
6 pour i < indDeb+1 à t a i l l e 1 faire
7 début
8 si ppe > tabEnt [ i ] alors
9 début
10 indppe < i
11 ppe < tabEnt [ i ]
12 fin
13 fin
14
15 si ppe $ n neq$ tabEnt [ i ] alors
16 permuter ( indppe , i )
17
18 si indDeb < t a i l l e 1 alors
19 t r iDir e c t ( tabEnt , t a i l l e , indDeb + 1)
20 fin
Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998
62 Chapitre3. Algorithmique et structures de données avancées

Implantation

permuter.c

1 #include " permuter . h"


2
3 void permuter ( int tabEnt [ ] , int ind1 , int ind2 )
4 f
5 int tmp;
6
7 tmp = tabEnt [ ind1 ] ;
8 tabEnt [ ind1 ] = tabEnt [ ind2 ] ;
9 tabEnt [ ind2 ] = tmp;
10 g

permuter.h

1 void permuter ( int tabEnt [ ] , int ind1 , int ind2 ) ;

triDirectRec.c

1 #include " permuter . h"


2
3 int triDirectRe c ( int tabEnt [ ] , int t a i l l e , int indDeb )
4 f
5 int ppe , indppe , i ;
6
7 ppe = tabEnt [ indDeb ] ;
8
9 for ( i = indDeb+1 ; i < t a i l l e ; i ++)
10 if ( ppe > tabEnt [ i ])
11 f
12 indppe = i ;
13 ppe = tabEnt [ i ] ;
14 g
15
16 if ( ppe != tabEnt [ indDeb ] ) permuter ( tabEnt , indppe , indDeb ) ;
17
18 if ( indDeb < t a i l l e 1 ) triDirect Re c ( tabEnt , t a i l l e , indDeb + 1 ) ;
19 g

triDirectRec.h

1 int triDirectRe c ( int tabEnt [ ] , int t a i l l e , int indDeb ) ;

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


3.6 Algorithmes de tri de tableau 63

Test
triDirectTest.c

1 #include<stdio . h>
2 #include<s t d lib . h>
3 #include " s a i s i e I n v e r s e . h"
4 #include " a f f ic h e . h"
5 #include " triDirect Re c . h"
6 #define TAILLE 10000
7
8 int main( void )
9 f
10
11 int tab [ TAILLE ] , i , maxRand = TAILLE 10 ;
12 /  = f 22 , 25 , 21 , 10 , 45 , 12 , 53 g ;  /
13
14 for ( i = 0 ; i < TAILLE ; i ++)
15 tab [ i ] = rand () % maxRand;
16
17 /  a f f i c h e ( tab , TAILLE);
18 /
19
20 triDirect Rec ( tab , TAILLE, 0 ) ;
21
22 /  a f f i c h e ( tab , TAILLE);
23 /
24 g

3.6.2 Tri par échange (tri-bulles)


Principe
1. Parcourir le tableau en comparant deux à deux les éléments successifs, permuter s'ils ne sont pas
dans l'ordre
2. Répéter tant que des permutation sont eectuées.
Exemple
Tri de 23 10 75 5 37 49 53

10 23 5 75 37 49 53
10 23 5 37 75 49 53
10 23 5 37 49 75 53
10 23 5 37 49 53 75
10 5 23 37 49 75 53
5 10 23 37 49 75 53
Analyse
1 entier tabEnt [ N] , i , bSup
2 bSup < N 1
3 1 . boucle tant qu ' i l y a des permutations
4 2 . 1 . boucle sur tabEnt [ 0 . . bSup ]
5 2 . 2 . si tabEnt [ i ] > tabEnt [ i+1 ] alors
6 permuter ( tabEnt [ i ] , tabEnt [ i+1 ])
7 décrément bSup
Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998
64 Chapitre3. Algorithmique et structures de données avancées

Ranement
 Après le premier passage (la 1re itération de la boucle extérieure) le plus grand élément se trouve
rangé en haut du tableau, on peut donc l'exclure dans l'itération suivante. Le même raisonnement
s'applique sur les itérations suivantes : à chaque itération on diminue de 1 la taille de la partie à
traiter du tableau.
 Plusieurs élément du  haut  du tableau peuvent se trouver rangés dans l'ordre ; on peut donc
optimiser le traitement en s'arrêtant au dernier élément déplacé de l'itération précédente, ce qui
peut être fait en ajoutant l'instruction :
bSup < indice de la dernière permutation.
Conception
1 Entrées :a : tableau d ' entier tabEnt , entier t a i l l e
2 S o r t ie s :a : tableau t r ié
3 Locales :a : entier i , booléen echange
4
5 bSup < N2
6 boucle
7 début
8 si bSup < 2 alors retour
9 echange < faux
10 pour i < 0 jusqu ' à bSup faire
11 si tabEnt [ i ] > tabEnt [ i+1 ] alors
12 début
13 permuter ( tabEnt [ i ] , tabEnt [ i+1 ])
14 indEchange < i
15 echange < vrai
16 fin
17 fin
18 si non echange alors retour
19 bSup < indEchange
Amélioration
Pour le tableau 10 92 35 50 69 90 95 il sut d'une seule passe (pour faire  remonter
92 ) pour obtenir le résultat :
10 35 50 69 90 92 95
Par contre dans la conguration  symétrique à la précédente  :
10 50 69 90 92 35 95
il faut plusieurs passes :
95 92 35 90 69 50 10
95 92 90 35 69 50 10
95 92 90 69 35 50 10
95 92 90 69 50 35 10
 dans le deuxième tableau il faut faire  descendre  l'élément mal placé ;
 par symétrie au premier cas ceci peut se faire en une seule passe si le parcours s'eectue  de haut
en bas .
Une solution consiste à alterner le sens du parcours. On appelle ce nouvel algorithme Tri-shaker .
1 determiner debut et fin de parcours
2 1 . boucle tant qu ' i l y a des permutations
3 2 . 1 . boucle echange debut . . fin
4 2 . 2 . mise à jour fin
5 3 . 1 . boucle echange fin . . debut
6 3 . 2 . mise à jour debut
Modication de l'analyse Ranement et conception : exercice.
Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998
3.6 Algorithmes de tri de tableau 65

3.6.3 Implatation et test

triBulTab.c

1 #include " permuter . h"


2
3 void triBulTab ( int tab [ ] , int t a i l l e )
4 f
5 int debut=0 , fin =t a i l l e 1 , indEchange , i ;
6
7 do
8 f
9 for ( i=debut ; i <fin ; i ++)
10 if ( tab [ i ] > tab [ i+1 ])
11 f
12 permuter ( tab , i , i+1 ) ;
13 indEchange = i ;
14 g
15 fin = indEchange ;
16
17 for ( i=fin ; i >debut ; i )
18 if ( tab [ i 1 ] > tab [ i ])
19 f
20 permuter ( tab , i , i 1 ) ;
21 indEchange = i ;
22 g
23 debut = indEchange ;
24
25 g while ( debut < fin ) ;
26
27 g

triBulTab.h

1 void triBulTab ( int tab [ ] , int t a i l l e ) ;

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


66 Chapitre3. Algorithmique et structures de données avancées
triBulTest.c

1 #include<stdio . h>
2 #include<s t d lib . h>
3 #include " s a i s i e I n v e r s e . h"
4 #include " a f f ic h e . h"
5 #include " triBulTab . h"
6
7 #define TAILLE 10000
8
9 int main( void )
10 f
11
12 int tab [ TAILLE ] , i , maxRand = TAILLE 10 ;
13 /  = f 22 , 25 , 21 , 10 , 45 , 12 , 53 g ;  /
14
15 for ( i = 0 ; i < TAILLE ; i ++)
16 tab [ i ] = rand () % maxRand;
17
18 /  a f f i c h e ( tab , TAILLE);
19 /
20
21 triBulTab ( tab , TAILLE) ;
22
23 /  a f f i c h e ( tab , TAILLE);
24 /
25 g

Tab. 3.1  Complexité des algorithmes de tri direct [8]


tri par insertion
cas/opération comparaisons déplacements
meilleur n-1 2n-2
moyenne 1 (n2 + 3n 4)
1 (n2 + 7n 8)
4 4
1 (n2 + n 2) 1 (n2 + 3n 4)
pire 4 4
tri par échange
meilleur 2 (n n) 0
1 2
moyenne 1 (n2 n ) 3 (n2 n)
2 4
pire 1 (n2 n )
3 (n2 n)
2 2

3.6.4 Tri par séparation (tri rapide)


Principe
1. Ranger un élément quelconque, el, du tableau ;
2. ranger dans deux parties séparées les éléments inférieures et supérieures à el ;
3. répéter sur chacune des deux parties tant qu'elle n'est pas réduite à un seul élément.
Analyse
1 1 . el < tabEnt [ 1 ]
2 2 . boucle tant que t a i l l e > 1 f a ir e
3 2 . 1 . parcours de droite à gauche
4 trouver x < el
5 permuter ( x , el )
6 2 . 2 . parcours de gauche à droite
Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998
3.6 Algorithmes de tri de tableau 67

7 trouver x > el
8 permuter ( x , el )
9 3 . 1 . separer partie gauche
10 3 . 2 . separer partie droite
Ranement
 Dans 2.1. et 2.2. la recherche de l'élément à permuter se fait à partir de l'emplacement de la
dernière permutation.

 Il faut déteminer le début et la n de chaque parcours .

Exemple

22 25 21 10 45 12 53
12 25 21 10 45 22 53
12 22 21 10 45 25 53
12 10 21 22 45 25 53
10 12 21 22 45 25 53
10 12 21 22 25 45 53

Conception
Données
1 Entrées
2 tabEnt:a : tableau à t r i e r
3 deb , fin :a : lim it e s du t r i
4 Sortie
5 tabEnt:a : tableau t r ié
6 Locales
7 g , d:a : indice de parcours
8

Traitement
1 début
2 g < ;adeb;; d < fin
3 tant que d > g faire
4 début
5 tant que tabEnt [ d ] < tabEbt [ g ] faire decrementer d
6
7 si d <= g alors retour
8
9 permuter ( tabEnt [ g ] , tabEnt [ d;a ]) ; incrementer g
10
11 tant que tabEnt [ g ] < tabEbt [ d ] faire incrementer g
12
13 si d <= g alors retour
14
15 permuter ( tabEnt [ g ] , tabEnt [ d;a ]) ; decrementer d
16 fin
17
18 si deb < g 1 alors triSep ( deb , g 1 )
19 si fin > g+1 alors triSep ( g+1 , fin )
20 fin

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


68 Chapitre3. Algorithmique et structures de données avancées

Implanataion

triSep.c

1 #include " triSep . h"


2
3 void triSep ( int tabEnt [ ] , int deb , int fin )
4 f
5 int g , d , pivot ;
6
7 pivot = tabEnt [ deb ] ;
8 for ( g = deb , d = fin ; g < d ; )
9 f
10
11 for ( ; tabEnt [ d ] > pivot ; d );
12
13 if ( g != d)
14 f
15 tabEnt [ g ] = tabEnt [ d ] ;
16 tabEnt [ d ] = pivot ;
17 g++;
18 g
19 for ( ; tabEnt [ g ] < pivot ; g++);
20
21 if ( g != d)
22 f
23 tabEnt [ d ] = tabEnt [ g ] ;
24 tabEnt [ g ] = pivot ;
25 d ;
26 g
27 g
28 if ( deb < g 1 ) triSep ( tabEnt , deb , g 1 ) ;
29 if ( fin > g+1 ) triSep ( tabEnt , g+1 , fin ) ;
30 g

triSep.h

1 void triSep ( int tabEnt [ ] , int deb , int fin ) ;

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


3.6 Algorithmes de tri de tableau 69

Test
triSepTest.c

1 /  Ce programme ne f a i t pas d ' E/S . I l est destiné à un t e s t de performance  /


2 #include<stdio . h>
3 #include< s t d lib . h>
4 #include " triSep . h"
5
6 #define TAILLE 10000
7
8 int main( void )
9 f
10 int tab [ TAILLE ] , i , maxRand = TAILLE 10 ;
11
12 for ( i = 0 ; i < TAILLE ; i ++)
13 tab [ i ] = rand () % maxRand;
14
15 triSep ( tab , 0 , TAILLE 1 ) ;
16 g

Performances
Le tableau 3.2 montre une comparaison des performances  réelles  des diérents algorithmes
présentés ici. Les essais ont eu lieu sur une machine Sun Sparcstation 20.

Tab. 3.2  Comparasion des performances  réelles  des algorithmes de tri.

taille des Temps d'exécution(sec)


Algorithme données réel utilisateur système
Insertion 10 000 34.3 15.2 0.1
Échange 10 000 1:43.0 31.8 0.0
Séparation 10 000 0.2 0.0 0.0
Séparation 100 000 2.4 1.0 0.0
Séparation 100 000 15.4 5.9 0.4
+ sauvegarde

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


70 Chapitre3. Algorithmique et structures de données avancées

3.7 Types de données abstraits


dénition 1 : un Type de Données Abstrait (TDA) est un ensemble de données et d'opérations sur ces
données.
dénition 2 : un TDA est un ensemble de données organisé de sorte que les spécications des objets
et des opérations sur ces objets soient séparées de la représentation interne des objets de de la
mise en oeuvre des opérations.
Les TDA sont nés de préoccupation de génie logiciel telles que l'abstraction, l'encapsulation et la
vérication de type. En eet les TDA généralisent les types prédénis (ou types simples).
exemples :
 Le type entier muni des opérations + - % / < > = >= <= est un TDA.
 Une pile munie des opérations initialiser, empiler, dépiler, consulter le sommet de pile est un TDA.
3.7.1 Incarnation d'un TDA
Une incarnation (une réalisation, une mise en oeuvre) d'un TDA est la structure de données parti-
culière et la dénition des opérations primitives dans un langage particulier. On parle aussi de type de
données concret.
Remarque : dénir le jeu de primitives peut s'avérer un problème délicat.
exemple : on peut mettre en oeuvre le TDA pile en utilisant en mémoire des cellules contiguës
(tableau) ou des cellules chaînées.
3.7.2 Programmation à l'aide des TDA
programmation à l'aide des TDA: Les programmeurs ont deux casquettes :
 Le concepteur du TDA qui met en ÷uvre les primitives et doit connaître la représentation interne
adoptée.
 L'utilisateur du TDA qui ne connaît que les services (les opérations) et n'accèdent jamais à la
représentation interne.
3.7.3 Avantages des TDA
 Écriture de programmes en couches : la couche supérieure dans les termes du domaine de problèmes
et non pas avec les détails du langage de programmation.
 Séparation claire des ores de service et du codage.
 Facilité de compréhension et d'utilisation.
 Prise en compte de types complexes.
 Briques d'une structuration modulaire rigoureuse.
3.7.4 Inconvénients des TDA
 L'utilisateur d'un TDA connaît les services mais ne connaît pas leur coût.
 Le concepteur du TDA connaît le coût des services mais ne connaît pas leurs conditions d'utilisa-
tion.
 Le choix des primitives est quelque fois dicile à faire.
3.7.5 Le TDA Liste
Dénitions :
Liste: une suite nie (éventuellement vide) d'éléments.
Liste homogène: tous les éléments sont du même type.
Liste hétérogène: les éléments sont de type diérents.
Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998
3.8 Listes Chaînées 71

3.8 Listes Chaînées

3.8.1 Introduction

Une liste chaînée est une structure de données composée de blocs de même nature (appelés élément s
ou n÷ud s) chaînés de telle manière que chaque n÷ud, à l'exception du dernier, désigne son successeur.

Ce type de liste est aussi appelé liste séquentielle ou encore liste séquentielle chaînée . Lorsqu'il n'y
a pas d'ambiguïté on parlera simplement de liste .

Par la suite on suppose que les listes sont implantées à l'aide des structures autoréférentielles
(cf. 2.3.5), le mécanisme de désignation est alors celui du pointeur.

Le premier n÷ud d'une liste est souvent appelé tête de liste et le dernier queue de liste . Un pointeur
(teteListe dans le cas de la gure 3.1) est normalement utilisé pour désigner la tête de la liste. Il est
indispensable lorsqu'une liste peut être vide ce qui s'exprime par la valeur NULL du pointeur.

teteListe (Tete) (Queue)

29 52 10 32 24

Fig. 3.1  Représentation schématique d'une liste chaînée.

Dans la pratique les listes sont généralement utilisées lorsque les données ne sont pas connues à
l'avance, les n÷ud s sont donc créés dynamiquement et ne font pas partie de la structure de la liste
initialement. Les n÷uds sont normalement implantés à l'aide des structures autoréférentielles (cf. 2.3.5).
Le code suivant contient les déclarations du type et de la fonction de création d'un n÷ud qui seront
utilisés par la suite.

noeud.h

1 /  Definiton generique de typeNoeud : dans une implantation concrete


2  " typeContenus cont " doit etre remplacer par la l i s t e des champs e f f e c t i f s
3 /
4 typedef struct noeud f
5 char cont ; /  typeContenus : chmaps du noeud  /
6 struct noeud  suiv ; /  pointeur de chainage  /
7 g typeNoeud ;
8
9 typeNoeud  creerNoeud ( ) ;
10 void lireNoeud ( typeNoeud  nd ) ;
11 void afficheNoeud ( typeNoeud  nd ) ;

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


72 Chapitre3. Algorithmique et structures de données avancées
noeud.c

1 #include < stdio . h>


2 #include < s t d lib . h>
3 #include "noeud . h"
4
5 typeNoeud  creerNoeud ()
6 /  creerNoeud : a l l o c a t i o n dynamique d ' un element de typeNoeud
7  retour : meme que malloc , traitement des erreurs a f a i r e par l ' appelant
8 /
9 f
10 return (( typeNoeud  ) malloc ( sizeof ( typeNoeud ) ) ) ;
11 g
12
13 void lireNoeud ( typeNoeud  nd)
14 f
15 char rc ;
16
17 p r in t f ( "Donner un caract e r e n n" ) ;
18 scanf ("%c%c " , &( nd >cont ), & rc ) ;
19 f f lu s h ( stdin ) ;
20 g
21
22 void afficheNoeud ( typeNoeud  nd)
23 f
24 p r in t f ("%c n n" , nd >cont ) ;
25 g

creerNoeud se contente de demander l'allocation nécessaire pour un nouveau n÷ud.

3.8.2 Opérations sur les listes


En plus des opérations de saisie et d'achage, les opérations suivantes sont caractéristiques et com-
plètent la dénition des listes :
listeVide tester si une liste est vide ;
suivant retrouver le successeur d'un élément donné ;
nListe tester si la n de liste est atteinte ;
parcours d'une liste pour eectuer une opération donnée (comme l'achage ou la recherche) sur les
éléments ;
trouver un élément (normalement identié par une clef ), nécessite un parcours ;
inserer un élément donné dans une liste ;
supprimer un élément dans une liste.
L'insertion et la suppression (cf. 3.9) peuvent s'opérer de diérentes manières : l'opération peut
s'eectuer sur l'élément de tête ou de queue de la liste, à une position donnée ou encore à l'emplacement
approprié dans une liste triée. Dans ce dernier cas l'emplacement est déterminé à l'aide d'une clef de la
même manière que pour la recherche dans un tableau par exemple.
Les opérations suivantes peuvent être utiles :
initialiser une liste existante ;
liberer tous les éléments d'une liste et la re-initialiser.
D'autres opérations encore peuvent être dénies selon les besoins de l'application.
Il peut y avoir plusieurs manières d'implanter une opération, en fonction des choix de performance,
des besoins de l'application ou de la représentation choisie. Nous présentons ici deux implantations des
listes chaînées. Pour la première, appelée implantation simple, un algorithme au moins sera présenté
pour chaque opération. Pour la deuxième, implantation avec sentinelle, seules les modications les plus
importantes par rapport à l'implantation simple seront soulignées.
Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998
3.8 Listes Chaînées 73

3.8.3 Implantation simple


Dans cette première implantation une liste est désignée simplement par un pointeur qui pointe sur
son premier élément :
1 typeNoeud *teteListe;

Ce choix implique qu'une liste est vide si teteListe ne pointe sur rien (fait exprimé par la valeur
empruntée au langage C) :
NULL
1 booléen lis t e V id e ( typeNoeud  t e t e L is t e )
2 début
3 retour ( t e t e L is t e = NULL)
4 fin
La fonction suivant retourne un pointeur sur l'élément (successeur ) désigné par un élément donné
(prédécesseur ) dans une liste donnée :
1 typeNoeud  suivant ( typeNoeud  courant )
2 début
3 retour ( courant >suiv )
4 fin
Le test de n de liste revient à tester si l'élément manipulé n'a pas de successeur (donc ne pointe
sur rien) :
1 booléen f in L is t e ( typeNoeud  courant )
2 début
3 retour ( courant >suiv = NULL)
4 fin
Le parcours d'une liste chaînée ne peut se faire que de manière séquentielle ; en faisant avancer un
pointeur donné d'un seul n÷ud à la fois :
1 parcours ( typeNoeud  t e t e L is t e )
2 début
3 ptrParcours < t e t e L is t e
4 tant que non f in L is t e ( ptrParcours )
5 début
6 Operation ( s ) sur l ' élément courant , p. e . a f f ic h e (  ptrParcours )
7 ptrParcours < ptrParcours >suivant
8 fin
9 fin
Par exemple, ayant à disposition une fonction afficheContenus pour l'achage des champs d'un
n÷ud, l'achage d'une lsite peut se faire de la manière suivante :
1 a f f i c h e r ( typeNoeud  t e t e L is t e )
2 début
3 ptrParcours < t e t e L is t e
4 tant que non f in L is t e ( ptrParcours )
5 début
6 afficheContenus ( ptrParcours >cont )
7 ptrParcours < ptrParcours >suivant
8 fin
9 fin
10

Pour rechercher un élément il faut faire un parcours en comparant l'élément pointé avec l'élément
recherché. En cas d'égalité on retourne la valeur courante du pointeur de parcours, si la boucle se termine
l'élément n'a pas été trouvé, ce qui doit être indiquée par la valeur retournée, NULL dans notre cas :
1 typeNoeud  trouver ( typeNoeud  t e t e L is t e , typeContenus cont )
2 début
3 ptrParcours < t e t e L is t e
4 tant que non f in L is t e ( ptrParcours )
5 début
6 si cont = ptrParcours >cont retour ( ptrParcours )
7 ptrParcours < ptrParcours >suivant
8 fin
Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998
74 Chapitre3. Algorithmique et structures de données avancées

9
10 retour (NULL)
11 fin
Il s'agit ici du cas général et la comparaison (ligne 6) est notée simplement  =. Dans une réalisa-
tion/utilisation concrète cette opération doit être remplacée par la comparaison adéquate éventuellement
implantée à l'aide d'une fonction, de la même manière que l'adaptation du tri rapide dans l'application
BDU (cf. 4.6) par exemple.
Pour l'insertion et la suppression on traite d'abord le cas le plus simple : l'opération s'eectue à
un emplacement donné de la liste. À première vue un nouvel élément ne peut être inséré qu'après
l'emplacement spécié. Le passage des paramètres doit se faire par référence (c.à.d. adresse ou pointeur
qui désigne l'élément) puisqu'ils seront modiés, ce qui en même temps simplie l'écriture :
1 in s e r e r Dir e c t ( typeNoeud  noeudAinserer , typeNoeud  emplacement)
2 début
3 noeudAinserer >suiv < emplacement >suiv
4 emplacement >suiv < noeudAinserer
5 fin
Cette fonction peut par exemple être utilisée pour la saisie en insérant l'élément saisi en tête de liste.
En supposant l'existence d'une fonction de saisie du contenu, lireContenus, qui retourne vrai en cas
de saisie valide, faux sinon (pour signier la n de la saisie), on peut eectuer la saisie par l'algorithme
suivant :
1 début
2 répéter
3 si ( ( nouveauNoeud < creerNoeud ()) == NULL)
4 SortieErr e ur
5 sinon
6 début
7 saisieOK < lireContenus ( nouveauNoeud >cont )
8 si saisieOK
9 in s e r e r Dir ( nouveauNoeud , t e t e L is t e )
10 fin
11 jusqu ' à non saisieOK
12 l i b e r e r ( nouveauNoeud )
13 fin

La fonction traite l'éventuelle erreur d'allocation de creerNoeud (lignes 4 et 5).


La suppression consiste à, d'abord, retirer l'élément de la liste et, ensuite, le supprimer eectivement
en libérant la mémoire. Pour retirer un élément la façon la plus simple est de faire désigner son successeur
par son prédecesseur, on a donc besoin d'une référence à ce dernier :
1 supprimerDirect ( typeNoeud  nouedAsupprimer , typeNoued  predeces se ur )
2 début
3 predeces se ur >suiv < noeudAsupprimer >suiv
4 l i b e r e r ( noeudAsupprimer )
5 fin

3.8.4 Implantation avec sentinelle


L'implantation précédente présente quelques inconvénients. Par exemple l'insertion dans une liste
triée doit s'eectuer avant l'élément qui provoque la sortie de la boucle de parcours. Si on utilise
l'algortihme 3.8.3 il est nécessaire d'avoir accès au prédecesseur, ce qui est fait normalement en utilisant
un pointeur supplémentaire qui  suit  l'élément courant du parcours (cf. algorithme 3.8.5 ci-après).
Une autre solution consiste à utiliser la copie des contenus des n÷uds (simple aectation d'enregis-
trement en langage C) ce qui permet d'eectuer l'insertion avant l'élément désigné et on a besion de la
seule référence de celui-ci.
On remarque cependant qu'il est impossible d'insérer un élément en n de liste, il en sera de même
pour la suppression. Pour pallier à ce problème on utilise une nouvelle implantation : un élément ctif,
appelé sentinelle, est ajouté en n de liste. Il sera désigné par le pointeur dernier : l'insertion et la
suppression du dernier élément reviennent alors à opérer sur la sentinelle (ou le pointeur dernier).
La structure d'une liste avec sentinelle comprend alors deux pointeurs qu'on préfère ici regrouper
dans un enregistrement :
Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998
3.8 Listes Chaînées 75
listesSent.h

1 typedef struct f typeNoeud  premier ,  dernier ; g typeListe ;

Dans le cas de l'insertion on duplique d'abord le n÷ud emplacement avant lequel on désire insérer
(lignes 3 et 5), puis on remplace ses contenus par ceux de noeudAinserer et on chaîne ce dernier à la
copie (qui désormais remplace l'original). Dans le cas particulier où l'emplacement désigne la sentinelle
il sut que la copie remplace celle-ci, ce qui revient à la faire désigner par dernier (ligne 4) :
1 insererAvant ( typeListe l i s t e , typeNoeud  nouedAinserer , typeNoued  emplacement )
2 début
3 typeNoeud  copie < creerNoeud ()
4
5 si emplacement = l i s t e . dernier l is t e . dernier < copie
6 sinon  copie <  emplacement
7 emplacement >cont < noeudAinserer >cont
8 emplacement >suiv < copie
9 l i b e r e r ( noeudAinserer )
10 fin
La suppression d'un n÷ud peut se faire en écrasant ses contenus avec ceux de son successeur, c'est
celui-ci qui est eectivement supprimé ensuite :
1 supprimerNoeud ( typeListe l i s t e , typeNoeud  nouedAsupprimer )
2 début
3 typeNoeud  succes s eu r < nouedAsupprimer >suiv
4 si succes se u r = l i s t e . dernier l is t e . dernier < noeudAsupprimer
5 sinon  noeudAsupprimer <  succe ss e ur
6 l i b e r e r ( succe ss e ur ) /  suppression e f f e c t i v e  /
7 fin
Si le n÷ud à supprimer est la queue de la liste, il devient tout simplement la sentinelle (ligne 4) ;
il n'est pas nécessaire de copier les contenus dans ce cas-là car ceux de la sentinelle n'ont aucune
importance.
Certains des algorithmes de l'implantation simple restent valables ici, comme l'insertion directe
(algorithme 3.8.3) utilisé dans l'algorithme 3.8.5 ci-après. Il s'agit des algorithmes indépendants de la
structure de la liste elle-même. Les autres algorithmes doivent être modiés pour s'adapter à cette
nouvelle structure, par exemple la n de liste est atteinte lorsque le pointeur courant pointe sur la
sentinelle (c.à.d. lorsqu'il a la même valeur que dernier) :
1 booléen f in L is t e ( typeNoeud  courant )
2 début
3 retour ( courant = dernier )
4 fin
3.8.5 Listes triées
Une liste triée est une liste dont les éléments sont toujours rangés dans un ordre déni par une clef
(un champ ou une combinaison de champs des contenus du n÷ud). Ceci implique qu'il faut toujours
rechercher la position de l'élément manipulé quelle que soit l'opération à eectuer, ce qui nécessite de
parcourir la liste dans tous les cas.
Par la suite, on suppose une implantation avec sentinelle, mais, comme on l'a mentionné au pa-
ragraphe précédent, il reste possible d'utiliser certains des algorithmes de l'implantation simple. On
suppose aussi que la liste est triée dans l'ordre croissant et on attribue à l'opératuer de comparaison  <
un sens générique dans le même esprit que précédemment.
Comparé au cas des listes non triées, la saisie devient moins performante mais on a un gain considé-
rable sur le coût la recherche, qui normalement est l'opération la plus fréquente.
1 n la b e l f :a a l g :LTsaisie :LTsaisieg%
2 s a i s i e L i s t e T r ie e ( typeListe liste )
3 début
4 tant que non f i n S a i s i e /  condition a r a f f i n e r  /
5 début
6 si ( ( nouveauNoeud < creerNoeud ()) == NULL)
Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998
76 Chapitre3. Algorithmique et structures de données avancées

7 SortieErr e ur
8 sinon
9 début
10 lireContenus ( nouveauNoeud >cont )
11 ptrParcours < premier
12 tant que ptrParcours != NULL et ptrParcours >cont < nouveauNoeud >cont
13 ptrParcours < ptrParcours >suiv
14
15 insererAvant ( ptrParcours , nouveauNoeud )
16 fin
17 fin
18 fin

1 n la b e l f :a a l g :LTrech :LTrech g
2 typeNoeud  trouverDansListeTriee ( typeListe l i s t e , typeContenus cont )
3 début
4 ptrParcours < l i s t e . premier
5 tant que non f in L is t e ( ptrParcours ) et cont < ptrParcours >cont
6 ptrParcours < ptrParcours >suivant
7
8 si cont = ptrParcours >cont retour ( ptrParcours )
9 retour (NULL)
10 fin
L'insertion dans une liste triée doit s'eectuer à la place correpondant à l'ordre de l'élément, un
parcours est donc nécessaire. On montre ici deux possibilités : un parcours avec deux pointeurs qui
utilise l'insertion directe, et un parcours avec un seul pointeur en utilisant l'algorithme d'insertion par
copie (3.8.4).
L'algorithme suivant eectue l'insertion en utilisant un parcours avec deux pointeurs (pour en donner
un exemple). Il montre aussi un cas de réutilisation d'algorithme : celui de l'insertion directe (3.8.3)
développé pour l'implantation simple, mais utilisable ici puisqu'indépendant de la structure de la liste :
1 in s e r e r Dir L is t e Tr ie e ( typeListe li s t e , typeNoeud  noeudAinserer )
2 début
3 ptrPrec < l is t e . premier /  non nul ( s e n t i n e l l e )  /
4 ptrParcours < l i s t e . premier > suiv
5 tant que non f in L is t e ( ptrParcours ) et
6 noeudAinserer >cont < ptrParcours >cont
7 début
8 ptrPrec < ptrParcours
9 ptrParcours < ptrParcours >suivant
10 fin
11 in s e r e r Dir e c t ( noeudAinserer , ptrPrec )
12 fin
L'algorithme suivant montre l'autre possibilité :
1 in s e r e r Co p ie L is t e Tr ie e ( typeListe l i s t e , typeNoeud  noeudAinserer )
2 début
3 ptrParcours < l i s t e . premier
4 tant que non f in L is t e ( ptrParcours ) et
5 noeudAinserer >cont < ptrParcours >cont
6 ptrParcours < ptrParcours >suivant
7
8 insererAvant ( li s t e , noeudAinserer , ptrParcours )
9 fin
Il est possible d'améliorer la performance du dernier algorithme en modiant la condition d'arrêt de
la boucle. Dans le cas général les contenus de la sentinelle ne sont pas utilisées : si on y copie ceux de
l'élément cherché la condition sur les contenus (ligne 5) sera vériée en n de boucle et on n'a donc plus
besoin d'eectuer le test correspondant :
1 n la b e l f :a a l g :LTinsCpieAmel :LTinsCpieAmel g
2 in s e r e r Co p ie L is t e Tr ie e ( typeListe l i s t e , typeNoeud  noeudAinserer )
3 début
4 l i s t e . dernier >cont < noeudAinserer >cont
Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998
3.9 Piles et queues 77

5 ptrParcours < l i s t e . premier


6 tant que noeudAinserer >cont < ptrParcours >cont
7 ptrParcours < ptrParcours >suivant
8
9 insererAvant ( li s t e , noeudAinserer , ptrParcours )
10 fin
Dans un cadre pratique (pour un problème donné) le choix de l'algorithme (et des améliorations !)
s'eectue conjointement avec celui de la structure de données et en fonction des besoins de l'application.
Par exemple dans le cas présent et du point de vue de la performance, le choix doit s'eectuer en com-
parant les deux coûts supplémentaires : une aectation supplémentaire par itération dans l'algorithme
3.8.5 contre une copie d'enregistrement dans l'algorithme 3.8.5. Le premier sera plus ecace si la liste
contient peu d'élément et la taille de l'enregistrement est importante.
Pour pallier à certains problèmes, il est possible de raner la dénition/utilisation des listes ou
de réaliser des implantaions plus élaborées. Dans le cas des listes, les deux implantations précédentes
présentent un inconvénient majeur : il est impossible d'eectuer un  retour en arièrre . récupérer
l'élément précédent (pour l'insertion directe par exemple) nécessite un nouveau parcours (à partir du
début de la liste) ou un pointeur supplémentaire.
Parmi les améliorations possibles notons :
Les listes circulaires: ce sont des listes chaînées dont le dernier élément pointe sur le premier. Il
est ainsi possible de maintenir un pointeur courant qui désigne le dernier élément du parcours
précédent, évitant ainsi de recommencer le parcours à chaque fois.
Les listes doublement chaînées: dans lequelles la structure du n÷ud est modiée pour inclure un
pointeur supplémentaire lui permettant de pointer son prédécesseur.
En combinant ces deux amélioartion on obtient la structure représentée schématiquement par la gure
3.2

premier

courant dernier

Fig. 3.2  Représentation schématique d'une liste circulaire doublement chaînée avec sentinelle.

3.9 Piles et queues


3.9.1 Élimination des appels récursifs à l'aide des piles
3.10 Arbres binaires

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


78 Chapitre3. Algorithmique et structures de données avancées

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


Chapitre 4

Application: Base de Données


Universitaire
4.1 Description du problème
Objectif: développer un logiciel de gestion d'une base de données d'inforamtions sur les étudaints
et les enseignants dans une université.

4.2 Analyse
Données
Tables d'informations sur les étudiants et les enseignants.
Il faut deux types d'enregistrements, mais on remarque qu'une partie de l'inforamtion est partagée par
les deux types. Cette partie donnera lieu à la déntion d'un troisième type regroupant des informations
sur une personne.

Traitement
Saisie, achage, recherche, suppression, modication. Interaction avec l'utilisateur.
Pour une performance optimale il faudra aussi trier les données.
4.2.1 Ranement
Données
Types
enregistrement personne
nom, prenom, date de naissance
enregistrement etudiant
personne, identiant
enregistrement enseignant
personne, grade
date de naissance : jours, mois, annee (enr.)
identiant : entier
grade : code (chaine de caracteres ou entier)
Variables
tableau de etudiant
tableau de enseignant

Traitement
1. Sur les enregistrements
saisie : retourne un enr. du type approprié
) une fonction par type d'enregistrement.
79
80 Chapitre4. Application : Base de Données Universitaire

personne saisiePersonne(void)
etudiant saisieEtudiant(void)
enseignant saisieEnseignant(void)
date saisieDate(void);
achage : ache un enr. du type approprié
) une fonction par type d'enregistrement.
Exercice : description des fonctions
2. Sur les tableaux
aectation d'un élément (enr.) : autorisée en C.
recherche d'un élément : retour indice/erreur.
modication d'un élément :
Entrées : élément à modier, modications.
Sortie : élément modié.
Exercice : description des autres fonctions.
3. Interaction avec l'utilisateur: exercice

4.3 Conception
4.3.1 Types et données
denir type : typeDate
entier jour, mois, annee
denir type : typePersonne
chaine_de_caracteres nom
chaine_de_caracteres prenom
typeDate date
denir type : typeEtudiant
typePersonne etudiant
entier identiant
denir type : typeEnseignant
Exercice : dénir les membres
typeEtudiant tabEtudiants[MAX_ETD]
typeEnseignant tabEnseignant[MAX_ENS]

Traitements
 Il s'agit de types composés  à plusieurs niveaux , il faut donc distinguer plusieurs niveaux
de traitement : d'abord sur les enregistrements date, etudiant et enseignant, ensuite sur les
tableaux d'enregistrement.
 Les données complexes ont été dénies par composition progressive de types simples. Il faut procé-
der de la même façon pour les traitements : construire progressivement les opérations sur les types
complexes à partir des opérations sur les types simples.

Exemple

 typeDate est composé de trois entiers : jour, mois, annee , pour saisir/acher une date il sut
de saisir/acher ses trois membres ;
 typeEtudiant est composé de typePersonne et de typeDate : pour saisir/acher une variable de
ce type il faut utiliser saisir/acher de ces deux type.
Attention: une opération sur un type complexe n'est pas nécessairement la répétition de la même
opération sur ses composants : la diérence entre deux dates ne s'obtient pas par simples soustractions
des membres respectifs.
Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998
4.3 Conception 81

Opérations sur les enregistrements


acheDate
Ache à l'écran un enregistrement de type typeDate
Entree : dt, enregistrement à acher
debut
ache dt.jour
ache dt.mois
ache dt.annee
n
saisieDate(typeDate *ptrDate)
permet la saisie au clavier d'un enregistrement de type typeDate
Entree : ptrDate, pointeur sur l'enregistrement à saisir
Remarque : il faut utiliser un pointeur pour récupérer les modications
debut
saisie ((*ptrDate).jour)
saisie ((*ptrDate).mois)
saisie ((*ptrDate).annee)
n
achePersonne(typePersonne prs)
ache (prs.nom)
ache (prs.prenom)
acheDate (prs.dateNaissance)
saisiePersonne (typePersonne *ptrPrs)
saisie (*ptrPrs).nom
saisie (*ptrPrs).prenom
saisieDate ((*ptrPrs).date)
acheEtudiant(typeEtudiant etd)
achePersonne(etd.etudiant)
ache etd.identiant
saisieEtudiant(typeEtudiant *ptrEt)
saisiePersonne (*ptrEt).etudiant
saisieDate ((*ptrEt).identiant)
acheEnseignant, saisieEnseignant : Exercice

1 saisieTabEtudiants ( typeEtudiant tabEtudiants [ ] , int t a i ll e )


2 boucle pour i < 0 jusqu ' à t a i l l e 1
3 s a is ie E t u d ian t (& tabEtudiants [ i ])
4
5 afficheTabEtudiants ( typeEtudiant tabEtudiants [ ] , int t a i l l e )
6 boucle pour i < 0 jusqu ' à t a i l l e 1
7 a f f ic h e E tu d iant ( tabEtudiants [ i ])
8
9 insereEtudiant ( typeEtudiant etd , typeEtudiant tabEtudiants [ ] , int pos )
10
11 tabEtudiants [ pos ] < etd
12
13 int rechercheEtudiant ( typeEtudiant etd , typeEtudiant tabEtudiants [ ])
14
15 boucle pour i < 0 jusqu ' à t a i l l e 1
16 si compEtudiant ( etd , tabEtudiants [ i ])
17 retourner i
18 retourner NON_TROUVE
19
20 n fbox fn emphf afficheTabEnseignant , saisieTabEnseignant :a : Exercice gg
Opérations sur les tableaux
Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998
82 Chapitre4. Application : Base de Données Universitaire

4.4 Notions de module et de modularité


Lorsqu'un programme (ou un logiciel) augmente en taille il devient indispensable de le découper en
modules pour des raisons pratiques mais aussi pour bien le maîtriser.
Module : c'est un élément de petite taille (en général un ou quelques sous-programmes) qui sert,
par assemblage à la construction de logiciels. Un module doit être cohérent et autonome.

 pour simplier on peut dire qu'un module regroupe les données de natures cohérentes et leurs
opérations ;
 un ensemble de modules (un logiciel ou un assemblage de modules) doit être bien organisé en
architecture robuste. En particulier il faut bien préciser les relations entre modules :  qui utilise
qui et comment , à l'aide de pseudo-langage, de schémas, etc. ;
 un module doit être utilisable sans avoir à se soucier des détails de son implantation. Seule son
interface (les fonctions, constantes et variables) qu'il exporte doivent être visibles par les modules
qui l'utilise ;
 en langage C on convient de dénir pour chaque module deux chiers : l'implantation (.c) et
l'interface (.h).

4.5 Première implantation


La gure 4.1 donne une idée générale du découpage en module de l'application. Chaque module doit
être implanté et testé séparément avant de l'intégrer à l'application.

Saisie Saisie
Afficher typeDate typePersonne Afficher
Modifier Modifier

Saisie Saisie
Afficher typeEtudiant typeEnsiegnant Afficher
Modifier Modifier

Rechercher Rechercher
Trier tabEtudiants tabEnseignants Trier
... ...

Module
Données/Type Principal

Opérations/Traitement
Pour maintenir la clarte, ce schéma est
Utiliser (composition de types) un peu simplifié.
Par exemple le module principal utilise
Utiliser (opérer sur) Interface tous les types, ce qui ne figure pas
Utilisateur explicitement ici.
Module

Fig. 4.1  Conception générale de l'application BDU

4.5.1 Module dates


Le code source doit faire le lien avec les phases d'analyse et de conception et supporter la gestion.
D'où les commentaires  types  de chier et de fonctions. Cette description ne sera pas répétée pour
les autres modules, mais elle doit être faite pour cahque module ou programme.
Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998
4.5 Première implantation 83
dates.c

1 /  Fichier : dates . c
2  Description : module de manipulation d ' un enregistremnt de type date .
3  dans l ' état actuel f o u r n i t uniquement l e s opérations de s a i s i e et
4  d ' a f f i c h a g e ( r e c q u i s e s par l ' a p p l i c a t i o n BDU).
5  Auteur : Mamoun A l i s s a l i
6  Historique : 28 . 11 . 96 création
7  29 . 11 . 96 t e s t OK
8  A FAIRE : modifiaction de date
9  opérations arithmétiqu es
10 /
11 #include < stdio . h>
12 #include " dates . h"
13
14 void
15 afficheDate ( typeDate dt )
16 / 
17  afficheDat e : Affiche à l ' écran un enregistrement de type typeDate
18  Entree : dt , enregistrement à a f f i c h e r
19  /
20 f
21 p r in t f (" %d/%d/%d n n" , dt . jour , dt . mois , dt . annee ) ;
22 g
23
24 void
25 s a is ie Dat e ( typeDate  ptrDate )
26 / 
27  permet la s a i s i e au c l a v i e r d ' un enregistrement de type typeDate
28  Entree : ptrDate , pointeur sur l ' enregistrement à s a i s i r
29  Remarque : i l faut u t i l i s e r un pointeur pour récupérer l e s modificatio n s
30  /
31 f
32 p r in t f ( " Jour ? n n" ) ;
33 scanf ("%d" , &((  ptrDate ) . jour ) ) ;
34 p r in t f ( " Mois ? n n" ) ;
35 scanf ("%d" , &((  ptrDate ) . mois ) ) ;
36 p r in t f ( " Annee ? n n" ) ;
37 scanf ("%d" , &((  ptrDate ) . annee ) ) ;
38 g
39

dates.h

1 typedef struct f
2 int jour , mois , annee ;
3 g typeDate ;
4
5 void afficheDate ( typeDate dt ) ;
6 void s a is ie Dat e ( typeDate  ptrDate ) ;

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


84 Chapitre4. Application : Base de Données Universitaire
datesTest.c

1#include " dates . h"


2
3 int main( void )
4 f
5 typeDate dt ;
6
7 s a is ie Dat e (&dt ) ;
8 afficheDate ( dt ) ;
9 g

4.5.2 Module personne


personne.h

1 /  typePersonne doit être inclu pour être reconnu des modules qui
2  u t i l i s a t e u r s : i l s s ' en servent pour la composition des types
3  ( p . e . etudiant et pour l ' appel des fonction s du present module
4 /
5 #include " dates . h"
6 #define TAILLE 32
7 typedef struct f
8 char nom[ TAILLE ] , prenom [ TAILLE ] ;
9 typeDate dateNaissance ;
10 g typePersonne ;
11
12 void affichePer s onn e ( typePersonne prs ) ;
13 void s a is ie P e r s on ne ( typePersonne  ptrPrs ) ;

personne.c

1 #include < stdio . h>


2 #include " personne . h"
3
4 void
5 affichePe rs on ne ( typePersonne prs )
6 f
7 p r in t f ( "Nom : %s n n" , prs . nom ) ;
8 p r in t f ( "Prenom : %s n n" , prs . prenom ) ;
9 p r in t f ( " Ne le :" ) ;
10 afficheDate ( prs . dateNaissance ) ;
11 g
12 void
13 s a is ie P e r s o nn e ( typePersonne  ptrPrs )
14 f
15 p r in t f ( "Nom ? n n" ) ;
16 scanf ("%s " , (  ptrPrs ) . nom ) ;
17 p r in t f ( "Prenom ? n n" ) ;
18 scanf ("%s " , (  ptrPrs ) . prenom ) ;
19 p r in t f ( "Date de naissance ? n n" ) ;
20 s a is ie Dat e (&((  ptrPrs ) . dateNaissance ) ) ;
21 g
Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998
4.5 Première implantation 85

personneTest.c

1#include " personne . h"


2
3 int main( void )
4 f
5 typePersonne pers ;
6
7 s a is ie P e r s on n e (&pers ) ;
8 affichePe rs onn e ( pers ) ;
9 g

4.5.3 Module etudiant


etudiant.c

1 /  Fichier : etudiant . c
2  Description : module de traitement d ' un enregistrement typeEtudiant .
3  Fournit l e s opérations d ' a f f i c h a g e et de s a i s i e .
4  Auteur : Mamoun A l i s s a l i
5  Historique : 10 . 12 . 96 : r é a l i s a t i o n , t e s t OK.
6 /
7 #include<stdio . h>
8 #include " etudiant . h" /  i n c l u t personne . h  /
9
10 void
11 a f f ic h e Et u dia nt ( typeEtudiant etd )
12 / 
13  a f f i c h e E t u d i a n t : a f f i c h a g e d ' un ernregistr emen t de typeEtudiant .
14  Entree : etd , ernregistre ment à a f f i c h e r .
15  U t i l i s e : affichePersonne .
16  /
17 f
18 affichePe rs onn e ( etd . pers ) ;
19 p r in t f ( " Id e n t if ia n t : %d n n" , etd . id ) ;
20 g
21
22 void
23 s a is ie E t u d ian t ( typeEtudiant  ptrEt )
24 / 
25  s a i s i e E t u d i a n t : sasie d ' un ernregistreme nt de typeEtudiant .
26  Entree : ptrEtd , pointeur sur l ' ernregistr emen t à s a i s i r .
27  U t i l i s e : saisiePersonne .
28  /
29 f
30 s a is ie P e r s on n e (&((  ptrEt ) . pers ) ) ;
31 p r in t f ( " Id e n t if ia n t ? n n" ) ;
32 scanf ("%d" , &((  ptrEt ) . id ) ) ;
33 g

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


86 Chapitre4. Application : Base de Données Universitaire
etudiant.h

1 #ifndef ETUDIANT_H
2 #define ETUDIANT_H
3
4 #include " personne . h"
5
6 typedef struct f
7 typePersonne pers ;
8 int id ;
9 g typeEtudiant ;
10
11 void a f f ic he E t ud ian t ( typeEtudiant etd ) ;
12 void s a is ie E t u d ia nt ( typeEtudiant  ptrEt ) ;
13
14 #endif /  ETUDIANT_H  /

etudiantTest.c

1#include " etudiant . h"


2
3 int main( void )
4 f
5 typeEtudiant etd ;
6
7 s a is ie E t u d ia n t (&etd ) ;
8 a f f ic he E t ud ian t ( etd ) ;
9 g

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


4.5 Première implantation 87

4.5.4 Module tabEtudiants

tabEtudiantsV1.c

1 #include < s t d lib . h>


2 #include < s t r in g . h>
3 #include " tabEtudiantsV0 . h"
4 #include " tabEtudiantsV1 . h"
5
6 typedef int Bool ;
7 #define FAUX 0
8 #define VRAI 1
9
10 static Bool
11 compEtudiant ( typeEtudiant etd1 , typeEtudiant etd2 )
12 f
13 if ( strcmp ( etd1 . pers . nom, etd2 . pers . nom) == 0 )
14 return (VRAI) ;
15
16 return (FAUX) ;
17 g
18 int
19 rechercheEtudiant ( typeEtudiant etd , typeEtudiant tabEtudiants [ ] , int t a i l l e )
20 /  rechercheEtudiant : recherche s é q u e n t i e l l e , basée sur le nom
21  d ' un enregistremnt de typeEtudiant .
22  A FAIRE : recherche dichotomique = > tableau t r i e ( A FAIRE).
23  /
24 f
25 int i ;
26
27 for ( i = 0 ; i < t a i l l e ; i ++)
28 if ( compEtudiant ( etd , tabEtudiants [ i ]) )
29 return ( i ) ;
30
31 return (NON_TROUVE) ;
32 g
33

tabEtudiantsV1.h

1 #include " etudiant . h"


2
3 #define NON_TROUVE 1
4
5 int rechercheEtudiant ( typeEtudiant etd , typeEtudiant tabEtudiants [ ] , int t a i l l e ) ;

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


88 Chapitre4. Application : Base de Données Universitaire
tabEtudiantsV1Test.c

1 #include " tabEtudiantsV1 . h"


2
3 #define TAILLE_TAB_ET 4
4
5 int main( void )
6 f
7 typeEtudiant tabEtudiants [TAILLE_TAB_ET] , etd ;
8 int i ;
9
10 p r in t f ( " Version 1 n n" ) ;
11
12 saisieTabEtudiants ( tabEtudiants , TAILLE_TAB_ET) ;
13 afficheTabEtudiants ( tabEtudiants , TAILLE_TAB_ET) ;
14
15 while ( 1 )
16 f
17 p r in t f ( " Nom ? n n" ) ;
18 scanf ("%s " , etd . pers . nom) ;
19 if ( strcmp ( etd . pers . nom, "0") == 0 ) return ( 0 ) ;
20 if (( i = rechercheEtudiant ( etd , tabEtudiants , TAILLE_TAB_ET) ) != NON_TROUVE)
21 a f f ic h e Et u dia nt ( tabEtudiants [ i ] ) ;
22 else
23 p r in t f ( " Il n' y aucun etudiant au nom de %s n n" , etd . pers . nom) ;
24 g
25 g

4.6 Améliorations
4.6.1 Version 2 : tri du tableau  adaptation du tri rapide
La méthode de tri rapide (tri par séparation peut être appliquée à un tableau d'enregistrements (en
l'occurence tabEtudiants) avec les deux modications suivantes :
 Remplacer le type entier par le type typeEtudiant ;
 fournir une opération de comparaison (qui exprime la relation d'ordre).
1 void triTabEtudiant ( typeEtudiant tabEtudiants [ ] g n , int deb , int fin )
2
3 g < ;adeb;; d < fin
4 tant que d > g f a ir e
5 DEBUT
6 tant que i n f e r i e u r ( tabEtudiant [ d ] , tabEtudiants [ g ] ) f a ir e decrementer d
7
8 si d <= g a lo r s retour
9
10 permuter ( tabEtudiant [ g ] , tabEtudiant [ d;a ]) ; incrementer g
11
12 tant que i n f e r i e u r ( tabEtudiant [ g ] , tabEtudiant [ d ] ) f a ir e incrementer g
13
14 si d <= g a lo r s retour
15
16 permuter ( tabEtudiant [ g ] , tabEtudiant [ d;a ]) ; decrementer d
17 FIN
18
19 si deb < g 1 a lo r s triSep ( tabEtudiants , deb , g 1)
20 si fin > g+1 a lo r s triSep ( tabEtudiants , g+1 , fin )

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


4.6 Améliorations 89

Fonction de comparaison
Pour pouvoir comparer des enregistrements de type typeEtudiant (comme inferieur ci-dessus) il
faut dénir une relation d'ordre et fournir les opérations appropriées :
 on choisit de trier par nom, le champ nom est la clef du tri ;
 pour la relation d'ordre on peut envisager deux solutions :
 dénir une fonction pour chaque opérateur de comparaison (<, >, =) ;
 à l'instar de la fonction de comparaison de chaînes de caractères (strcmp), dénir une seule
fonction qui retourne une valeur inférieure (resp. égale, resp. supérieure) à zéro si le pre-
mier paramètre est inférieur (resp. égale, resp. supérieur) au deuxième. C'est cette deuxième
solution qui sera retenue.
int compEtudiant(typeEtudiant etd1, typeEtudiant etd2)
f
return(strcmp(etd1.pers.nom, etd2.pers.nom));
g
Ce même principe peut être étendu à d'autres clefs pour trier le tableau par prénom ou par identiant
par exemple. Dans ce cas-là, pour ne pas dupliquer les données, il faut utiliser des tableaux d'indices
auxiliaire (cf. 4.6.2).

4.6.2 Version 3 : utilisation de tableaux auxiliaires d'indices


Un tableau auxiliaire d' indices est un tableau dont les éléments sont les indices d'un autre tableau,
il permet d'avoir un accès indexé indirect pour éviter de déplacer les élément du tableau indexé.
Exemples
Tris ascendant et descendant d'un tableau d'entiers, tabEnt : on utilise deux tableaux d'indices :
indAsce et indDesc.
indAsce indDesc tabEnt indAsce indDesc
0 0 53 4 3
1 1 49 6 0
2 2 37 5 1
3 3 75 2 2
4 4 5 1 5
5 5 23 0 6
6 6 10 3 4
avant tris après tris
Tri ascendant par nom et par prénom d'un tableau d'enregistrements de typePersonne
0 Jacques Martin 2
2 Philippe Gildas 1
1 Michel Drucker 0
prenom nom
indP[] tabPers[] indN[]

Pour parcourir (pour acher par exemple) le tableau trié par prénom :
1 boucle pour i < 0 jusqu ' à t a i l l e
2 a f f ic h e r ( tabPers [ indP [ i ] ])
Un tableau auxiliaire d'indices est particulièrement utile (voire indispensable) dans les situations
suivantes :
1 n item le coût du déplacement des éléments du tableau indexé est
2 élevé à cause de leur t a i l l e ;a ;
3 n item on d é s ir e t r i e r le tableau selon p lu s ie u r s c l e f s ou p lu s ie u r s
4 c r i t è r e s en même temps .
Une autre manière de construire un tableau d'indices est de faire ses éléments pointer sur les éléments
du tableau indexé : le tableau d'indices est alors un tableau de pointeurs.
Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998
90 Chapitre4. Application : Base de Données Universitaire

4.7 Implantation des améliorations

 Les modules dates, personne et etudiant ne sont pas modiés (grâce à la modularité !).

 Il en est de même pour une partie du module tabEtudiants (saisie, achage, ...). Pour éviter la
duplication, cette partie se trouve désormais dans le  sous-module  tabEtudiantV0.

 La mention Vn est ajoutée au nom d'un module modié pour indiquer qu'il s'agit de la version
no n.

Les versions 2 et 3 implantent en deux étapes les améliorations (cf. 4.6) présentées précédemment.
Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998
4.7 Implantation des améliorations 91

4.7.1 Implantation de la version 2

tabEtudiantsV2.c

1 #include < s t d lib . h>


2 #include < s t r in g . h>
3 #include " tabEtudiantsV0 . h"
4 #include " tabEtudiantsV2 . h"
5
6 static int
7 compEtudiant ( typeEtudiant etd1 , typeEtudiant etd2 )
8 f
9 return ( strcmp ( etd1 . pers . nom, etd2 . pers . nom) ) ;
10 g
11 int
12 rechercheEtudiant ( typeEtudiant etd , typeEtudiant tabEtudiants [ ] , int t a i l l e )
13 /  rechercheEtudiant : recherche s é q u e n t i e l l e , basée sur le nom
14  d ' un enregistremnt de typeEtudiant .
15  A FAIRE : recherche dichotomique = > tableau trie .
16  /
17 f
18 int i ;
19
20 for ( i = 0 ; i < t a i l l e ; i ++)
21 if ( compEtudiant ( etd , tabEtudiants [ i ])==0)
22 return ( i ) ;
23
24 return (NON_TROUVE) ;
25 g
26 void
27 triTabEtudiants ( typeEtudiant tabEtudiants [ ] , int deb , int fin )
28 f
29 int g , d ;
30 typeEtudiant pivot ;
31
32 pivot = tabEtudiants [ deb ] ;
33 for ( g = deb , d = fin ; g < d ; )
34 f
35 for ( ; compEtudiant ( tabEtudiants [ d ] , pivot ) > 0 ; d );
36
37 if ( g != d)
38 f
39 tabEtudiants [ g ] = tabEtudiants [ d ] ;
40 tabEtudiants [ d ] = pivot ;
41 g++;
42 g
43 for ( ; compEtudiant ( tabEtudiants [ g ] , pivot ) < 0 ; g++);
44
45 if ( g != d)
46 f
47 tabEtudiants [ d ] = tabEtudiants [ g ] ;
48 tabEtudiants [ g ] = pivot ;
49 d ;
50 g
51 g
52 if ( deb < g 1 ) triTabEtudiants ( tabEtudiants , deb , g 1 ) ;
53 if ( fin > g+1 ) triTabEtudiants ( tabEtudiants , g+1 , fin ) ;
54 g

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


92 Chapitre4. Application : Base de Données Universitaire
tabEtudiantsV2.h

1 #include " etudiant . h"


2
3 #define NON_TROUVE 1
4
5 void triTabEtudiants ( typeEtudiant tabEtudiants [ ] , int deb , int fin ) ;
6 int rechercheEtudiant ( typeEtudiant etd , typeEtudiant tabEt [ ] , int t a i l l e ) ;

tabEtudiantsV2Test.c

1 #include<stdio . h>
2 #include " tabEtudiants . h"
3 #define TAILLE_TAB_ET 4
4
5 int main( void )
6 f
7 typeEtudiant tabEtudiants [TAILLE_TAB_ET] , etd ;
8 int i ;
9
10 p r in t f ( " n tVersion 2 n n n n" ) ;
11 saisieTabEtudiants ( tabEtudiants , TAILLE_TAB_ET) ;
12 afficheTabEtudiants ( tabEtudiants , TAILLE_TAB_ET) ;
13 triTabEtudiants ( tabEtudiants , 0 , TAILLE_TAB_ET 1 ) ;
14 afficheTabEtudiants ( tabEtudiants , TAILLE_TAB_ET) ;
15 while ( 1 )
16 f
17 p r in t f ( " Nom ? n n" ) ; scanf ("%s " , etd . pers . nom) ;
18 if ( strcmp ( etd . pers . nom, "0") == 0 ) return ( 0 ) ;
19 if (( i = rechercheEtudiant ( etd , tabEtudiants , TAILLE_TAB_ET) ) != NON_TROUVE)
20 a f f ic h e Et u dia nt ( tabEtudiants [ i ] ) ;
21 else
22 p r in t f ( " Il n' y aucun etudiant au nom de %s n n" , etd . pers . nom) ;
23 g
24 g

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


4.7 Implantation des améliorations 93

4.7.2 Implantation de la version 3


tabEtudiantsV3bis.c

1 /  A FAIRE : recherche dichotomique ;


2  Modification d ' element de tableau .
3  Les fonctions compEtudiant et recherche sont i d e n t i q u e s a la version 2 ,
4  e l l e ne sont pas recopiees i c i mais doivent l ' etre pour une version
5  operationnelle .
6 /
7 #include < s t d lib . h>
8 #include < s t r in g . h>
9 #include " tabEtudiantsV0 . h"
10 #include " tabEtudiantsV3 . h"
11
12 void triTabEtudiants ( int index [ ] , typeEtudiant tabEtudiants [ ] , int deb , int fin )
13 f
14 int g , d ;
15 int pivot ;
16
17 pivot = index [ deb ] ;
18 for ( g = deb , d = fin ; g < d ; )
19 f
20 for ( ; compEtudiant ( tabEtudiants [ index [ d ] ] , tabEtudiants [ pivot ]) > 0 ; d );
21 if ( g != d)
22 f
23 index [ g ] = index [ d ] ;
24 index [ d ] = pivot ;
25 g++;
26 g
27 for ( ; compEtudiant ( tabEtudiants [ index [ g ] ] , tabEtudiants [ pivot ]) < 0 ; g++);
28 if ( g != d)
29 f
30 index [ d ] = index [ g ] ;
31 index [ g ] = pivot ;
32 d ;
33 g
34 g
35 if ( deb < g 1 ) triTabEtudiants ( index , tabEtudiants , deb , g 1 ) ;
36 if ( fin > g+1 ) triTabEtudiants ( index , tabEtudiants , g+1 , fin ) ;
37 g
38 void
39 initInde x ( int index [ ] , int t a i l l e )
40 f
41 int i ;
42
43 for ( i=0 ; i < t a i l l e ; i ++)
44 f
45 index [ i ] = i ;
46 g
47 g
48 void
49 afficheParInde x ( typeEtudiant tabEtudiants [ ] , int index [ ] , int t a i l l e )
50 f
51 int i ;
52
53 for ( i=0 ; i < t a i l l e ; i ++)
54 a f f ic he E t ud ian t ( tabEtudiants [ index [ i ] ] ) ;
55 g

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


94 Chapitre4. Application : Base de Données Universitaire
tabEtudiantsV3.h

1 #include " etudiant . h"


2
3 #define NON_TROUVE 1
4
5 void initInde x ( int index [ ] , int t a i l l e ) ;
6 void triTabEtudiants ( int index [ ] , typeEtudiant tabEt [ ] , int deb , int fin ) ;
7 void afficheParIndex ( typeEtudiant tabEtudiants [ ] , int index [ ] , int t a i l l e ) ;

4.8 Version 4
 utilisation de la fonction  générique  de tri rapide, qsort, de la bibliothèque standard ;
 utilisation d'un tableau de pointeurs pour l'indexage auxiliaire ;
 gestion des inclusions multiples de chiers d'en-tête.
4.8.1 La fonction générique qsort
La fonction qsort permet de trier un tableau de n'importe quel type à condition de fournir une
fonction de comparaison (cf. 4.6) et certaines informations sur le type des éléments du tableau. Sa
déclaration est la suivante :
void qsort(void base, size_t nel, size_t width, int (compar) (const void , const void ));
 base : pointeur (ou adresse) du début ;
 nel : nombre d'éléments (taille) du tableau ;
 width : taille (seule information nécessaire) de chaque élément;
 compar : fonction de comparaison par accès indirect (pointeurs) de deux éléments ;

void * est un pointeur générique qui peut pointer sur n'importe quel type.
4.8.2 Gestion des inclusions multiples
Inclure des chiers d'en-tête dans d'autres chiers d'en-tête comporte le risque d'inclure plusieurs
fois un même chier. Par exemple, après intégration du module enseignant, on trouvera dans le module
principal :
#include "tabEtudiants.h"
#include "tabEnseignants.h"
Ces deux chiers incluent respectivement "etudiant.h" et "enseignant.h", qui à leur tour incluent
chacun "personne.h". Ce dernier sera donc inclus deux fois dans le module principal, ce qui provoquera
des erreurs (p.e. typePersonne sera déni deux fois).
Pour résoudre ce problème on fait appel au préprocesseur 1 pour eectuer de la compilation condi-
tionnelle : chaque chier d'en-tête, p.e. monModule.h, a alors la forme suivante :
#ifndef MONMODULE_H / constante symbolique quelconque /
#dene MONMODULE_H / sera denie a la premiere inclusion /
/ corps de monModule.h /
#endif
La première ligne indique qui la suite (jusqu'à la directive #endif) sera prise en compte si la constante
MONMODULE_H n'est pas dénie. Dans ce cas, celle-ci sera dénie dans la ligne suivante, ce qui ne peut se
produire qu'une seule fois.
Le test #ifndef (if not dened ) est un cas particulier des tests reconnus par le préprocessuer et dont
la forme générale est :
#if EXPRESSION
...
#else
1. On rappelle que le préprocesseur exécute les directives (comme #define et #include) avant la compilation. Pour être
distinguées des mots clefs, variables, etc., les directives commencent toutes par #.

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


4.8 Version 4 95

...
#endif
les lignes qui suivent la directive #if seront traitées normalement si EXPRESSION est vériée, sinon
elles seront ignorées, et ce sont celles qui suivent la directive #else qui seront traitées.
EXPRESSION est une expression booléenne (qui peut utiliser les opératuers logiques du C) sur des
constatntes et des constantes symboliques.

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


Algorithmes
Squelette des shells Unix ... .... .... ... .... .... .... .... .... ... .... .... .... .. .. .... ... .... .... .... ...5
Somme des N premiers entiers positifs . .... .... ... .... .... .... .... .... ... .... .... .... .... .... ... ...56
Recherche séquentielle dans un tableau : analyse .. .... .... ... .... .... .... .... .... ... .... .... .... ...58
Recherche séquentielle dans un tableau : ranement . .... .... .... ... .... .... .... .... .... .... ... .... 58
Recherche séquentielle dans un tableau : conception .. .... .... .... ... .... .... .... .... .... ... .... ... 58
Recherche dichotomique : anlayse . ... .... .... .... .... .... ... .... .... .... .... .... ... .... .... .... ....58
Recherhce dichotomique ... .... ... .... .... .... .... .... ... .... .... .... .... . ... ... .... .... .... .... ...59
Tri direct : analyse ... .... .... ... .... .... .... .... .... ... .... .... .... .. .. .... .... ... .... .... .... .... 61
Tri direct .. .... ... .... .... .... .... .... .... ... .... .... .... ... . .... ... .... .... .... .... .... ... .... ... 61
... .... .... ... .... .... .... .... .... .... ... .... .... .. .. .... .... ... .... .... .... .... .... ... .... .... ....63
Tri Bulles . .... .... ... .... .... .... .... .... ... .... .... .... .... .... .... ... .... .... .... .... .... ... .... 64
Tri bulles à alternation (shake sort ) ... ... .... .... .... .... .... ... .... .... .... .... .... .. . .... .... ... 64
Tri rapide ... .... .... .... .... .... ... .... .... .... .... .... ... .. .. .... .... .... .... ... .... .... .... .... .67
Test liste vide ... .... .... .... .... .... .... ... .... .... .... .... .... . .. .... .... .... .... .... ... .... .... .73
Élément suivant dans une liste ... .... .... .... .... ... .... .... .... .... .... .... ... .. .. .... .... .... ... 73
Test de n de liste . .... .... .... .... ... .... .... .... .... .... .... ... .... .... .... .... .... ... .... .... .. 73
Parcours d'une liste . .... .... .... ... .... .... .... .... .... ... .... .... .... .... .... ... .... .... .... .... . 73
Achage de liste .... .... ... .... .... .... .... .... ... .... .... .... .... . ... ... .... .... .... .... .... .... .73
Recherche d'élément dans une liste . .... ... .... .... .... .... .... ... .... .... .... .... .... .... ... .... .. 73
Insertion directe d'un élément dans une liste .... .... ... .... .... .... .... .... ... .... .... .... .... .... 74
Saisie de liste .. .... .... .... ... .... .... .... .... .... ... .... .... ... . .... .... ... .... .... .... .... .... .. 74
Suppression directe d'un élément dans une liste . .... .... .... .... .... ... .... .... .... .... .... .... ... 74
Insertion par copie dans une liste avec sentinelle .. .... ... .... .... .... .... .... ... .... .... .... .... ...75
Suppression par copie dans une liste avec sentinelle ... .... .... .... .... .... ... .... .... .... .... .... ..75
Test de n de liste avec sentinelle . .... .... ... .... .... .... .... .... ... .... .... .... .... .... .... ... ... 75
Saisie de liste triée .. .... .... .... ... .... .... .... .... .... .... ... .... ... . .... .... .... ... .... .... .... . 75
Recherche dans une liste triée .. .... .... ... .... .... .... .... .... ... .... .... .... ... . .... ... .... .... .. 76
Insertion dans une liste triée ... .... ... .... .... .... .... .... .... ... .... .... .... .. .. .... ... .... .... .. 76
Insertion par copie dans une liste triée .. .... ... .... .... .... .... .... ... .... .... .... .... .... ... .... . 76
Amélioration de l'insertion avec copie dans une liste triée .... ... .... .... .... .... .... ... .... .... ....76

i
ii ALGORITHMES

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


Programmes
Arguments d'appel de programme : argProg.c ... .... .... .... .... .... ... .... .... .... .... .... ... ...28
Exemple d'utilisation de tableau : explTableau.c ... ... .... .... .... .... .... ... .... .... .... .... ... 38
Exemple d'utilisation de pointeur : explPointeur.c . .... .... ... .... .... .... .... .... ... .... .... ... 39
Modication de paramètres de fonctions : explMdfParFct.c . .... .... .... .... ... .... .... .... .... .. 41
Structures récursives : strucRcrsv.c ... .... ... .... .... .... .... .... ... .... .... .... .... .... ... .... . 44
Structures récursives, déntion de type : strucRcrsvType.h . ... .... .... .... .... .... ... .... .... ... 45
Version (très) simpliée de la commande cat : mCat.c . .... .... .... .... .... .... ... .... .... .... .... 46
Identication d'utilisateur : identite.c .... .... .... .... .... ... .... .... .... .... .... ... .... .... .... 48
Identication d'utilisateur, module de test : principal.c ... .... .... .... .... .... ... .... .... .... ... 49
Identication d'utilisateur (interface) : identite.h . .... .... .... .... ... .... .... .... .... .... ... .... 50
Identication d'utilisateur, module de test (interface) : principal.h .... .... .... .... .... ... .... ... 50
Somme des N premiers entiers positifs : sommeNentiers.c . .... ... .... .... .... .... .... ... .... .... . 56
Recherche dihotomique, version récursive (implantation) : rechDichRec.c .... .... .... ... .... .... ..59
Recherche dihotomique, version récursive (interface) : rechDichRec.h .... .... .... .... .... ... .... ..59
Recherche dihotomique, version itérative (implantation) : rechDichIt.c ... .... .... .... .... ... .... 60
Recherche dihotomique, version itérative (interface) : rechDichIt.h .... .... .... .... ... .... .... ....60
Test de la recherche dihotomique : rechDichTest.c .. .... .... .... .... .... ... .... .... .... .... .... ..60
Permutation de deux éléments dans un tableau (implantation) : permuter.c ... .... ... .... .... .... 62
Permutation de deux éléments dans un tableau (interface) : permuter.h ... .... .... .... ... .... .... 62
Tri direct (implantation) : triDirectRec.c ... .... ... .... .... .... .... .... ... .... .... .... .... .... .. 62
Tri direct (inerface) : triDirectRec.h .. ... .... .... .... .... .... ... .... .... .... .... .... .... ... .... . 62
Tri direct  programme de test : triDirectTest.c ... .... .... ... .... .... .... .... .... ... .... .... ...63
Tri bulles (implantation) : triBulTab.c ... .... .... .... .... ... .... .... .... .... .... .... ... .... .... ..65
Tri bulles (interface) : triBulTab.h .... ... .... .... .... .... .... ... .... .... .... .... .... . ... ... .... ..65
Tri bulles  programme detest : triBulTest.c ... .... .... .... .... ... .... .... .... .... .... ... .... ... 66
Tri (rapide) par séparation (implantation) : triSep.c .. .... .... .... .... .... ... .... .... .... .... ....68
Tri (rapide) par séparation (interface) : triSep.h ... ... .... .... .... .... .... .... ... .... .... .... .... 68
Tri (rapide) par séparation  programme de test : triSepTest.c .. .... ... .... .... .... .... .... ... ..69
Déntion de n÷d de liste chaînée (interface) : noeud.h . .... .... ... .... .... .... .... .... ... .... .... .71
Déntion de n÷d de liste chaînée (implantation) : noeud.c . ... .... .... .... .... .... ... .... .... .... .72
Dénition du type liste avec sentinelle : listesSent.h .. .... .... .... .... .... ... .... .... .... .... ... 75
Déntion du type dates (implantation) : dates.c ... .... ... .... .... .... .... .... ... .... .... .... ... 83
Déntion du type dates (interface) : dates.h .... ... .... .... .... .... .... ... .... .... .... .... .... ...83
Déntion du type dates  programme de test : datesTest.c ... .... ... .... .... .... .... .... ... .... .84
Déntion du type personne (interface) : personne.h ... ... .... .... .... .... .... ... .... .... .... .... .84
Déntion du type personne (implantation) : personne.c .. .... ... .... .... .... .... .... ... .... .... . 85
Déntion du type personne  programme de test : personneTest.c . .... .... .... ... .... .... .... .. 85
Déntion du type etudiant (implantation) : etudiant.c .. .... ... .... .... .... .... .... ... .... .... . 85
Déntion du type etudiant (interface) : etudiant.h ... ... .... .... .... .... .... ... .... .... .... .... .86
Déntion du type etudiant  programme de test : etudiantTest.c . .... .... .... ... .... .... .... .. 86
Déntion du tableau d'étudiants (implantation) : tabEtudiantsV1.c ... .... ... .... .... .... .... ....87
Déntion du tableau d'étudiants (interface) : tabEtudiantsV1.h ... .... .... .... ... .... .... .... .... 87
Déntion du tableau d'étudiants  programme de test : tabEtudiantsV1Test.c .. .... .... .... .... .88
BDU Version 2 (implantation) : tabEtudiantsV2.c .. .... .... .... ... .... .... .... .... .... ... .... ... 91
BDU Version 2 (interface) : tabEtudiantsV2.h .. .... .... .... .... .... ... .... .... .... .... .... ... ... 92
BDU Version 2, module de test : tabEtudiantsV2Test.c .... .... ... .... .... .... .... .... ... .... ... 92
BDU Version 3 (implantation) : tabEtudiantsV3bis.c . .... .... .... .... ... .... .... .... .... .... ... 93
BDU Version 3 (interface) : tabEtudiantsV3.h .. .... .... .... .... .... ... .... .... .... .... .... ... ... 94

iii
iv PROGRAMMES

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


Table des gures
1.1 Unix comme environnement d'utilisation et de programmation. . . . . . . . . . . . . . . 3
1.2 Présentation générale d'un ltre Unix. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
1.3 Utilisation des tubes avec les ltres Unix. . . . . . . . . . . . . . . . . . . . . . . . . . . 19
2.1 Représentation schématique d'une structure autoréférentielle . . . . . . . . . . . . . . . 43
2.2 Enchaînement de structures autoréférentielles . . . . . . . . . . . . . . . . . . . . . . . . 43
2.3 Insertion d'un élément dans une liste chaînée. . . . . . . . . . . . . . . . . . . . . . . . . 44
2.4 Phases de production d'un programme exécutable . . . . . . . . . . . . . . . . . . . . . . 47
2.5 Précompilation des deux modules de l'exemple. . . . . . . . . . . . . . . . . . . . . . . . 52
2.6 Compilation et d'édition des lien des deux modules de l'exemple. . . . . . . . . . . . . . 53
3.1 Représentation schématique d'une liste chaînée. . . . . . . . . . . . . . . . . . . . . . . . 71
3.2 Représentation schématique d'une liste circulaire doublement chaînée avec sentinelle. . . 77
4.1 Conception générale de l'application BDU . . . . . . . . . . . . . . . . . . . . . . . . . . 82

v
vi TABLE DES FIGURES

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


Liste des tableaux
1.1 Variables internes (prédénies) du C-Shell. . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.2 Quelques commandes de manipulation de chiers sous Unix. . . . . . . . . . . . . . . . 13
1.3 Modicateurs de rappel de commande et de nom de chier . . . . . . . . . . . . . . . . . 23
1.4 Expressions spéciques sur les varaibles en C Shell . . . . . . . . . . . . . . . . . . . . . 24
1.5 Opérateurs du C Shell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
1.6 Tests sur les chiers en C Shell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
1.7 Commandes interne de contrôle du C Shell . . . . . . . . . . . . . . . . . . . . . . . . . 26
1.8 Autres commandes interne du C Shell . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
2.1 Types simples du langage C. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
3.1 Complexité des algorithmes de tri direct [8] . . . . . . . . . . . . . . . . . . . . . . . . . 66
3.2 Comparasion des performances  réelles  des algorithmes de tri. . . . . . . . . . . . . . 69

vii
viii LISTE DES TABLEAUX

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


Table des matières
1 Introduction au système d'exploitation Unix 3
1.1 Débuter Unix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.1.1 La structure d'Unix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.1.2 Caractéristiques d'Unix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.2 Environnement de l'utilisateur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.2.1 Le terminal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.2.2 Caractéristiques de l'utilisateur . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.2.3 Interpréteurs de commandes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.3 Introduction au C-Shell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.3.1 Interprétation des commandes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.3.2 Variables prédénies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.3.3 Variables d'environnement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.3.4 Conguration du C-Shell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.4 Notion de système de chiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.4.1 La table des i-nodes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.4.2 Fichiers et types de chiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.4.3 Commandes de manipulation de chiers . . . . . . . . . . . . . . . . . . . . . . . 12
1.4.4 La commande ls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.4.5 La commande find . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.4.6 La commande tar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.5 Fichiers texte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
1.5.1 Les Expressions Régulières . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
1.5.2 La commande egrep . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
1.5.3 Les ltres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
1.6 La programmation en C-Shell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
1.6.1 Substitution de nom de chier . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
1.6.2 Variables internes du C Shell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
1.6.3 Rappel de commande et modicateurs de mots . . . . . . . . . . . . . . . . . . . 22
1.6.4 Expressions et opérateurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
1.6.5 Commandes internes (built-in ) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
1.6.6 Analyse du script annuRech.csh . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
1.6.7 Exercice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
1.7 Processus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
1.7.1 Caractéristiques des processus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
1.7.2 Exemples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
1.7.3 Processus et langage C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
1.7.4 Processus et shell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
1.7.5 Commandes de manipulation des processus . . . . . . . . . . . . . . . . . . . . . 29
2 Le langage C 31
2.1 Le langage C en bref (Rappels) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
2.1.1 Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
2.1.2 Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
2.1.3 Valeurs constantes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
2.1.4 Aectation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
2.1.5 Opérateurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
2.1.6 Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
2.1.7 Instructions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
2.1.8 Lecture du langage C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
2.1.9 Fonctions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
ix
x TABLE DES MATIÈRES

2.1.10 Bibliothèques et utilisation des fonctions prédénies . . . . . . . . . . . . . . . . 35


2.2 De l'applicatif à l'impératif : de CAML à C . . . . . . . . . . . . . . . . . . . . . . . . . 36
2.3 Structure de données en C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
2.3.1 Tableaux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
2.3.2 Pointeurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
2.3.3 Enregistrements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
2.3.4 Types et dénition de type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
2.3.5 Structures autoréférentielles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
2.3.6 Unions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
2.4 Accès aux chiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
2.4.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
2.4.2 Fonctions de manipulation de chiers . . . . . . . . . . . . . . . . . . . . . . . . . 45
2.4.3 Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
2.5 La compilation Séparée . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
2.5.1 Production de programme exécutable . . . . . . . . . . . . . . . . . . . . . . . . 46
2.5.2 Utilisation de la compilation Séparée . . . . . . . . . . . . . . . . . . . . . . . . . 47
2.5.3 Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
3 Algorithmique et structures de données avancées 55
3.1 Fondements et principes de l'algorithmique . . . . . . . . . . . . . . . . . . . . . . . . . 55
3.1.1 Éléments de conception d'algorithmes . . . . . . . . . . . . . . . . . . . . . . . . 55
3.2 Exemple : calcul de la somme des N premiers entiers positifs . . . . . . . . . . . . . . . . 55
3.2.1 Analyse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
3.2.2 Conception . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
3.2.3 Implantation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
3.2.4 Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
3.3 Pratique du développement d'algorithmes . . . . . . . . . . . . . . . . . . . . . . . . . . 57
3.4 Notion de complexité d'algorithme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
3.5 Algorithmes de recherche dans un tableau . . . . . . . . . . . . . . . . . . . . . . . . . . 57
3.5.1 Recherche Séquentielle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
3.5.2 Recherche Dichotomique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
3.6 Algorithmes de tri de tableau . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
3.6.1 Tri direct . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
3.6.2 Tri par échange (tri-bulles) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
3.6.3 Implatation et test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
3.6.4 Tri par séparation (tri rapide) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
3.7 Types de données abstraits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
3.7.1 Incarnation d'un TDA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
3.7.2 Programmation à l'aide des TDA . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
3.7.3 Avantages des TDA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
3.7.4 Inconvénients des TDA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
3.7.5 Le TDA Liste . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
3.8 Listes Chaînées . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
3.8.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
3.8.2 Opérations sur les listes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
3.8.3 Implantation simple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
3.8.4 Implantation avec sentinelle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
3.8.5 Listes triées . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
3.9 Piles et queues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
3.9.1 Élimination des appels récursifs à l'aide des piles . . . . . . . . . . . . . . . . . . 77
3.10 Arbres binaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
4 Application: Base de Données Universitaire 79
4.1 Description du problème . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
4.2 Analyse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
4.2.1 Ranement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
4.3 Conception . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
4.3.1 Types et données . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
4.4 Notions de module et de modularité . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
4.5 Première implantation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
4.5.1 Module dates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
4.5.2 Module personne . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998
TABLE DES MATIÈRES xi

4.5.3 Module etudiant . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85


4.5.4 Module tabEtudiants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
4.6 Améliorations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
4.6.1 Version 2 : tri du tableau  adaptation du tri rapide . . . . . . . . . . . . . . . . 88
4.6.2 Version 3 : utilisation de tableaux auxiliaires d'indices . . . . . . . . . . . . . . . 89
4.7 Implantation des améliorations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
4.7.1 Implantation de la version 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
4.7.2 Implantation de la version 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
4.8 Version 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
4.8.1 La fonction générique qsort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
4.8.2 Gestion des inclusions multiples . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


Index
< (caractère spécial ), 7 (
${?var} opérateur ), 24
> (caractère spécial ), 7 (
${n} opérateur ), 24
(
' ' caractère spécial ), 8 $argv[*] opérateur ( ), 24
(
' ' opérateur ), 22 $argv[n] opérateur ( ), 24
(
( caractère spécial ), 17 (
$n opérateur ), 24
(
( ) opérateur ), 42 (
% caractère spécial ), 9
(
() opérateur ), 34 (
% opérateur ), 24
(
(...) opérateur ), 24 (
% caractère spécial ), 9
(
) caractère spécial ), 17 (
%m caractère spécial ), 9
(
* caractère spécial ), 7, 15, 17, 21 (
& caractère spécial ), 9
(
* opérateur ), 24, 32, 34, 39 (
& opérateur ), 24, 39, 40
(
*= opérateur ), 32 (
&& opérateur ), 24, 32
(
+ opérateur ), 24, 32 édition
(
+= opérateur ), 32 des liens, 48
(
- opérateur ), 24, 32 élément, 71
(
-= opérateur ), 32  (caractère spécial ), 17
(
. opérateur ), 41  (opérateur ), 24
(
.c chier ), 16, 47 D (caractère spécial ), 20
(
.cshrc chier ), 11 déntion de type
(
.h chier ), 48 syntaxe, 42
(
.o chier ), 16, 47, 48 do
(
/ opérateur ), 24, 32 syntaxe, 33
(
/= opérateur ), 32 enregistrement
(
/dev répertoire ), 4 syntaxe, 41, 42
/etc/group chier ( ), 4 for
/etc/passwd chier ( ), 4 syntaxe, 34
(
/usr/bin répertoire ), 10 if
/usr/include répertoire( ), 32 syntaxe, 33
(
< opérateur ), 24, 32 matrice
(
 opérateur ), 24 syntaxe, 36
(
<= opérateur ), 24, 32 pointeur
(
= opérateur ), 32 syntaxe, 38
(
== opérateur ), 24, 32 tableau
(
= opérateur ), 24 syntaxe, 36
(
> opérateur ), 24, 32 while
(
>= opérateur ), 24, 32 syntaxe, 33
(
 opérateur ), 24 syntaxe, 33
(
? opérateur ), 33  (caractère spécial ), 9, 21
(
[ caractère spécial ), 17  (opérateur ), 24
(
[ ] opérateur ), 42
(
[...] caractère spécial ), 7, 21 *(opérateur ), 42
(
[] opérateur ), 34 @ (caractère spécial ), 9
(
#define directive ), 37, 47, 94
(
#else directive ), 95 a.out (chier ), 16
(
#endif directive ), 94 accès
(
#if directive ), 95 à une variable, 31
(
#ifndef directive ), 94 chemin d', 9, 15
(
#include directive ), 47, 94 direct, 43
(
$ caractère spécial ), 7, 9, 17 droits d', 14
(
$* opérateur ), 24, 25 indexé, 36
(
$< opérateur ), 24 indexé indirect, 89
(
$?var opérateur ), 24 indirect, 3840, 43
xii
INDEX xiii

adresse, 39 (
cd commande ), 6, 8, 13, 25, 26
aectation, 31 (
cdpath variable ), 26
algorithme, 55 chaîne
alias (commande ), 6 caractère de n de, 37
allocation de caractères, 37
dynamique, 39 champ, 41
statique, 39 char (type ), 31, 41, 42
appel chargement
de fonction, 35 de programme, 27
arguments d', 27, 28 chdir (commande ), 26
argc (variable ), 28 chemin
argument, 5 d'accès, 9, 15
arguments chgrp (commande ), 5
d'appel, 27, 28 chmod (commande ), 1214
argv (variable ), 28 chown (commande ), 5
arrêt classes de caractères, 17
condition d', 33 clef, 75
arrière plan, 5, 9 clonage, 27
ASCII cmp (commande ), 13
code, 32 code
table, 32 ASCII, 32
autoréférentielles objet, 47
structures, 71 comm (commande ), 13
awk (commande ), 4, 19 commande, 5
bash (commande ), 5
interpréteur de, 5
bibliothèque, 35 ligne de, 5
standard, 12, 35, 37, 39, 40, 47 rappel de, 22
alias, 6
boucle, 33 awk, 4, 19
break (commande ), 26
bash, 5
BUS (constante ), 30
break, 26
calloc (fonction ), 39, 40 cat, 8, 13, 20, 46
caractère cc, 4
de n de chaîne, 37 cd, 6, 8, 13, 25, 26
constant, 32 chdir, 26
normal, 16 chgrp, 5
spécial, 16 chmod, 1214
caractère spécial chown, 5
<, 7 cmp, 13
>, 7 comm, 13
' ', 8 continue, 26
(, 17 cp, 13
), 17 csh, 5, 6, 911
*, 7, 15, 17, 21 cut, 13, 27
[, 17 diff, 13
[...], 7, 21 echo, 6, 8, 27
$, 7, 9, 17 ed, 16
%, 9 egrep, 12, 17, 19, 21
%, 9 else, 25
%m, 9 emacs, 9
&, 9 end, 25, 26
, 17 exec, 26
D, 20 exit, 5, 2426
, 9, 21 find, 12, 13, 15
@, 9 foreach, 21, 2527
caractères getty, 28
chaîne de, 37 goto, 26
lignes de, 19 grep, 4, 19, 25
spéciaux, 5 history, 22
cat (commande ), 8, 13, 20, 46 id, 4
cc (commande ), 4 if, 6, 24, 26, 27

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


xiv INDEX

if...then , 25 NULL , 40, 46, 71


incorporée, 5 SEGV , 30
init, 28 true , 25
interne, 5, 21 VRAI , 31, 33
jsh, 5 constructeur, 42
kill, 30 continue (commande ), 26
ksh, 5 conversion
ln, 13, 27 de type, 32, 35
logname, 4 corps
lp, 8 de fonction, 35
ls, 68, 10, 1214, 19, 27 courant
man, 12, 29, 35, 36 environnement, 27
mkdir, 13 répertoire, 9, 10, 26
more, 7, 8, 13 cp (commande ), 13
mv, 13 création
newgrp, 5 de processus, 27
nl, 8 csh (commande ), 5, 6, 911
paste, 13 cut (commande ), 13, 27
ps, 29 cwd (variable ), 9, 10
pwd, 13
repeat, 26
d'accès
rm, 13
mode, 14
rmdir, 13
déclaration
sed, 16, 19
de fonction, 35
set, 6, 9, 10, 21, 22, 24, 27
de variable, 31
setenv, 10
dénition
sh, 5, 6
de fonction, 35
sort, 13, 19
de type, 42, 45
stty, 4
de variable, 31
diff (commande ), 13
switch, 25, 26
tail, 19
direct
tar, 12, 13, 15
accès, 43
tcsh, 9
directive, 35
#define, 37, 47, 94
time, 6
#else, 95
times, 6
#endif, 94
tr, 19
#if, 95
troff, 4
#ifndef, 94
unset, 22
#include, 47, 94
wc, 13, 19
do (instruction ), 34
which, 10
données
while, 2426
structure de, 43
who, 6
dynamiques, 27
compilateur, 48 statiques, 27
composé droits
type, 31 d'accès, 14
composée dynamique
instruction, 35 allocation, 39
condition dynamiques
d'arrêt, 33 données, 27
conguration
chier de, 11 (
echo commande ), 6, 8, 27
constant (
ed commande ), 16
caractère, 32 eet de bord, 33
entier, 31, 37 egrep (commande ), 12, 17, 19, 21
pointeur, 39 else (commande ), 25
constante else (instruction ), 33
BUS, 30 emacs (commande ), 9
EOF, 46 en-tête
false, 25 de fonction, 35
FAUX, 3133 chier d', 35, 48
KILL, 30 end (commande ), 25, 26

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


INDEX xv

enregistrement, 41 corps de, 35


modèle d', 42 déclaration de, 35
entier dénition de, 35
constant, 31, 37 en-tête de, 35
entrée nom de, 35
standard, 7, 19, 20, 24, 46 paramètres de, 35
entrée standard (chier ), 13 prototype de, 35
environnement, 27 signature de, 35
courant, 27 type de, 35
variable d', 29 utilisation de, 35
variables d', 11, 27 valeur de, 35
EOF (constante ), 46 calloc, 39, 40
erreur exec, 4
d'exécution, 30 fopen, 46
exécutable fork, 4
programme, 47 fprintf, 12, 46
exécution fscanf, 46
erreur d', 30 getc, 35, 36, 46
exec (commande ), 26 main, 9, 28
exec (fonction ), 4 malloc, 39
exit (commande ), 5, 2426 pipe, 4
expression, 32, 33 printf, 35, 46
conditionnelle, 33 putc, 46
expression régulière, 16 scanf, 35, 40, 46
Expressions Régulières sqrt, 35
en C Shell, 21 strcat, 40
strcmp, 37, 89
(
false constante ), 25 strcpy, 37, 40
(
FAUX constante ), 3133 strlen, 40
chier, 12 fopen (fonction ), 46
.c, 16, 47 for (instruction ), 34, 37
.cshrc, 11 foreach (commande ), 21, 2527
.h, 48 fork (fonction ), 4
.o, 16, 47, 48 fprintf (fonction ), 12, 46
/etc/group, 4 fscanf (fonction ), 46
/etc/passwd, 4
de conguration, 11 (
getc fonction ), 35, 36, 46
pointeur de, 46 (
getty commande ), 28
a.out, 16 (
GID paramètre système ), 5
d'en-tête, 35, 48 (
goto commande ), 26
entrée standard, 13 (
grep commande ), 4, 19, 25
float.h, 32 groupe, 4
limit.h, 32
normal, 12, 14, 46 history commande( ), 22
périphérique, 4 history variable( ), 22
source, 47 (
HOME répertoire ), 11, 15
stdin, 46 (
HOME variable d'environnement ), 10, 13, 21, 26
stdio.h, 35, 46 (
home variable ), 9
stdout, 46
string.h, 37 i-node, 11, 46
texte, 16 number, 12
chiers i-nodes, 14
tests sur, 25 table des, 11
FILE (type ), 46 id (commande ), 4
ls if (commande ), 6, 24, 26, 27
processus, 27 if (instruction ), 33
ltre, 12, 19, 46 if...then (commande ), 25
find (commande ), 12, 13, 15 image
float (type ), 31, 41, 42 mémoire, 27
float.h (chier ), 32 incorporée
fonction commande, 5
appel de, 35 index node, 11
Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998
xvi INDEX

indexé allouée dynamiquement, 39


accès, 36 image, 27
indexé indirect main (fonction ), 9, 28
accès, 89 malloc (fonction ), 39
indexage, 36, 42, 43 man (commande ), 12, 29, 35, 36
indices MANPATH (variable d'environnement ), 29
tableau auxiliaire d', 89 membre, 41
indirect mkdir (commande ), 13
accès, 3840, 43 modèle
indirection, 42 d'enregistrement, 42
init (commande ), 28 mode
initialisation d'accès, 14
de variable, 31 modicateur, 23
instruction Module, 82
composée, 33, 35 module, 47
do, 34 more (commande ), 7, 8, 13
else, 33 mot
for, 34, 37 de passe, 28
if, 33 mot de passe, 4
simple, 33 mv (commande ), 13
struct, 41, 42
typedef, 42 n÷ud, 71
union, 42 newgrp (commande ), 5
while, 33, 34 nl (commande ), 8
int (type ), 31, 41, 42 nom
interne de fonction, 35
commande, 5, 21 de login, 4
variable, 21 de variable, 31
interpréteur normal
de commande, 5 caractère, 16
invite, 5, 7, 9, 11 chier, 14, 46
nouvelle-ligne, 16
jsh (commande ), 5 noyau, 46
NULL (constante ), 40, 46, 71
(
KILL constante ), 30 numéro
(
kill commande ), 30 d'utilisateur, 4
(
ksh commande ), 5 number
i-node, 12
lien, 12, 13, 14, 27, 28
liens objet
édition des, 48 code, 47
ligne, 16, 16 opérateur, 32
de commande, 5 ' ', 22
lignes ( ), 42
de caractères, 19 (), 34
limit.h (chier ), 32 (...), 24
liste, 71 *, 24, 32, 34, 39
queue de, 71 *=, 32
tête de, 71 +, 24, 32
triée, 75 +=, 32
liste chaînée, 71 -, 24, 32
liste séquentielle, 71 -=, 32
liste séquentielle chaînée, 71 ., 41
ln (commande ), 13, 27 /, 24, 32
login /=, 32
nom de, 4 <, 24, 32
logname (commande ), 4 , 24
lp (commande ), 8 <=, 24, 32
ls (commande ), 68, 10, 1214, 19, 27 =, 32
==, 24, 32
mémoire =, 24
alloué statiquement, 39 >, 24, 32

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


INDEX xvii

>= , 24, 32 de fonction, 35


, 24 (
ps commande ), 29
?, 33 (
putc fonction ), 46
[ ] , 42 (
PWD variable d'environnement ), 10
[] , 34 (
pwd commande ), 13
$* , 24, 25
$< , 24 qualicatifs
$?var , 24 de type, 31
${?var} , 24 queue
${n} , 24 de liste, 71
$argv[*] , 24
$argv[n] , 24 récursive
$n , 24 structure, 43
%, 24 référence, 39
&, 24, 39, 40 à une variable, 31
&& , 24, 32 répertoire, 12, 14, 15
, 24 /dev, 4
, 24 /usr/bin, 10
*, 42 /usr/include, 32
option, 5 de travail, 26
courant, 9, 10, 26
périphérique HOME, 11, 15
chier, 4 personnel, 4, 9
père racine, 9, 11, 13, 21
processus, 27 racine
paramètre répertoire, 9, 13, 21
passage de, 40 rappel
paramètre système de commande, 22
GID, 5 repeat (commande ), 26
PID, 27, 30 retour-chariot, 16
UID, 5, 30 rm (commande ), 13
paramètres rmdir (commande ), 13
de fonction, 35
passage sélection, 42
de paramètre, 40 scanf (fonction ), 35, 40, 46
passe script, 12
mot de, 28 sed (commande ), 16, 19
paste (commande ), 13 SEGV (constante ), 30
PATH (variable d'environnement ), 10 set (commande ), 6, 9, 10, 21, 22, 24, 27
path (variable ), 911, 25 setenv (commande ), 10
personnel sh (commande ), 5, 6
répertoire, 4, 9 shell, 4, 5
PID (paramètre système ), 27, 30 script, 21
PID (variable ), 28 shell (variable ), 9
pipe (fonction ), 4 signal, 30
pointeur, 38 signature
de chier, 46 de fonction, 35
sur type, 38 simple
constant, 39 type, 31
dans les listes chaînées, 71 sort (commande ), 13, 19
préprocessuer, 94 sortie
printf (fonction ), 35, 46 standard, 7, 19, 20, 46
processus, 27, 46 source
création de, 27 chier, 47
ls, 27 programme, 47
père, 27 spécial
programme caractère, 16
chargement de, 27 spéciaux
exécutable, 47 caractères, 5
source, 47 sqrt (fonction ), 35
prompt (variable ), 5, 911 standard
prototype bibliothèque, 12, 35, 37, 39, 40, 47
Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998
xviii INDEX

entrée, 7, 19, 20, 24, 46 (


troff commande ), 4
sortie, 7, 19, 20, 46 (
true constante ), 25
statique tube, 6, 8, 12, 19
allocation, 39 type, 36, 42
statiques conversion de, 32, 35
données, 27 dénition de, 42, 45
status (variable ), 9, 10, 25, 26 de fonction, 35
stdin (chier ), 46 de variable, 31
stdin (variable ), 46 pointeur sur, 38
stdio.h (chier ), 35, 46 qualicatifs de, 31
stdout (chier ), 46 char, 31, 41, 42
stdout (variable ), 46 composé, 31, 42
strcat (fonction ), 40 FILE, 46
strcmp (fonction ), 37, 89 float, 31, 41, 42
strcpy (fonction ), 37, 40 int, 31, 41, 42
string.h (chier ), 37 simple, 31, 42
strlen (fonction ), 40 typedef (instruction ), 42
struct (instruction ), 41, 42
structure (
UID paramètre système ), 5, 30
de données, 43 (
union instruction ), 42
autoréférentielle, 43 (
unset commande ), 22
récursive, 43 (
USER variable d'environnement ), 10
structures (
user variable ), 9
autoréférentielles, 71 utilisateur
stty (commande ), 4 numéro d', 4
switch (commande ), 25, 26 utilisation
syntaxe, 47 de fonction, 35
déntion de type, 42
do, 33 valeur
enregistrement, 41, 42 de fonction, 35
for, 34 de variable, 31
if, 33 variable, 31
matrice, 36 accès à une, 31
pointeur, 38 déclaration de, 31
tableau, 36 dénition de, 31
while, 33 initialisation de, 31
, 33 nom de, 31
système de chiers, 11 référence à une, 31
type de, 31
tête valeur de, 31
de liste, 71 argc, 28
table argv, 28
des i-nodes, 11 cdpath, 26
ASCII, 32 cwd, 9, 10
tableau, 36, 39 d'environnement, 10
auxiliaire d' indices, 89 d'environnement, 29
tail (commande ), 19 history, 22
tar (commande ), 12, 13, 15 home, 9
tcsh, 5 interne, 21
tcsh (commande ), 9 path, 911, 25
tests PID, 28
sur chiers, 25 prompt, 5, 911
texte shell, 9
chier, 16 status, 9, 10, 25, 26
time (commande ), 6 stdin, 46
times (commande ), 6 stdout, 46
tr (commande ), 19 user, 9
travail variable d'environnement
répertoire de, 26 HOME, 10, 13, 21, 26
Tri-shaker, 64 MANPATH, 29
triée PATH, 10
liste, 75 PWD, 10

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


INDEX xix

USER, 10
variables
d'environnement, 11, 27
internes, 11
VRAI (constante ), 31, 33

(
wc commande ), 13, 19
(
which commande ), 10
(
while commande ), 2426
(
while instruction ), 33, 34
(
who commande ), 6

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


xx INDEX

Introduction à l'algorithmique en C/Unix c M. Alissali, Université du Maine 1998


Bibliographie
[1] A. Aho, J. Hopcroft, and J. Ullman. Structures de données et algorithmique. Interédition, Paris,
1989.
[2] Leendert Ammeraal. Algorithmes et structures de données en langage C. InterEditions/Masson,
Paris, 1996.
[3] Daniel Appelman. La prgrammation, comment ça marche? Dunod, Paris, 1994. En images.
[4] J. Arsac. Préceptes pour programmer. Dunod, Paris, 1991.
[5] D. Bodouel and A. Khaled. La programmation en C et C++. Hermes, Paris, 2e edition, 1995.
[6] J.-M. Braquelqire. Méthodologie de la programmation en langage C. Principes et applications.
Masson, Paris, 2e edition, 1994. Environnement UNIX.
[7] Bernard Cassagne. Introduction au langage C, norme iso / ansi. Laboratoire clips Université
Joseph Fourier & cnrs, Grenoble, 1997.
[8] G. Clavel and J.Biondi. Structure de données, volume 2 of Introduction à la programmation. Masson,
Paris, 2e edition, 1984.
[9] Jacques Courtin and Irène Kowarski. Inititiation à l'algorithmique et aux structures de données,
volume 1. Dunod, 1994. Très bonne introduction, tableaux, tri, etc.
[10] Jacques Courtin and Irène Kowarski. Inititiation à l'algorithmique et aux structures de données,
volume 2. Dunod, 1995. Très bonne introduction, listes chaînées, piles, les, arbres, etc.
[11] Philippe Drix. Langage C norme ANSI, vers une approche orientée objet. Masson, Paris, 1989.
Concis, anatomie de chier source, production de l'exécutable, tableaux et pointeurs.
[12] Alan R. Feuer. Langage C, problèmes et exercices. Masson Paris et Prentice Hall Interantional
(UK) Ltd., 1991. Lecture du langage C.
[13] Horowitz, Sahni, and Anderson-Freed. L'essentiel des structures de données en C. Dunod, Paris,
1993.
[14] Albert Jassens. Unix sous tous les angles. Eyrolles, Paris, 1991.
[15] Jean-Pierre Laureau. Initiation à l'analyse et à la programmation. Dunod, 2 edition, 1985? Bien
commenté.
[16] Jean-Pierre Laureau and J. Ayel. Exercices commentés d'analyse et de programmation. Dunod,
Paris, 1985. Raisonnment détaillé.
[17] Thoams Plum. Le langage C, introduction à la programmation. Collection Intermicro, dirigée par
Jacky Akoka. Inter Éditions, Paris, Printice Hall Internation, Londres, 1986. Non ANSI.
[18] J-.M. Riet. La programmation sous UNIX. Ediscience, Paris, 1993.
[19] C.L. Tondo and S.E. Gimpel. Le langage C, solutions. Masson Paris et Prentice Hall International
Londres, 2 edition,??? ANSI.
[20] C.L. Tondo and S.E. Gimpel. Le langage C, solutions. Masson, Paris, 1986. Non ANSI.
[21] Gerhard Wilms. Grand Livre, le langage C. Micro Applications, 1997. Très détaillé.

xxi