Académique Documents
Professionnel Documents
Culture Documents
ii
xi 1
1 2 3 5 7 7 7 7 7 8
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9
9 9 9 10 10 10
Instructions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3 Types et variables
3.1 Types de base . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.1.1 3.1.2 3.1.3 3.2 Types entiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Types avec parties dcimales Tailles des types . . . . . . . . . . . . . . . . . . . . . . . . . .
11
11 12 12 12 13 13 14 14
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Constantes associes aux types de base . . . . . . . . . . . . . . . . . . . . . . . . . 3.2.1 3.2.2 3.2.3 Constantes de type entier . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . .
iv
Chanes de caractres
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15 15 15 16 18 18 19 20 21 22 23 23 23 23 24 25
Qualicatifs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Taille et normalisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Dnition de variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Types drivs des types de base . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.6.1 3.6.2 Tableaux et structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Pointeurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.7 3.8
Initialisation de variables
3.9
Dclaration et dnition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4 Elments de base
4.1 4.2 4.3 4.4 4.5 Bonjour . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Lire et crire
27
27 28 29 29 31 31 31 31 32
printf()
et
scanf() .
et
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
printf()
scanf()
5 Oprateurs et expressions
5.1 Oprateurs un-aires 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.1.8 5.2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Oprateur de rfrencement . . . . . . . . . . . . . . . . . . . . . . . . . . . Oprateur de drfrencement ou indirection Utilisation des & et * . . . . . . . . . . . . . . . . .
37
37 38 38 38 39 40 40 40 40 41 41
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5.2.2 5.2.3 5.2.4 5.2.5 5.2.6 5.2.7 5.2.8 5.3 5.4 5.5
. . . . . . . . . . . . . . . . . . . . . . . . .
41 42 43 44 44 45 46 47 47 48 48 48 48 48 49 49
. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Oprateurs de relation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Oprateur binaire d'aectation et de succession . . . . . . . . . . . . . . . . Oprateurs d'aectation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Oprateur ternaire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Prcdence des oprateurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Expressions
Instructions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Exercices sur les oprateurs et les expressions . . . . . . . . . . . . . . . . . . . . . 5.5.1 5.5.2 5.5.3 5.5.4 5.5.5 5.5.6 Exercice 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Exercice 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Exercice 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Exercice 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Exercice 5 : Operateur ternaire . . . . . . . . . . . . . . . . . . . . . . . . . Exercice 6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6 Instructions de contrle
6.1 Instructions conditionnelles 6.1.1 6.1.2 6.2 Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
57
57 57 58 60 60 61 62 63 63 63 63 65 65 66 66 66 66 66 66 66 66
Table de branchement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
while for
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
do while
6.3
continue break
goto
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
return
6.4
Exercices sur les instructions de contrle . . . . . . . . . . . . . . . . . . . . . . . . 6.4.1 6.4.2 6.4.3 6.4.4 Exercice 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Exercice 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Exercice 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Exercice 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.5
vi
7 Programmation structure
7.1 7.2 7.3 Historique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ides fondamentales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
83
83 83 84 84 84 84 85 86
7.4
Quelques exemples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.4.1 7.4.2 Exemple avec des tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Exemple avec une boucle . . . . . . . . . . . . . . . . . . . . . . . . . . . .
8 Fonctions
8.1 8.2 8.3 Dnition d'une fonction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Retour de fonction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
95
95 96 97 97 99 99 102 102 103 103 103 106 106 106 106
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
8.10 Exercices sur les fonctions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.10.1 Exercice 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.10.2 Exercice 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.10.3 Exercice 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9 Compilations spares
9.1 9.2 9.3 Programme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Fichier source . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Visibilit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9.3.1 9.3.2 9.4 9.5 9.6 9.7 9.8 Espaces de nommage et visibilit . . . . . . . . . . . . . . . . . . . . . . . . Extension de la visibilit . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
111
111 111 113 114 114 115 116 116 116 117 118 119
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
vii
. . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Exercices sur les fonctions et la visibilit des variables 9.9.1 9.9.2 9.9.3
Exercice 1 : simulation d'un ascenseur . . . . . . . . . . . . . . . . . . . . . Exercice 2 : racines d'une quation du deuxime degr . . . . . . . . . . . . Exercice 3 : utilisation des chiers d'inclusion . . . . . . . . . . . . . . . . .
10 Pointeurs et tableaux
10.1 Tableaux une dimension . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10.2 Arithmtique d'adresse et tableaux . . . . . . . . . . . . . . . . . . . . . . . . . . . 10.3 Tableaux multidimensionnels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
129
129 130 131 132 133 135 135 135
10.4 Pointeurs et tableaux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10.5 Tableau de pointeurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10.6 Pointeurs vers un tableau . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11 Structures
11.1 Dnition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.2 Utilisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.2.1 Oprations sur les champs . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.2.2 Oprations sur la variable dans son ensemble 11.3 Structures et listes chanes . . . . . . . . . . . . . . . . .
143
143 144 144 144 145 145 146 146 147
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
12 Unions
12.1 Dnition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.2 Accs aux champs
149
149 150 150 150 151
13 numrations
13.1 Dnition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13.2 Utilisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13.3 Limites des numrations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
153
153 154 155
157
viii
15 Prprocesseur
15.1 Commentaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15.2 Inclusion de chiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15.3 Variables de pr-compilation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15.3.1 Dnition de constantes de compilation 15.3.2 Dnition destine la slection . . . . . . . . . . . . . . . . . . . .
165
165 165 168 168 168 168 169 169 170 171 171 171 171 171
. . . . . . . . . . . . . . . . . . . . . . . .
#if
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . et
#ifdef
#ifndef .
. . . . . . . . . . . . . . . . . . . . . . .
16 Entres-sorties de la bibliothque
16.1 Entre-sorties standards . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16.1.1 changes caractre par caractre . . . . . . . . . . . . . . . . . . . . . . . . 16.1.2 changes ligne par ligne . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16.1.3 changes avec formats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16.2 Ouverture d'un chier 16.3 Fermeture d'un chier . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
179
179 180 181 182 183 184 185 185 186 188 190 190 191 193 193
16.4.2 Accs ligne par ligne . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16.4.3 Accs enregistrement par enregistrement . . . . . . . . . . . . . . . . . . . . 16.5 Entre-sorties formates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
16.5.1 Formats : cas de la lecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16.5.2 Formats : cas de l'criture . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16.5.3 Conversion sur les entre-sorties standards . . . . . . . . . . . . . . . . . . . 16.5.4 Conversion en mmoire . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
ix
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
203
203 203 204 204 204
system() exit()
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
207
207 208 208 209 210 210 211 211 211 211
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Liste des programmes exemples Liste des gures Liste des tableaux Bibliographie Index
Avant-propos
Notice de copyright
NOTICE de COPYRIGHT c Ce support de cours correspond au cours de langage C de Christian Bac (ci-aprs l'auteur, je ou moi) de l'Institut National de Tlcommunications, 9 rue Charles Fourier 91011, vry, France.
http ://picolibre.int-evry.fr/projects/coursc/.
Ce document est disponible aux formats latex, PostScript ou HTML, sur le web l'URL :
Il est fourni tel quel, l'auteur ayant fait de son mieux pour supprimer les erreurs, sans garantie sur son utilisabilit, ni sur l'exactitude des informations qu'il contient. Vous avez le droit de copier, distribuer et/ou modier ce document selon les termes de la licence de documentation libre, version 1.1 ou toute version postrieure publie par la Free Software Foundation ; avec une section invariante le chapitre
texte spcique en premire et en quatrime de couverture. Une copie de la licence est inclue dans le chapitre 17.3.2 intitul "GNU Free Documentation License". Toute remarque ou erreur peut tre notie l'auteur l'adresse lectronique suivante :
Christian.Bac AT int-evry.fr
Fin de la NOTICE de COPYRIGHT c -
Conventions d'criture
Voici les conventions d'criture suivies dans ce support : le en anglais comme
style italique n'est quasiment jamais utilis car je ne l'aime pas, je le rserve pour les phrases The C programming Language et pour les locutions latines comme versus ; les caractres de type imprimante boule (teletype) sont utiliss pour les noms de chiers et les parties de programme, comme /usr/include/stdio.h ;
le
les caractres sont plus larges dans l'nonc de rgles ou de parties de syntaxe telles que la syntaxe de la conversion explicite : (type) expression ; les mots qui ne sont pas franais mais sont souvent utiliss dans le jargon des informaticiens comme quote sont considrs comme de type neutre et se voient appliquer le genre masculin. Ainsi je peux appeler un index-noeud du systme de chiers UNIX : un inode ; dans les dessins reprsentant l'espace mmoire occup par les variables ou les tableaux, les noms entours par des pointills sont des adresses et non des variables.
style gras est utilis lorsqu'un mot me semble important, par exemple instructions ;
xii
Vocabulaire courant
Voici quelques mots que j'utilise de manire courante :
Bit
(Binary digiT) ou lment binaire, la plus petite partie manipulable par un ordinateur. Comme son nom l'indique un lment binaire peut prendre deux valeurs : 0 ou 1.
Octet
ou
byte,
groupe est le plus souvent (comme son nom l'indique) constitu de huit bits. En langage C, l'octet sert dans les calculs d'occupation d'espace mmoire et en particulier les variables plus compliques comme le mot machine ont une taille donne en nombre d'octets.
Pile
ou pile d'excution, c'est une partie de l'espace mmoire d'une application qui permet au programme de tenir jour des sries de variables actives. Cet espace est gr comme une pile d'assiettes, c'est--dire que l'on peut ajouter de l'espace (faire grandir la pile) ou diminuer cet espace seulement par le haut. Ainsi, les derniers lments qui ont t ajouts sur une pile sont les plus facilement accessible, une pile reprsente le modle LIFO (Last
Out )
In First
les derniers lments qui y sont ajouts sont les premiers pouvoir tre retirs. Les
oprations d'agrandissement ou de rduction de la pile sont faites de manire automatique lors des appels de fonctions et respectivement des retours de fonctions. La pile est gre partir d'un espace mmoire de taille xe qui est attribu de manire automatique par le systme d'exploitation. Le processeur tient jour sa relation avec la pile travers un registre interne qui dcrit le sommet de pile et un autre registre qui maintient un lien sur le contexte (arguments de l'appel et variables locales).
Un peu d'histoire
Ce cours de langage C a la gnalogie suivante :
Gnse
1. Il a t cr en 1985 lorsque j'tais au centre de calcul du CNET Paris A, pour assurer la formation en interne.
2. La premire version tait tape avec les accents franais grce une version d'Emacs sur
Multics
accents. 3. Les exercices associs ont t raliss sur une machine de type SM90. 4. Les personnes m'ayant aid dans la ralisation de cette premire version sont : M. Auguste et M. Sabatier du CNET.
Tro
1. Lorsque le
ticipation du CNET travers la personne de M. Gien, dans l'organisation de la confrence Europenne sur UNIX Paris en 1986, j'ai dcid de faire migrer ce cours sous une version
2. J'ai alors choisi d'utiliser les macros qui me semblaient devoir tre la future rfrence car elles faisaient partie de la distribution d'UNIX que j'ai t le seul). 3. Les premires gures sont apparues dans ce support grce la disponibilit de l'utilitaire
system V,
les macros
-mm
(je crois
pic.
4. Les personnes m'ayant aid dans la ralisation de cette version sont : M. Fondain et M. Horn du CNET.
venir travailler l'INT en 1989. Elle a alors servi de support de cours pour la mise en place d'un ensemble de cours dus l'arrive du systme UNIX dans les services oprationnels, par le service national de la formation de France Tlcom.
Macintosh
J'ai arrt de modier cette version en 1991, pour deux raisons : c Christian Bac 1985-2003
CHAPITRE 0.
AVANT-PROPOS
xiii
Microsoft Word
pour
Macintosh.
Ces ad-
dendas avaient pour but d'expliquer les modications apportes par la normalisation
2. deuximement, j'ai constitu un jeu de transparents partir de ce cours en supprimant des phrases et en modiant les polices de caractres de manire le rendre lisible une fois projet. Ce jeu de transparents est devenu mon nouveau support de cours et je l'ai fait voluer de manire indpendante.
LaTeX
J'ai dcid en 1997 de reconstituer ce support en utilisant 1. pour moi, ce fut un trs bon apprentissage de
LaTeX,
LaTeX2HTML,
support sur le World Wide Web ; 3. j'ai mesur la limite des transparents surtout lorsqu'ils sont utiliss par les lves comme support de cours. Je tiens souligner la participation active de Mmes. Monget et Carpentier, Ms. Conan, Volt et Laleve dans la relecture et la correction de ce support. Je suis aussi redevable, ce dernier de moult conseils relatifs l'utilisation de
GnuFDL
LaTeX2e.
En 2003, je suis convaincu des vertus du partage au travers d'Internet, non seulement
des codes mais aussi du savoir, j'ai plac ce cours sous licence GNU Free Documentation Licence pour lui permettre de continuer vivre et pour faciliter son utilisation par mes collgues enseignants francophones. Pour l'occasion, j'en ai prott pour associer ce support quelques exercices et leurs corrigs qui taient sur un support spar. Je tiens enn remercier les internautes qui m'envoient des correctifs ou des remarques qui permettent ce cours de s'amliorer.
xiv
Chapitre 1
Historique et prsentation
Ce chapitre essaye de placer le langage C [BK78] dans son contexte historique et technique, de manire approcher l'tat d'esprit du langage qui nous permet de deviner les rgles sous-jacentes au langage sans pour cela avoir les mmoriser.
1.1 Historique
Le langage C [DR78] est li la conception du systme ayant inuenc son dveloppement sont : le langage le langage
UNIX1
Ces deux langages partagent avec le langage C : les structures de contrle ; l'usage des pointeurs ; la rcursivit. Ces deux langages prdcesseurs du C avaient la particularit d'tre sans type. Ils ne travaillaient que sur des donnes dcrites par un mot machine ce qui leur donnait un degr de portabilit nul. Le langage C comble ces lacunes en introduisant des types de donnes tels que l'entier, ou le caractre. Les dates marquantes de l'histoire du langage 1970 diusion de la famille PDP 11. 1971 dbut du travail sur le langage C, car le PDP 11 peut manipuler un octet alors que son mot mmoire est de 2 octets, il est ncessaire pour utiliser les fonctionnalits du PDP11 introduire un type de donne char et un type int. Ces notions de type n'tant pas prises en compte par le langage B, elles le seront dans son successeur le C. 1972 la premire version de C est crite en assembleur par Brian W. Kernighan et Dennis M. Ritchie. 1973 Alan Snyder crit un compilateur C portable (thse MIT). 1975 Steve C. Johnson crit et prsente le PCC (Portable C Compiler). C'tait l'poque le compilateur le plus rpandu. Le PCC a longtemps assur sa propre norme puisqu'il tait plus simple de porter le PCC que de rcrire un compilateur C (25 % du code du PCC modier). 1987 dbut de la normalisation du langage par l'IEEE avec constitution d'un comit appel : X3 J-11.
l'poque UNIX tait une marque dpose des laboratoires Bell. Aujourd'hui, c'est devenu un nom quasiment
1.2.
PRSENTATION DU LANGAGE
1989 sortie du premier document normalis appel norme ANSI X3-159. 1990 ralisation du document nal normalis auprs de l'ISO : ISO/IEC 9899 [ISO89] ; 1999 premire rvision de la norme ISO/IEC 9899 [ISO99]. Jusqu'en 1987, il n'y avait pas de norme. Le livre "The C Programming Language" [BK78] de B. W. Kernighan et D. M. Ritchie dnit le langage. Ce livre contient une description prcise du langage appele [BK88] ainsi que la norme ISO [ISO89] sont la base de ce cours. Le livre de Philippe Dax [Dax92] est lui aussi une bonne introduction pour l'apprentissage de ce langage.
"C Reference Manual". Ce livre qui a lui aussi t remis au gout du jour en 1988
Le compilateur de langage C se limite aux fonctionnalits qui peuvent tre traduites ecacement en instructions machine.
La rgle de fonctionnement du compilateur C, dicte ci-dessus, permet de dtecter ce qui est fait directement par le compilateur lui-mme et ce qui ne peut l'tre. Essayons d'illustrer cette rgle par quelques exemples : Le compilateur C est capable de gnrer des instructions machine qui permettent de manipuler des lments binaires(bits) ou des groupes d'lments binaires. Il peut donc raliser des masques pour slectionner des groupes de bits, ou encore faire des dcalages de bits l'intrieur de mots machine. Il permet les manipulations algbriques (addition, multiplication, etc.) de groupes d'octets qui reprsentent des valeurs entires ou des valeurs dcimales. c Christian Bac 1985-2003
CHAPITRE 1.
HISTORIQUE ET PRSENTATION
Il permet de manipuler des caractres en considrant qu'un caractre est reprsent par un octet partir du code ASCII . Il ne permet pas de manipuler directement des tableaux. En particulier, il ne permet par de manipuler directement les groupes de caractres utiliss pour stocker les chanes de caractres. Pour cela, il faut faire appel des fonctions de bibliothques dont le nom commence par
De manire contradictoire la rgle prcdente, le compilateur accepte l'aectation d'une collection de donnes groupes (structure) par une collection de donnes de type identique, depuis la normalisation du langage. Ceci s'explique par le fait qu'une structure est considre dans le langage comme une donne simple, elle doit donc pouvoir tre aecte une autre donne de mme type. Pour raliser des oprations plus compliques, le programmeur doit crire ses propres fonctions ou faire appel aux fonctions prdnies de la bibliothque du langage C (voir chapitres 16 et 17). Ces fonctions sont, elles aussi, standardises. La rdaction de la norme a supprim un petit problme qui venait de la rfrence sous-jacente aux oprations possibles sur le processeur du PDP 11 de Digital Equipment sur lequel ont t conues les premires versions du compilateur C. Cette machine tait cependant susamment gnrale pour que cela ne transparaisse pas.
la partie stockage des donnes sur disque une fois ces donnes tries (fichier3.c). Chaque chier (voir g. 1.2) contient les lments suivants dans un ordre quelconque : des rfrences des variables ou des fonctions externes (sous forme de dclarations). Ces rfrences dcrivent les types des variables ou le prototype des fonctions utilises dans ce module mais dnies dans d'autres modules ; des dnitions de variables globales et de fonctions, qui peuvent tre rfrences
la partie de calcul qui dans ce cas est un tri (par note ou par nom) (fichier2.c) ;
3 dans les
2 ASCII 3 Nous
: Americans Standard Code for Information Interchange. ISO 646 :1983, Information processing - ISO
7-bit coded character set for information interchange. verrons plus en dtail l'ensemble des possibilits associes aux dclarations et aux dnitions dans les chapitres 3 et 9.
1.3.
IDES FONDAMENTALES
Fig.
Fig.
CHAPITRE 1.
HISTORIQUE ET PRSENTATION
Fig.
autres chiers ;
des lignes de directives de compilation (pour le pr-processeur). Une fonction (Fig. 1.3) est construite partir : d'une interface constitue du type et du nom de la fonction suivis par les types et les noms de ses paramtres ; d'un bloc, appel aussi corps de la fonction. La fonction
main()
conu partir de l'ensemble des chiers source, commence par elle. Un bloc est constitu : d'une accolade ouvrante ; des dnitions des variables locales au bloc ; des instructions ; d'une accolade fermante. Une instruction peut tre : un bloc ;
ou une expression
;) ;
ou une instruction de contrle de ot (test, boucle, rupture de squence). Nous parlerons en dtail des possibilits du pr-processeur dans le chapitre 15.
cc6
cc options nom_du_fichier.c
Ces compilateurs sont en fait des en-chaneurs de passes ; nous allons voir l'usage, le fonctionnement, et les options de uvre cinq utilitaires : le pr-processeur, que nous appellerons le compilateur C, que nous appellerons
cc.
cc
met en
cpp ; c0+c1
4 On
voit apparatre une dnition rcursive l'intrieur du langage : savoir un bloc contient des instructions 5.
5 Les expressions sont explicites dans le chapitre 6 cc ou tout autre compilateur comme gcc.
Fig.
cc
CHAPITRE 1.
HISTORIQUE ET PRSENTATION
c2 ;
as ;
ld.
La gure1.4 donne un organigramme des direntes actions entreprises par un en-chaneur de passes. Les chiers temporaires de 1 3 dcrits dans cette gure sont utiliss par les outils pour stocker les donnes intermdiaires ncessaires la traduction des dirents codes.
1.4.1 Pr-processeur
Le pr-processeur ou pr-compilateur est un utilitaire qui traite le chier source avant le compilateur. C'est un manipulateur de chanes de caractres. Il retire les parties de commentaires, qui sont comprises entre
/*
et
*/.
en
premire colonne pour crer le texte que le compilateur analysera. Ses possibilits sont de trois ordres (voir chap. 15) : inclusion de chiers ; dnition d'alias et de macro-expressions ; slection de parties de texte.
1.4.2 Compilateur
Le compilateur lit ce que gnre le pr-processeur et cre les lignes d'assembleur correspondantes. Le compilateur lit le texte source une seule fois du dbut du chier la n. Cette lecture conditionne les contrles qu'il peut faire, et explique pourquoi toute variable ou fonction doit tre dclare avant d'tre utilise.
1.4.4 Assembleur
L'assembleur prend le code gnr par le compilateur, ventuellement modi par l'optimiseur, et gnre un chier en format relogeable. Ce chier possde des rfrences insatisfaites qui seront rsolues par l'diteur de liens. Sur les machines utilisant un systme de type UNIX, ce chier est sux par
.o 7 .
crt0.o,
a.out.
7 De
mauvaises langues prtendent que sur d'autres types de systme un mauvais esprit aurait os les suxer
par .OBJ
cc,
relativement aux options qui lui sont (-). Voici les options
-c -E -S
provoque la gnration d'un module objet non excutable, il s'arrte avant l'dition de liens.
cc -c toto.c toto.o
par .i.
cpp,
-O optimise le code gnr (utilisation de c2). -o nom donne le nom au chier excutable au lieu de a.out. -v
cc -o toto toto.c toto option bavarde, cc annonce ce qu'il
fait. Deux options sont utiles sur le compilateur GNU correspondant la norme ANSI :
cc -S toto.c toto.s
gcc
-ansi
avec cette option le compilateur se comporte comme un compilateur de langage C ANSI sans extensions de langage correspondant au C GNU ;
-pedantic
ansi ;
-Wall
cette option augmente le nombre de messages d'alerte gnrs par le compilateur lorsqu'il
rencontre des constructions dangereuses. L'utilisation de ces options est recommande lors de l'apprentissage du langage C en utilisant le compilateur
gcc.
8 Selon
Chapitre 2
#.
2.1.1 Identiant
Les identiants sont utiliss pour donner des noms aux direntes entits utiliss dans le langage. Un identiant est construit selon le modle : partir de l'alphabet : a-z,
A-Z, 0-9, _ ;
il peut avoir jusqu' trente et un caractres signicatifs lation. La norme mentionne que les noms
de compilation et que les diteurs de liens peuvent ne pas tenir compte des majuscules et il commence par une lettre ou le soulign _. minuscules. Cette contrainte n'est pas suivie par les compilateurs modernes.
10
Ces espaces sont isols ce qui permet d'avoir une tiquette qui porte le mme nom qu'une variable mais jamais une fonction qui porte le mme nom qu'une variable.
char const double float int long short signed unsigned void volatile auto extern register static enum struct typedef union do for while
case default else if switch break continue goto return asm entry fortran sizeof
2.3 Constantes
Les constantes servent dans l'expression des tailles, l'initialisation des variables et dans les expressions. Les constantes de type chane de caractres ont un statut particulier : elles permettent de constituer des tableaux de caractres anonymes. Les caractres de ces tableaux peuvent tre constants. Nous approfondirons l'expression des constantes dans la section 3.2 qui traite des types de variables. Voici cependant quelques exemples de constantes : constante entire : constante ottante :
2.4 Instructions
Une
instruction est :
Chapitre 3
Types et variables
variable a les rles suivants :
Ce chapitre traite des dnitions de variables. Dans tous les langages, une
dnition de
2. dnir les oprations possibles sur cette variable ; 3. dnir le domaine de visibilit de cette variable ; 4. permettre l'environnement d'excution du programme d'associer le nom de la variable une adresse mmoire ; 5. initialiser la variable avec une valeur compatible avec le domaine de valeur. En langage C, une variable se caractrise partir de son type et de sa classe mmoire. Les points prcdents numros 1 et 2 sont associs au type de la variable ; les points 3 et 4 sont associs la classe mmoire de la variable. L'initialisation est traite dans la section3.7.
void int
c'est le type vide. Il a t introduit par la norme ANSI. Il est surtout utilis pour prciser les fonctions sans argument ou sans retour. Il joue un rle particulier dans l'utilisation des pointeurs (voir chapitre 10).
c'est le type entier. Ce type se dcline avec des qualicatifs pour prciser sa taille (long ou
short), et le fait qu'il soit uniquement positif (unsigned) ou positif et ngatif (signed) 1 . Le qualicatif signed est appliqu par dfaut, ainsi il n'y a pas de dirence entre une variable de type int et une variable de type signed int.
ce type est trs proche de l'octet. Il reprsente un entier sur huit bits. Sa valeur peut voluer entre -128 et +127. Il est le support des caractres au sens commun du terme. Ces caractres sont reprsents par la table ASCII. Comme le type
char
int
le type
char
manire tre sign ou non. La norme ANSI introduit un type permettant de supporter des alphabets comprenant plus de 255 signes, ce type est appel chier<stddef.h>.
wchar_t.
float ce type sert pour les calculs avec des parties dcimales. double c'est un type qui permet de reprsenter des valeurs ayant une partie dcimale avec une plus grande prcision que le type float. Comme nous le verrons dans l'expression des constantes
1 Dans
le cas le plus courant une variable du type entier peut contenir une valeur positive ou ngative.
12
(sec. 3.2.2) et dans les calculs(sec. 3.8), ce type est le plus courant pour reprsenter des valeurs avec parties dcimales.
long double
ce type est rcent, il permet de reprsenter des nombres avec parties dcimales qui
short
et
long
ou
short
int, donnant la possibilit short int ou long int. Ces dnitions peuvent aussi s'crire de long.
peuvent tre utiliss seuls ou avec le mot
et
long int,
et permet de les mlanger lors des calculs (5.3). A priori, les types entiers sont signs, c'est--dire qu'ils peuvent contenir des valeurs positives ou ngatives. Par exemple, la valeur d'une variable du type
ce type tre considres comme uniquement positives. Par exemple, la valeur d'une variable du
unsigned char
et
255.
Le qualicatif
signed
permet d'insister sur le fait que la variable peut prendre des valeurs
unsigned
float
ce type sert pour les calculs avec des parties dcimales. Il est souvent reprsent selon la
double
ce type de plus grande prcision permet de reprsenter des valeurs avec parties dcimales.
long double
ce type est rcent et permet de reprsenter des nombres avec parties dcimales sur
sizeof (short) sizeof (int) sizeof (long ) sizeof (f loat) sizeof (double) sizeof (longdouble) sizeof est un oprateur qui donne la taille en nombre d'octets
parenthses. La taille de l'entier est le plus souvent la taille des registres internes de la machine, c'est par exemple seize bits sur une machine de type ordinateur personnel machines du type station de travail. La taille des variables ayant une partie dcimale est le plus souvent cadre sur la norme ISO/IEEE 754. Les machines supportant un type assez rares.
long double
dirent du type
double
sont
2 Pour
des problmes de compatibilit avec les anciennes versions, les compilateurs pour PC gnrent le plus
CHAPITRE 3.
TYPES ET VARIABLES
13
Type Anne
char short int long oat double long double
Alpha 1994
8bits 16 bits 32 bits 64 bits 32 bits 64 bits 128 bits
Tab.
Le tableau 3.1 donne quelques exemples de tailles pour des machines dont les registres ont les tailles suivantes en nombre de bits : 16 (DEC PDP11, Intel 486), 32 (SUN Sparc, Intel Pentium) et 64 (DEC Alpha). Vous remarquerez que malgr son architecture interne de 64 bits, le compilateur pour alpha utilise des entiers sur 32 bits. Il est aussi le seul processeur capable de direncier les
double
des
long doubles.
0X
(hexadcimal).
int
plus grand entier reprsentable. Si la valeur de la constante est suprieure au plus grand entier reprsentable, la constante devient du type
long.
long int.
Les constantes peuvent tre suxes par un l ou L pour prciser que leur type associ est
Les constantes peuvent tre prcdes par un signe - ou +. Elles peuvent tre suxes par un u ou U pour prciser qu'elles expriment une valeur sans signe (qualies
unsigned).
Voici quelques exemples de constantes de type entier : constante sans prcision de type :
14
3.2.
2.
120u, 0364u, 0x1fau 120UL, 0364UL, 0x1faUL, 120uL, 0364uL, 0x1fauL 120Ul, 0364Ul, 0x1faUl, 120ul, 0364ul, 0x1faul
partir d'une notation utilisant le point dcimal ou partir d'une notation exponentielle. Ces constantes peuvent tre suxes par un f ou F pour prciser qu'elles reprsentent une valeur de type
float.
long double.
Elles peuvent de mme tre suxes par un l ou un L pour exprimer des valeurs de type
121.34
12134e-2 la mme constante exprime en notation exponentielle +12134E-2 la notation exponentielle accepte le E majuscule, et le + un-aire. 121.34f constante de valeur identique mais de type float car suxe par f. 121.34l constante de valeur identique mais de type long double car suxe par l.
double.
constante exprime avec la notation utilisant le point dcimal, son type implicite est
quote ).
'a'.
2. un caractre peut aussi tre reprsent par sa valeur exprime dans la table ASCII en utilisant une notation en base huit. Cette valeur est prcde l'intrieur des apostrophes par une barre de fraction inverse.
'\0' : octet du nul, il sert dlimiter les ns de chanes de caractres. '\012' : saut de ligne (Line Feed, LF) ; '\015' : retour chariot (Carriage Return, CR) ; '\011' : tabulation horizontale (Horizontal Tabulation, HT) ;
3. de mme, un caractre peut tre reprsent par sa notation en base seize.
'\x0' : caractre nul ; '\xA' : saut de ligne (LF) ; '\xC ' : retour chariot (CR) ; '\x9' : tabulation horizontale '\a' : alert (sonnerie, BEL) ; '\b' : backspace (BS) ; '\f ' : saut de page (FF) ; '\n' : saut de ligne (LF) ;
(HT) ;
CHAPITRE 3.
TYPES ET VARIABLES
15
Fig.
'\r' '\t' '\v '
Pour spcier qu'une constante caractre est du type (wchar_t), elle doit tre prcde d'un L. Par exemple,
L'a'
quote ).
Le compilateur gnre une suite d'octets termine par un caractre nul (tous les bits 0) partir des caractres contenus dans la chane. Cette suite d'octets peut tre place par le systme dans une zone de mmoire en lecture seulement. La zone correspondante est en fait un tableau de du tableau. Par exemple, la chane de caractres le schma de la gure 3.1.
char. La chane est rfrence par l'adresse "message" est gnre par le compilateur selon
3.3 Qualicatifs
Nous avons dj parl des qualicatifs
unsigned
et
signed
type entier. Il existe d'autres qualicatifs qui ont t spcis par la norme. Il s'agit de
volatile, static
et
register.
const,
considre comme constante et ne doit pas tre utilise dans la partie gauche d'une aectation. Ce type de dnition autorise le compilateur placer la variable dans une zone mmoire accessible en lecture seulement l'excution. Le qualicatif
une zone de mmoire qui peut tre modie par d'autres parties du systme que le programme lui-mme. Ceci supprime les optimisations faites par le compilateur lors de l'accs en lecture de la variable. Ce type de variable sert dcrire des zones de mmoire partages entre plusieurs programmes ou encore des espaces mmoires correspondant des zones d'entre-sorties de la machine. Les deux qualicatifs peuvent tre utiliss sur la mme variable, spciant que la variable n'est pas modie par la partie correspondante du programme mais par l'extrieur. Les qualicatifs
static
et
register
limits.h float.h
16
3.5.
DFINITION DE VARIABLES
Ces chiers contiennent des dnitions qui s'adressent au pr-compilateur et donnent les tailles et valeurs maximales des types de base et des types non signs. Le programme 3.1 est un exemple de chier de chier
<float.h>.
<limits.h>
/* Min and max values a signed char can hold. #define SCHAR_MIN (-128) #define SCHAR_MAX 127 /* Max value an unsigned char can hold. #define UCHAR_MAX 255U /* Min and max values a char can hold. #define CHAR_MIN SCHAR_MIN #define CHAR_MAX SCHAR_MAX
(Min is 0). */ */
/* Min and max values a signed short int can hold. #define SHRT_MIN (-32768) #define SHRT_MAX 32767
*/
/* Max value an unsigned short int can hold. (Min is 0). */ #define USHRT_MAX 65535U /* Min and max values a signed int can hold. #define INT_MIN (-INT_MAX-1) #define INT_MAX 2147483647 /* Max value an unsigned int can hold. #define UINT_MAX 4294967295U */
(Min is 0). */ */
/* Min and max values a signed long int can hold. #define LONG_MIN (-LONG_MAX-1) #define LONG_MAX 2147483647
/* Max value an unsigned long int can hold. (Min is 0). */ #define ULONG_MAX 4294967295U
La normalisation a aussi introduit un ensemble de types prdnis comme type de la valeur retourne par l'oprateur le chier
<stddef.h>.
sizeof.
size_t
qui est le
<stddef.h>.
ce que nous avons dit dans l'introduction de ce chapitre, voici comment les dirents besoins
dnition de variables sont couverts par le langage C : dnition du domaine de valeur de cette variable et les oprations lgales sur cette variable ;
=
grce au type. c Christian Bac 1985-2003
CHAPITRE 3.
TYPES ET VARIABLES
17
Double definitions */ DBL_MANT_DIG DBL_EPSILON DBL_DIG DBL_MIN_EXP DBL_MIN DBL_MIN_10_EXP DBL_MAX_EXP DBL_MAX DBL_MAX_10_EXP 53 2.2204460492503131e-16 15 -1021 2.2250738585072014e-308 -307 1024 1.79769313486231570e+308 308
grce au type et la classe mmoire. l'aide d'une constante dont le type correspond celui de la va-
initialisation de la variable
riable ;
la variable.
Une dnition de variable est l'association d'un identiant un type et la spcication d'une classe mmoire. La
classe mmoire sert expliciter la visibilit d'une variable et son implantation classes mmoire sont :
en machine. Nous approfondirons les possibilits associes aux classes mmoire dans le chapitre 9 sur la visibilit. Les
global
cette classe est celle des variables dnies en dehors d'une fonction. Ces variables sont
accessibles toutes les fonctions. La dure de vie des variables de type global est la mme que celle du programme en cours d'excution.
local
ou
auto : cette classe comprend l'ensemble des variables dnies dans un bloc. C'est le cas
de toute variable dnie l'intrieur d'une fonction. L'espace mmoire rserv pour ce type de variable est allou dans la pile d'excution. C'est pourquoi elles sont appeles aussi
auto
c.a.d automatique car l'espace mmoire associ est cr lors de l'entre dans la fonction et c Christian Bac 1985-2003
18
Dclaration/dnition
Classe mmoire dnition d'une variable globale paramtres passs dans la pile, donc automatiques dnition d'une variable locale main donc automatique variable locale main mais implante avec les globales dclaration d'une variable qui est dnie dans un autre chier (rien voir la variable
int a ; int main (int argc, char *argv[]) { int b ; static char c[50] ; } extern int b ; int coucou(const int c) { volatile char c ; register int a ; if (b == 1) }
paramtre constant, variable locale la fonction coucou s'engage ne pas modier c variable locale volatile variable locale coucou, mettre en registre si possible rfrence la variable b externe
Tab.
static
il est dtruit lors de la sortie de la fonction. La dure de vie des variables de type local est celle de la fonction dans laquelle elles sont dnies. ce qualicatif modie la visibilit de la variable, ou son implantation : l'espace de mmoire globale pour cette variable. Une variable locale de type statique a un nom local mais a une dure de vie gale celle du programme en cours d'excution. dans le cas d'une variable globale, ce prdicat restreint la visibilit du nom de la variable l'unit de compilation. Une variable globale de type statique ne peut pas tre utilise par un autre chier source participant au mme programme par une rfrence avec le mot rserv
dans le cas d'une variable locale il modie son implantation en attribuant une partie de
extern
extern
ce qualicatif permet de spcier que la ligne correspondante n'est pas une tentative de
qui sont dnies dans un autre chier source et qui sont utilises dans ce chier source.
register
ce qualicatif permet d'informer le compilateur que les variables locales dnies dans
le reste de la ligne sont utilises souvent. Le prdicat demande de les mettre si possible dans des registres disponibles du processeur de manire optimiser le temps d'excution. Le nombre de registres disponibles pour de telles demandes est variable selon les machines. Il est de toute faon limit (4 pour les donnes, 4 pour les pointeurs sur un 680X0). Seules les variables locales peuvent tre qualies
register.
CHAPITRE 3.
TYPES ET VARIABLES
19
tableau est donne entre les crochets lors de la dnition. Pour simplier le travail du compilateur, le rang des lments du tableau ne peut voluer qu'entre 0 et la taille du tableau -1. Les structures sont des ensembles de donnes non homognes. Les donnes peuvent avoir des types dirents. Les structures sont dclares ou dnies selon le modle : struct un nom de structure facultatif
{ }
la liste des donnes contenues dans la structure la liste des variables construites selon ce modle. Prenons pour exemple les dnitions suivantes :
int tab[10]; struct st1 { int a1; float b1; long c1; } objst1;
Dans cet exemple : 1.
tab st1
jusqu' 2.
tab[9] ;
tab[0]
objst1.c1.
objst1
objst1
3.6.2 Pointeurs
Le
pointeur est une variable destine contenir une adresse mmoire. Le compilateur connais*) qui
sant la taille de l'espace adressable de la machine, il sait la taille ncessaire pour contenir un pointeur. Un pointeur est reconnu syntaxiquement par l'toile (symbole de la multiplication prcde son nom dans sa dnition. Tout pointeur est associ un type d'objet. Ce type est celui des objets qui sont manipulables
grce au pointeur. Ce type est utilis en particulier lors des calculs d'adresse qui permettent de manipuler des tableaux partir de pointeurs (voir Chap. 10). Prenons les dnitions suivantes :
ptint
des valeurs qui sont des adresses de variables de type caractre (char).
ptchar
est une variable du type pointeur sur un caractre. Elle peut donc contenir
Le compilateur C vrie le type des adresses mises dans un pointeur. Le type du pointeur conditionne les oprations arithmtiques (voir chap. 9 pointeurs et tableaux) sur ce pointeur. Les oprations les plus simples sur un pointeur sont les suivantes :
3 Une
valeur la fois mais comme le pointeur est une variable cette valeur peut changer au cours de l'excution
du programme.
20
aectation d'une adresse au pointeur ; utilisation du pointeur pour accder l'objet dont il contient l'adresse. Si l'on dnit les variables de la manire suivante :
Un pointeur peut tre aect avec l'adresse d'une variable ayant un type qui correspond celui associ au pointeur. Comme nous le verrons dans la partie sur les oprateurs, le -commercial donne l'adresse du nom de variable qui le suit et les noms de tableau correspondent l'adresse du premier lment du tableau. Les pointeurs prcdents peuvent donc tre aects de la manire suivante :
car.
in ;
Il est possible de raliser ces oprations en utilisant le pointeur pour accder aux lments du tableau. Ainsi les lignes :
ptint=tab; *ptint=4;
aectent le pointeur lment du tableau nous le reverrons dans le chapitre sur pointeurs et tableaux 10)
ptint avec l'adresse du premier lment du tableau tabint quivalent (comme &tabint[0] ; puis le premier (tabint[0]) est aect avec la valeur 4.
CHAPITRE 3.
TYPES ET VARIABLES
21
int i = 10; int j = 12, k = 3, l; int *p1 = &i; char d = '\n'; float tf[10] = { 3.1, 4.5, 6.4, 9.3 }; char t1[10] = "Coucou"; struct tt1{ int i; float j; char l[20]; } obst = { 12, 3.14, "qwertyuiop" }; char t2[] = "bonjour"; char t3[10] = { 'a', 'b','c','d','e'}; const char *p3 = "Bonjour les";
Entier i initialis 10 entiers j initialis 12 ; k initialis 3 et l non initialis. Pointeur d'entier initialis l'adresse de i Caractre initialis la valeur du retour chariot. Tableau de dix ottants dont les quatre premiers sont initialiss 3.1 4.5 6.4 et 9.3, les autres sont initialiss 0.0. Tableau de 10 caractres initialis avec les caractres
'\0'.
avec le premier champ (obst.i) initialis 12, le deuxime champ (obst.j) initialis 3.14, de la chane "qwertyuiop" Tableau de caractres initialis avec la chane "bonjour". La taille du tableau est calcule selon le nombre de caractres + 1 (pour le nul). Tableau de 10 caractres dont les 5 premiers sont initialiss. Pointeur sur un caractre initialis l'adresse de la chane de caractres constante. La chane peut tre mise dans une zone de mmoire accessible en lecture seulement. et le troisime champ (obst.l) initialis partir
struct tt1,
Tab.
2. dans le cas de tableaux ou structures, il faut faire suivre la dnition du signe gal suivi d'une accolade ouvrante et de la srie de valeurs termine par une accolade fermante. Les valeurs sont spares par des virgules. Elles doivent correspondre aux lments du tableau ou de la structure. La norme prconise que lorsque le nombre de valeurs d'initialisation est infrieur au nombre d'lments initialiser, les derniers lments soient initialiss avec la valeur nulle correspondant leur type. 3. les tableaux de caractres peuvent tre initialiss partir d'une chane de caractres. Les caractres de la chine sont considrs comme constants. Le tableau 3.3 donne des exemples d'initialisation.
22
3.8.
CONVERSION DE TYPE
f,
le rsultat est transform en long et rang dans li. i est transform en long puis additionn li, le rsultat est transform en double et rang dans d. f est transform en double, additionn d, le rsultat est transform en int et rang dans i.
Tab.
Convertir les lments de la partie droite d'une expression d'aectation dans le type de la variable ou de la constante le plus riche. Faire les oprations de calcul dans ce type. Puis convertir le rsultat dans le type de la variable aecte.
La notion de richesse d'un type est prcise dans la norme [ISO89]. Le type dans lequel le calcul d'une expression deux oprandes doit se faire est donn par les rgles suivantes : 1. si l'un des deux oprandes est du type
long double alors le calcul doit tre fait dans le type double
alors le calcul doit tre fait dans le
float ;
4. sinon, appliquer la rgle de promotion en entier, puis : (a) si l'un des deux oprandes est du type dans ce type ; (b) si l'un des deux oprandes est du type type
unsigned long int alors le calcul doit tre fait long int
alors le calcul doit tre fait dans le
long int ;
unsigned int ;
unsigned int
double,
et d'autre part sur tous les types entier dont la taille est
plus petite que l'entier naturel. Les variables ou les constantes des types suivants sont utilises dans une expression, les valeurs de ces variables ou constantes sont transformes en leur quivalent en entier avant de faire les calculs. Ceci permet d'utiliser des caractres, des entiers courts, des champs de bits et des numrations de la mme faon que des entiers. Le principe permet d'utiliser la place d'un entier : des caractres et des entiers courts signs ou non signs ; des champs de bits et des numrations signs ou non signs. Des exemples de conversions implicites sont donns dans le tableau3.4. Il est possible de forcer la conversion d'une variable (ou d'une expression) dans un autre type avant de l'utiliser par une conversion implicite. Cette opration est appele cast. Elle se ralise de la manire suivante : c Christian Bac 1985-2003
CHAPITRE 3.
TYPES ET VARIABLES
23
(type) expression
Prenons pour exemple l'expression :
i = (int) f + (int) d ;
f et d sont convertis en int, puis additionns. Le rsultat entier est rang dans i.
i = f + d ;
et
i = (int) f + (int) d ;
du fait de la perte des parties fractionnaires.
dclaration : une association de type avec un nom de variable ou de fonction (dans ce cas
: une dclaration et si c'est une variable, une demande d'allocation d'espace
la dclaration contient aussi le type des arguments de la fonction, les noms des arguments peuvent tre omis),
dnition
pour cette variable, si c'est une fonction la dnition du corps de fonction contenant les instructions associes cette fonction. De manire simpliste, une dclaration fait rfrence une dnition dans une autre partie du programme. Elle peut se traduire par je sais qu'il existe une variable ayant ce type et portant ce nom.
exo1.c,
chane de 10 caractres globale et statique ; tableau de 10 entiers global ; pointeur sur caractre local en registre ; ottant local ; caractre local statique ; entier nomm ex externe. Dans la fonction
main(),
Compiler avec :
ex
gcc -c exo1bis.c
3.10.2 Exercice 2
Dans un chier appel
exo2.c,
"bonjour" ;
24
3.10.
un pointeur sur caractre initialis l'adresse du premier lment du tableau. Compiler, essayer de mettre l'adresse de l'entier dans le pointeur de caractre et regardez les messages d'erreurs. Une fois que vous aurez lu le chapitre 4 sur les lments de bases pour raliser les premiers programmes, faire crire le tableau partir de son nom et avec le pointeur.
Programme 3.6
1 2 3 4 5 6 7 8 9 10 11 12
/* declaration des variables globales */ int global = 10; char tableau[10] = "bonjour"; int main (int argc, char *argv[], char **envp){ char *pt = tableau; /* ou pt = & tableau[0] */ pt = (char *) &global; /* adresse de l entier dans le pointeur de char */ pt = tableau; /* adresse du tableau dans le pointeur */ printf("%s\n", tableau); printf("%s\n", pt); return 0; }
3.10.3 Exercice 3
Dclarer : un entier un ottant
i; f;
ti ;
ptc ; pti ;
CHAPITRE 3.
TYPES ET VARIABLES
25
un tableau de caractres
tc.
f; i; = 0; = pti ; = tc ; = ti.
3.10.4 Exercice 4
Dnir les variables :
caractres. 50 ;
26
3.10.
1 int 2 main (int argc, char *argv[], char **envp){ 3 /* declaration et initialisation des variables */ 4 int i = 50; 5 float f = 3.1415927; 6 long l = 040L; 7 char c = 'z'; 8 static char tc[] = "qwertyuiop"; 9 return 0; 10 }
Chapitre 4
Elments de base
Le langage C est utilis dans un contexte interactif. Ce qui veut dire que la plupart des programmes crits en langage C font des changes d'information avec un utilisateur du programme. Bien sr, le langage C est un langage des annes 70 et l'ide de l'interaction avec l'utilisateur est celle des systmes centraliss temps partag. Un utilisateur de ce type de systme est connect via une voie d'entre-sortie qui permet d'changer des caractres. Ces voies sont la plupart du temps relies un tltype (cran, clavier, avec sortie optionnelle sur papier). Les caractres sont crits sur l'cran du terminal et lus partir du clavier. Ce modle cran clavier qui est repris par le systme UNIX est celui des interactions en langage C partir des chiers standard d'entre et de sortie. Les entre-sorties en langage C ne sont pas prises en charge directement par le compilateur mais elles sont ralises travers des fonctions de bibliothque. Le compilateur ne peut pas faire de contrle de cohrence dans les arguments passs ces fonctions car ils sont de type variable. Ceci explique l'attention toute particulire avec laquelle ces oprations doivent tre programmes.
4.1 Bonjour
Le premier programme que tout un chacun crit lorsqu'il apprend un nouveau langage rpond la question suivante : comment crire un programme principal qui imprime programme est donn dans la gure 4.1. Il est constitu de la manire suivante : la premire ligne est une directive pour le pr-processeur qui demande celui-ci de lire le chier reprsentant l'interface standard des entres sorties. Le contenu de ce chier est dcrit
Bonjour ?
Ce
Fig.
28
4.2.
LIRE ET CRIRE
de manire approfondie dans le chapitre 16. Cette premire ligne doit tre prsente dans tout module faisant appel des fonctions d'entres sorties et en particulier aux fonctions et
scanf() ;
printf()
il n'y a pas de variable globale ; le programme contient une seule fonction Cette fonction est utilise sans argument ; la dnition de la fonction ouvrante ; elle ne contient pas de variable locale ;
main()
main()
la seule instruction correspond un appel de fonction qui provoque l'criture sur le terminal. Cette instruction est une demande d'criture d'une chane de caractres ; la fonction La fonction
main() est termine par une accolade fermante. printf()1 est une fonction2 qui reoit un nombre d'arguments variable. Ces argu-
ments sont transforms en une chane de caractres. Cette transformation fait appel une notion de format. Comme nous le verrons plus loin, le format dnit le type de la donne en mmoire et le mode de reprsentation de la donne lorsqu'elle est ache.
scanf()
printf().
sur le clavier. Le programme 4.1 est un exemple de lecture et d'criture l'cran d'une chane de
Programme 4.1
1 2 3 4 5 6 7 8 9 10
#include <stdio.h> char tt[80]; /* Tableau de 80 caracteres */ int main (int argc, char *argv[]) { printf ("ecrivez une chaine de caracteres : "); scanf ("%s", tt); printf ("\nLa chaine entree est : %s\n", tt); return 0; }
printf()
Donnes en entre
bonjour
main().
nition d'une variable globale. Cette variable est un tableau de quatre-vingt caractres destin
1 La
fonction
printf@A
fait
liF.
2 La
Ces chiers sont stocks dans des parties de l'arborescence qui dpendent de l'installation du compilateur
stdioFh
fonctions. Le module objet est associ au programme lors de l'dition de liens (chap. 1). notion de fonction sera explicite au chapitre 5.
CHAPITRE 4.
ELMENTS DE BASE
29
%d %f %c %s
Tab.
printf
et
scanf
recevoir les caractres lus au clavier. Il n'y a toujours pas de variable locale. Les seules instructions sont les appels aux fonctions de lecture et d'criture (scanf() et
printf()).
a a a a
= b + c ; = b * c ; = b / c ; = b - c ;
chane de caractres (vision humaine) en une reprsentation manipulable par la machine (vision machine), et vice et versa. Pour raliser ces transformations ces fonctions sont guides par des formats qui dcrivent le type des objets manipuls (vision interne) et la reprsentation en chane de caractres cible (vision externe). Par exemple, un format du type en base 16 (hexadcimal).
%x
variable est du type entier et d'autre part que la chane de caractres qui la reprsente est exprime
Pour
printf(), scanf(),
insrs les caractres reprsentant la ou les variables crire. Pour un format est une chane de caractres qui dcrit
la ou les variables lire. Pour chaque variable, un type de conversion est spci. Ce type de conversion est dcrit par les caractres qui suivent le caractre %.
Les types de conversion les plus usuels sont donns dans la table4.1. Dans une premire approche de
scanf(),
de conversion dans le format de lecture. Le lecteur curieux peut se reporter la section 16.5. Le tableau 4.2 donne un rsum des dclarations de variables et des formats ncessaires leurs manipulations pour Le
printf
et
scanf.
&
est un oprateur du langage C dont nous parlons dans la section 5.1. Cet oprateur doit
tre mis devant le nom de la variable, dans les formats destins la fonction tableau de caractres.
scanf,
comme le
montre le tableau 4.2, pour les variables dont nous avons dj parl sauf pour les variables du type
Les exemples de lecture d'une chane de caractres montrent que l'adresse du premier lment d'un tableau correspond au nom de tableau, nous en reparlerons dans le chapitre 10. c Christian Bac 1985-2003
30
4.4.
PLUS SUR
PRINTF()
ET
SCANF()
dclaration
int i ; int i ; int i ; unsigned int i ; short j ; short j ; short j ; unsigned short j ; long k ; long k ; long k ; unsigned long k ; float l ; float l ; float l ; double m ; double m ; double m ; long double n ; long double n ; long double n ; char o ; char p[10] ;
lecture
scanf("%d",&i) ; scanf("%o",&i) ; scanf("%x",&i) ; scanf("%u",&i) ; scanf("%hd",&j) ; scanf("%ho",&j) ; scanf("%hx",&j) ; scanf("%hu",&j) ; scanf("%ld",&k) ; scanf("%lo",&k) ; scanf("%lx",&k) ; scanf("%lu",&k) ; scanf("%f",&l) ; scanf("%e",&l) ; scanf("%lf",&m) ; scanf("%le"&m) ; scanf("%Lf"&n) ; scanf("%Le"&n) ; scanf("%c",&o) ; scanf("%s",p) ; scanf("%s",&p[0]) ;
criture
printf("%d",i) ; printf("%o",i) ; printf("%x",i) ; printf("%u",i) ; printf("%d",j) ; printf("%o",j) ; printf("%x",j) ; printf("%u",j) ; printf("%ld",k) ; printf("%lo",k) ; printf("%lx",k) ; printf("%lu",k) ; printf("%f",l) ; printf("%e",l) ; printf("%g",l) ; printf("%f",m) ; printf("%e",m) ; printf("%g",m) ; printf("%Lf",n) ; printf("%Le",n) ; printf("%Lg",n) ; printf("%c",o) ; printf("%s",p) ; printf
et
format externe
dcimal octal hexadcimal dcimal dcimal octal hexadcimal dcimal dcimal octal hexadcimal dcimal point dcimal exponentielle la plus courte des deux point dcimal exponentielle la plus courte point dcimal exponentielle la plus courte caractre chane de caractres
Tab.
4.2 Exemples de
scanf
CHAPITRE 4.
ELMENTS DE BASE
31
Le programme 4.2, montre qu'il est possible de faire l'criture ou la lecture de plusieurs variables en utilisant une seule chane de caractres contenant plusieurs descriptions de formats.
Programme 4.2
1 2 3 4 5 6 7 8 9 10 11 12
scanf() #include <stdio.h> int main (int argc, char *argv[]) { int i = 10; float l = 3.14159; char p[50] = "Bonjour"; printf ("%d bonjour %f %s\n", i, l, p); scanf ("%d%f%s", &i, &l, p); printf ("Apres lecture au clavier : %d %f %s\n", i, l, p); return 0; }
Donnes en entre
23 6.55957 salut
main()
4.5.2 Exercice 2
Reprendre l'exercice 1 en sparant chaque impression par un retour chariot.
4.5.3 Exercice 3
Dclarer des variables des types suivants : c Christian Bac 1985-2003
32
4.5.
EXERCICES SUR
PRINTF()
ET
SCANF()
Programme 4.3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
#include <stdio.h> int main (int argc, char *argv[], char **envp){ /* ecriture de a bonjour 32567 32567 hexa 32567 octal 32567 non signe */ printf("%c", 'a'); printf("%s", "bonjour"); printf("%d", 32567); printf("%x", 32567); printf("%o", 32567); printf("%d", (unsigned) 32567); /* ecriture de pi format e f g */ printf("%e", 3.1415927); printf("%9.7f", 3.1415927); printf("%g", 3.1415927); return 0; }
entier ; caractre ; ottant ; chane de caractres ; puis raliser des oprations de lecture an d'aecter ces variables.
4.5.4 Exercice 4
Lire et rcrire les lments de l'exercice 3.
CHAPITRE 4.
ELMENTS DE BASE
33
Programme 4.4
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
#include <stdio.h> int main (int argc, char *argv[], char **envp){ /* ecriture de a bonjour 32567 32567 hexa 32567 octal 32567 non signe */ printf("%c\n", 'a'); printf("%s\n", "bonjour"); printf("%d\n", 32567); printf("%x\n", 32567); printf("%o\n", 32567); printf("%d\n", (unsigned) 32567); /* ecriture de pi au format e f g */ printf("%e\n", 3.1415927); printf("%9.7f\n", 3.1415927); printf("%g\n", 3.1415927); return 0; }
34
4.5.
EXERCICES SUR
PRINTF()
ET
SCANF()
Programme 4.5
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
#include <stdio.h> int main (int argc, char *argv[], char **envp){ /* declaration des variables */ int evry; char dassaut; float ille; char io[100]; /* saisie du nombre entier */ printf("entrer un entier\n"); scanf("%d", &evry); /* saisie du caractere */ /* en effacant le caractere blanc ou \r ou \n precedent genant pour %c */ printf("entrer un caractere\n"); scanf(" %c", &dassaut); /* saisie du nombre reel */ printf("entrer un reel\n"); scanf("%f", &ille); /* saisie de la chaine de caracteres */ printf("entrer une chaine de caracteres\n"); scanf("%s", io); return 0; }
Donnes en entre
126 f 655957e-1 unseulmot possible
CHAPITRE 4.
ELMENTS DE BASE
35
Programme 4.6
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
#include <stdio.h> int main(int argc, char *argv[], char **envp){ /* declaration des variables */ int evry; char dassaut; float ille; char io[100]; /* saisie du nombre entier */ printf("entrer un entier\n"); scanf("%d", &evry); /* saisie du caractere */ /* en effacant le caractere blanc (\r ou \n) precedent genant pour %c */ printf("entrer un caractere\n"); scanf(" %c", &dassaut); /* saisie du nombre reel */ printf("entrer un reel\n"); scanf("%f", &ille); /* saisie de la chaine de caracteres */ printf("entrer une chaine de caracteres\n"); scanf("%s", io); /* impression des resultats */ printf("%d\n%c\n%f\n%s\n", evry, dassaut, ille, io); return 0; }
Donnes en entre
126 f 655957e-1 unseulmot possible
36
4.5.
EXERCICES SUR
PRINTF()
ET
SCANF()
Chapitre 5
Oprateurs et expressions
Le langage C est connu pour la richesse de ces oprateurs. Il apporte aussi quelques notions innovantes en matire d'oprateurs. En particulier, le langage C considre l'aectation comme un oprateur normal alors que les langages qui l'ont prcd (par exemple FORTRAN, ADA) la considrent comme une opration privilgie. Cette richesse au niveau des oprateurs permet d'crire des expressions (combinaisons d'oprateurs et d'oprandes) parfois complexes. Les oprateurs sont les lments du langage qui permettent de faire du calcul ou de dnir des relations. Ils servent combiner des variables et des constantes pour raliser des expressions. La classication faite ci-aprs est guide par le nombre d'oprandes mis en cause par l'oprateur et non par l'utilisation des oprateurs.
-2 o 2 est une constante ; -i o i est une variable ; -(i+2) o i+2 est une expression.
Le tableau 5.1 donne la liste des oprateurs un-aires. Nous allons prendre quelques exemples pour expliquer l'utilisation de base de ces oprateurs sur les variables dcrites dans le programme 5.1.
Oprateur
Utilisation oprateur d'adresse appel aussi de rfrencement oprateur d'indirection ou de drfrencement sur une adresse oprateur de dcrmentation oprateur d'incrmentation oprateur donnant la taille en octet ngation logique moins unaire, inversion du signe plus unaire complment un
Tab.
38
5.1.
OPRATEURS UN-AIRES
Fig.
Le
& est l'oprateur de rfrencement, il retourne l'adresse en mmoir (rfrence) de la variable &var donne l'adresse en mmoire de la variable var. Cette adresse peut tre pint = &var ;
utilise pour aecter un pointeur ( la condition que le pointeur soit d'un type compatible avec l'adresse de la variable). Comme le montre l'extrait de l'exemple :
* est
l'oprateur d'indirection. Il permet d'accder une variable partir d'une adresse (le
plus souvent en utilisant la valeur contenue dans un pointeur). Dans notre programme 5.1, donne la valeur
10,
de mme que
*pint,
puisque
pint
*&var var.
pint
et la variable
var.
pint = &nvar ;
Fig.
CHAPITRE 5.
OPRATEURS ET EXPRESSIONS
39
*pint = var - 2
@ 0x20000,
var
R0 8) ;
3. mettre la valeur de
4.
pint dans le registre A0 soit A0 0x20008) ; mettre la valeur qui est dans R0 l'adresse contenue dans le A0, c'est--dire dans var (@ A0 R0, soit 0x20008 8).
@ 0x20004,
registre
Nous reparlerons des relations entre les pointeurs et les variables dans le chapitre 10 sur les tableaux et les pointeurs.
--
et
++
var = var - 1, ce qui implique en partant d'une variable var ayant une 8 que cette variable contient la valeur 7 une fois l'expression calcule l'excution ; var++ est quivalent var = var + 1, ce qui implique en partant de var ayant une valeur de 8 que cette variable contient la valeur 9 la n de l'excution de l'expression.
est quivalent valeur de Il est possible d'utiliser les oprateurs un-aires d'incrmentation et de dcrmentation derrire la variable (postx) ou devant celle-ci variable (prx). Ce qui permet de post-incrmenter, de pr-incrmenter, de post-dcrmenter ou de pr-dcrmenter. Lorsque l'oprateur est prx, l'opration est applique avant que la valeur correspondant l'opration ne soit calcule. Dans le cas o l'opration est post-xe, la valeur de la variable avant l'opration est utilise pour les autres calculs et ensuite l'opration est applique.
var
0.
et
j,
de
j = ++i, c'est une pr-incrmentation de la variable i. Cela signie incrmeni dans j. la n de cette opration i vaut 1 et j vaut 1. En
anticipant sur l'oprateur de succession 5.2.5, nous pouvons considrer cette instruction comme quivalente :
i = i+1 , j = i
Si au contraire, nous crivons menter vaut
j = i++, cela signie mettre la valeur de i dans j puis incri de 1. En partant des mmes valeurs, i valant 0 et j valant 0, la n de cette instruction 1 et j vaut 0. Cette opration est quivalente :
j=i, i = i+1, j
1 Cet
exemple suppose un processeur simple ayant des registres internes banaliss appels R0, R1, . . .pour les registres de donnes et A0, A1 pour les registres d'adresses. L'@ est utilis pour signier le contenu de la variable l'adresse.
40
5.1.
OPRATEURS UN-AIRES
sizeof
sizeof f
donne la valeur
42 .
sizeof peut aussi donner la taille d'un type, le sizeof f est quivalent sizeof(long).
langage en assembleur, et non lors de l'excution du programme. L'expression lors de la compilation). Le type de la valeur calcule par sizeof est
sizeof sont raliss par le compilateur lors de la traduction du sizeof f est donc
une valeur constante et peut entrer dans la construction d'une expression constante (calculable
size_t
3.4. Ce type est un type synonyme, comme dcrit dans le chapitre 14, il est dni dans le chier
<stddef.h>.
1.
!var
vaut
car
var
var
contient
9.
5.1.8 Complment un
L'oprateur
utilis dans les calculs de masquage et nous le considrons comme un oprateur portant sur les bits de l'oprande associ. Si nous gardons l'exemple de notre variable de type entier
var
contenant la valeur
10.
En
0000 0000 0000 0000 0000 0000 0000 1010 et la valeur ~var est quivalente en binaire : 1111 1111 1111 1111 1111 1111 1111 0101 soit la valeur dcimale -11. -1, dont la valeur en binaire est : 1111 1111 1111 1111 1111 1111 1111 1111
complment 2 puisque plus 1.
considrant qu'un entier est reprsent sur 16 bits, cette valeur est quivalente en binaire :
Ceci explique pourquoi en rfrence au complment 1, l'inversion de signe est aussi appele
2 Un
entier long sur les machines les plus courantes est reprsent sur 32 bits soit 4 octets.
CHAPITRE 5.
OPRATEURS ET EXPRESSIONS
41
Oprateurs
Usage addition, soustraction, multiplication, division, reste de la division entire. et, ou, ou exclusif vers la droite ou vers la gauche infrieur, infrieur ou gal, suprieur, suprieur ou gal gal, non gal et logique, ou logique aectation succession
Tab.
+ - * /.
Comme nous avons dj vu les oprateurs un-aires, vous remarquerez l'utilisation contextuelle dans le cas des trois symboles : son nombre d'oprandes. Comme nous le verrons plus loin, le type (au sens type des donnes) de l'opration est dtermin par le type des valeurs sur lesquelles portent l'opration. Les oprations arithmtiques classiques peuvent s'appliquer aux types entiers et dans ce cas elles ont un comportement d'opration entire (en particulier la division). Ces oprations s'appliquent aussi aux types avec partie dcimale et dans ce cas, elles donnent un rsultat avec partie dcimale. Le langage C introduit l'oprateur modulo, not
+ - *.
entire dtermine par les deux oprandes entiers qui lui sont associs. Par exemple, l'expression
14 % 3
donne la valeur
2.
short int long). Ces oprations servent stocker des valeurs qui s'expriment
3 dans le systme UNIX est un exemple
dans de petits intervalles. Par exemple, il sut de trois bits pour exprimer une valeur entre 0 et 7. Ainsi, la reprsentation des droits d'accs sur un chier caractristique d'utilisation. Les oprations de niveau bit sont utilises de manire interne par les systmes d'exploitation pour l'interfaage des priphriques. Elles sont aussi beaucoup utilises dans le cadre des rseaux
3 Les
droits sont exprims sur trois bits que l'on appelle communment les bits r(ead) w(rite) et (e)x(ecute).
Les droits sont exprims pour trois populations : le propritaire du chier, le groupe propritaire et les autres. Un quatrime groupe de trois bits (sst) est utilis pour dnir des comportements particuliers.
42
o le contenu d'un espace mmoire est souvent dpendant d'informations reprsentes sur peu de bits. Elles permettent aussi de manipuler les images une fois que celles-ci ont t numrises. Les oprateurs qui permettent de manipuler des expressions au niveau bit sont de deux types ceux qui permettent d'extraire une partie des informations contenue dans un oprande (oprateurs de masquage) et ceux qui modient l'information en dplaant les bits vers la droite ou vers la gauche (oprateurs de dcalage).
Oprateurs de masquage
Les trois premiers oprateurs binaires de niveau bit d'une valeur ou bien forcer certains bits un. Pour reprendre l'exemple des droits d'accs sur un chier dans le systme UNIX, considrons que le type de chier et les droits d'accs d'un chier sont contenus dans une variable du type
\& | ^)
unsigned short,
dans la valeur) reprsente le type du chier et les modes spciaux (bits appels sst) et que les neuf autres bits reprsentent les droits d'accs (rwx respectivement pour le propritaire du chier, pour le groupe auquel appartient le chier et pour les autres utilisateurs). La valeur 1. chier
0100751 sert reprsenter un chier en mode normal 010 dans la partie gauche de la valeur ;
2. pas de traitement particulier (bits sst 0) ; 3. lecture criture et excutable pour le propritaire (7 ou 4. lecture et excutable pour le groupe (5 ou 5. excutable pour les autres(1 ou
111) ;
101) ;
001).
Voici l'explication des direntes lignes du programme 5.2 : la ligne 3 met dans la variable
res
la ligne 4 met
res la partie de mode qui spcie le type de chier, aprs cette instruction 0100000 ; dans res la valeur courante de mode en conservant le type de chier et en
contient la valeur
forant les bits numro 5 et 3 1. Ces bits reprsentent respectivement le droit en criture pour le groupe et le droit en lecture pour les autres. Ainsi, cette instruction met dans la variable
res
la valeur
de
mode
100573,
res
contient la
>>)
riables de type entier en poussant les bits vers la gauche ou la droite. Ces oprateurs servent raliser des tests ou eacer certaines parties d'une variable. Le dcalage peut se faire vers la gauche ou vers la droite. c Christian Bac 1985-2003
CHAPITRE 5.
OPRATEURS ET EXPRESSIONS
43
Le dcalage vers la droite peut tre sign si l'expression est signe, le rsultat est cependant dpendant de l'implantation (ce qui veut dire que pour crire un programme portable il ne faut pas utiliser le dcalage droite sur une valeur ngative). De manire simple (en ne parlant pas des cas de dbordement), un dcalage vers la gauche d'une position revient une multiplication par deux et un dcalage vers la droite correspond une division par deux.
Programme 5.3
1 2 3 4 5 6 7 8 9 10 11 12 13
#include <stdio.h> int main (int argc, char *argv[]) { unsigned short int mode = 0100751; int res = mode << 4; printf ("res = %o\n", res); res = res >> 4; printf ("res = %o\n", res); res = (mode >> 12) << 12; printf ("res = %o\n", res); return 0; }
res
la valeur correspondant
mode
supprimant ainsi la partie qui spcie le type de chier. Le dcalage vers la gauche a t ralis en insrant des bits la valeur zro sur la droite de la valeur. La variable la n de cette opration la valeur la ligne 3 remet dans
conservant que les droits d'accs du chier. Cette ligne met dans la variable
000751. res
res sa valeur courante dcale de quatre positions vers la droite, en ne res la valeur
017220 ;
res contient
Vous constatez que nous avons ainsi eac la partie de la valeur qui correspond au
type du chier ; rciproquement la ligne 4 eace les bits correspondant aux droits d'accs en mettant dans la valeur de met dans la variable
<= >
>=
==
!=).
Ces
oprateurs peuvent tre utiliss avec des variables de type entier ou des variables ayant une partie dcimale. Notez le double gal pour le test qui est souvent source de confusion avec le simple gal qui dcrit l'aectation. Les deux autres oprateurs de tests (&&
||)
le ou logique. Le et logique permet de dcrire qu'une condition constitue de deux parties est satisfaite si et seulement si les deux parties sont satisfaites. c Christian Bac 1985-2003
44
%=
Tab.
Le ou logique permet de dcrire qu'une condition constitue de deux parties est satisfaite ds lors qu'une des deux parties est satisfaite. Ces oprateurs servent donc dcrire des relations logiques du type ncessit de deux conditions (et logique) ou susance d'une des deux conditions (condition ou). Ces oprateurs s'appliquent des expressions que l'on peut considrer comme de type entier et dont la valeur est teste comme pour le non logique savoir une expression est considre comme fausse si la valeur correspondant cette expression est gale 0. Ainsi en langage C, pour tester si une variable de type entier entre deux bornes non strictes
12
et
143
il faut crire :
valeur comprise
i = j = k = 1
La virgule, quant elle, sert sparer deux expressions qui sont values successivement. La valeur associe sera la dernire valeur calcule. Une expression comme :
i = (j=2, k=3)
associe
la valeur 3.
L'association d'un oprateur binaire avec l'oprateur d'aectation donne les oprateurs dcrits dans le tableau 5.3. Le tableau 5.4 donne un exemple d'utilisation de chacun de ces oprateurs et la faon de lire ces direntes expressions. Ce tableau est construit en supposant que le type entier est reprsent sur 32 bits, et que les deux variables
= 5 ;.
et
int i = 100,j
i += ( j * 25 + 342 )
i += ( j += j * 25 + 342 ) - 12
celle de celle de Soit, si
et
j i
avec avec
j + j * 25 + 342 i + j - 12
vaudra 357.
Ce type d'expression est un peu compliqu et rend le programme dicile lire. Ces possibilits complexes oertes en matire d'expressions sont de ce fait peu utilises ou alors soigneusement encadres par des parenthses qui favorisent la comprhension. c Christian Bac 1985-2003
CHAPITRE 5.
OPRATEURS ET EXPRESSIONS
45
expression
quivalence
lecture ajoute 10 i ajoute j i retranche 5 i retranche j i multiplie i par 10 multiplie i par j divise i par 10 divise i par j i reoit le reste de la division entire de i par 10
oprateurs arithmtiques
i i i i i i i i i
+= += -= -= *= *= /= /= %=
10 j 5 j 10 j 10 j 10 8 8 4
i i i i i i i i i
= = = = = = = = =
i i i i i i i i i
+ + * * / / %
10 j 5 j 10 j 10 j 10
oprateurs de masquage
i &= i |= i ^=
ET de i avec 8 OU de i avec 8 OU exclusif de i avec 4 dcale i gauche de 4 positions dcale i droite de 4 positions
oprateurs de dcalage
i <<= 4 i >>= 4
Tab.
Usage Retourne ex2 si ex1 est vrai retourne ex3 si ex1 est faux
Tab.
5.2.7 Oprateur ternaire
L'oprateur ternaire met en jeu trois expressions (ex1,ex2,ex3) et permet de contruire une test avec retour de valeur. La premire expression (ex1) joue le rle de condition. Si la condition est vrie, l'valuation de la deuxime expression est ralise et le rsultat de cette expression est propag comme rsultat de l'expression globale. Dans le cas contraire (le test est faux), l'valuation de la troisime expression est ralise et le rsultat de cette expression est propag comme rsultat de l'expression globale. Prenons pour exemple l'expression
a == b ? c : d. b. c
si la valeur contenue dans la Dans le cas contraire, l'expression retourne la valeur
d.
a >= b ? a : b a
1. si la valeur de de
a;
b,
b;
permet de mmoriser dans la variable
max = a >= b ? a : b
et
b.
max
la valeur
46
Classe d'oprateur Parenthsage Appel de fonction Suxes ou Un-aires prxes Changement de type Multiplicatifs Additifs Dcalages Comparaisons galits et bit bit ou exclusif bit bit ou bit bit et logique ou logique Condition Aectations
Oprateur(s)
Succession
() () [] -> . ++ -& * + - ~ ! ++ sizeof sizeof() (type) * / % + << >> < <= > >= == != & ^ | && || ?: = += -= *= /= %= &= |= ^= <<= >>= ,
de droite gauche de droite gauche de gauche droite de gauche droite de gauche droite de gauche droite de gauche droite de gauche droite de gauche droite de gauche droite de gauche droite de gauche droite de droite gauche de droite gauche
de gauche droite
Tab.
prcdence.
l'ordre d'association des oprateurs et oprande par le compilateur. Ces rgles de prcdences sont reprsentes par le tableau 5.6, l'encart suivant donne la grille de lecture de ce tableau.
RGLE de prcdence :
La priorit des oprateurs du langage C est dcroissante de haut en bas selon le tableau 5.6. Lorsque deux oprateurs se trouvent dans la mme case du tableau 5.6, la priorit d'valuation d'une ligne de C dans laquelle se trouvent ces oprateurs, est donne par la colonne de droite (associativit), qui dtermine dans quel ordre le compilateur associe, les oprateurs et les oprandes (en commenant par la droite ou la gauche).
Il faut consulter ce tableau pour tre sr de l'ordre d'valuation d'une expression. L'associativit n'est pas la prcdence entre oprateurs d'une mme ligne de ce tableau. C'est la faon dont le compilateur analyse la ligne source en C. C'est l'ordre dans la ligne source qui est important et non l'ordre sur la ligne du tableau. Pour rsumer, cette rgle de prcdence suit l'ordre : parenthsage ; oprateurs d'accs, appel de fonction et post incrmentation ou dcrmentation ; oprateurs un-aires (associativit de droite gauche) ; c Christian Bac 1985-2003
CHAPITRE 5.
OPRATEURS ET EXPRESSIONS
47
oprateurs binaires (selon le bon sens commun, mez vous des relations oprateurs de test et oprateurs bit bit) ; oprateur ternaire (associativit de droite gauche) ; oprateurs binaires d'aectation (associativit de droite gauche) ; succession.
5.3 Expressions
Une EXPRESSION est :
Une expression ramne toujours une valeur, mme si la valeur n'est pas utilise. Une expression est fausse si son rsultat est nul. Elle est vraie si son rsultat est non nul.
La table 5.3 dcrit les relations entre expression et utilisation d'une expression dans un test. Prenons la variable
donne la valeur
10
. Cette
valeur peut tre utilise dans un test et est considre comme vraie dans ce cas.
5.4 Instructions
Maintenant que nous connaissons la notion d'expression nous pouvons introduire celle d' Une
instruction est :
instruction.
soit une instruction de contrle (voir chapitre suivant), soit une expression suivie de ;.
une accolade ouvrante "{" une liste de dnitions locales au bloc (optionnelle) une suite d'instructions une accolade fermante "}". partir de maintenant, lorsque nous employons le terme manire indirente l'une des trois signications : 1. instruction simple ; 2. ou instruction de contrle de ot ; 3. ou bloc d'instructions. c Christian Bac 1985-2003
instruction,
il peut prendre de
48
5.5.2 Exercice 2
Dnir deux entiers
et
i i i i i
+ * / %
j j j j j
i et j.
i % j.
i i i i j
5.5.3 Exercice 3
Dnir deux entiers
et
Faire crire les rsultats des direntes oprations logiques entre ou, etc.). Noter les dierences eventuelles entre les resultats de :
et
i && j i || j
et et
i & j i | j
5.5.4 Exercice 4
En faisant crire les rsultats intermdiaires, raliser les oprations suivantes sur un entier initialis 10 : division par 2 addition avec 3 c Christian Bac 1985-2003
CHAPITRE 5.
OPRATEURS ET EXPRESSIONS
49
multiplication par 2 aectation du reste de sa propre division par 3 ou avec 10 dcalage de 2 bits vers la gauche et avec 19 ou exclusif avec 7. NB : Il est possible de raliser ces oprations de deux facons direntes.
i, j, k et l, avec k initialis 12 i et j de k si i est nul ; de i + l i est non nul et j est nul de i + j dans les autres cas.
et
5.5.6 Exercice 6
En utilisant quatre variables entires ajouter 1
i, j, k
et
l: i, j
et
k.
et incrmente
crire l'expression qui aecte solutions au moins). crire l'expression qui met :
le resultat dei
+ j +1
et
de 1 (quatre
50
Programme 5.4
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
#include <stdio.h>
int i, *pti, tab[10]; int main (int argc, char *argv[], char **envp){ /* ecriture de l'adresse de l'entier */ printf(" Adresse de l'entier : %x \n", &i); /* affectation de l'entier a 1 */ i = 1; /* ecriture de la valeur de l'entier + 1 */ printf(" Valeur de l'entier + 1 : %d\n", i + 1); /* ecriture de a valeur de l'entier */ printf(" Valeur de l'entier : %d\n", i); /* remplissage du tableau */ tab[0] = 1; tab[1] = 2; tab[2] = 3; tab[3] = 4; /* Affectation de l adresse de debut du tableau au pointeur */ pti = tab; /* ecriture du contenu du pointeur et de son increment. */ printf(" Contenu du pointeur : %x \n", pti); printf(" et de son increment : %x \n", pti + 1); /* ecriture du contenu des objets pointes */ printf(" contenu de l'objet pointe par pt : %d \n", *pti); printf(" et par l'increment de pt : %d \n", *++pti); /* ecriture des tailles de l'entier du pointeur et du tableau */ printf(" Taille de l'entier : %d octets \n", sizeof (i)); printf(" Taille du pointeur : %d octets \n", sizeof (pti)); printf(" Taille du tableau : %d octets \n", sizeof (tab)); /* ecriture de la negation de ce qui est pointe par pt */ printf(" Negation de pt : %d \n", !*pti); return 0; }
CHAPITRE 5.
OPRATEURS ET EXPRESSIONS
51
Programme 5.5
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
#include <stdio.h>
int main(int argc, char *argv[], char **envp){ /* Definition des deux entiers initialises a 10 et 3 */ int i = 10, j = 3; /* ecriture du resultat de differentes operations arithmetiques */ printf(" Le resultat de i + j est %d \n", i + j); printf(" Le resultat de i - j est %d \n", i - j); printf(" Le resultat de i * j est %d \n", i * j); printf(" Le resultat de i / j est %d \n", i / j); printf(" Le resultat de i %% j est %d \n", i % j); /* facon differente de calculer i % j */ printf(" calcul different de i %% j : %d \n", i - (j * (i / j))); /* nouvelle affectation de i et de j */ i = 0x0FF; j = 0xF0F; /* ecriture du resultat de differentes operations logiques */ printf(" Le resultat de i & j est %x \n", i & j); printf(" Le resultat de i | j est %x \n", i | j); printf(" Le resultat de i ^ j est %x \n", i ^ j); printf(" Le resultat de i << 2 est %x \n", i << 2); printf(" Le resultat de j >> 2 est %x \n", j >> 2); return 0; }
52
Programme 5.6
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
#include <stdio.h>
int i, *pti, tab[10]; int main (int argc, char *argv[], char **envp){ int i = 1, j = 2; /* initialisation de deux entiers */ /* ecriture du resultat de differentes operations logiques */ printf(" Resultat de diverses operations logiques avec i = 1 et j = 2\n"); printf(" Le resultat de i & j est %x \n", i & j); printf(" Le resultat de i | j est %x \n", i | j); printf(" Le resultat de i ^ j est %x \n", i ^ j); printf(" Le resultat de ~i est %x \n", ~i); printf(" Le resultat de ~j est %x \n", ~j); printf(" Le resultat de i && j est %x \n", i && j); printf(" Le resultat de i || j est %x \n", i || j); printf(" Le resultat de !i est %x \n", !i); printf(" Le resultat de !j est %x \n", !j); return 0; }
CHAPITRE 5.
OPRATEURS ET EXPRESSIONS
53
Programme 5.7
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
#include <stdio.h> int main (int argc, char *argv[], char **envp){ int i = 10; printf (" Resultat de diverses operations avec i = %d\n\n", i); /* ecriture du resultat de differentes operations */ printf(" Division par 2 %d\n", i /= 2); printf(" Addition avec 3 %d\n", i += 3); printf(" Multiplication par 2 %d\n", i *= 2); printf(" Reste de la division par 3 %d\n", i %= 3); printf(" OU logique avec 10 %d\n", i |= 10); printf(" Shift de 2 a gauche %d\n", i <<= 2); printf(" ET logique avec 19 %d\n", i &= 19); printf(" OU exclusif avec 7 %d\n", i ^= 7); return 0; }
54
Programme 5.8
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
#include <stdio.h> int main(int argc, char *argv[], char **envp){ int i, j, k = 12, l = 8; /* definition de 4 entiers */ /* lecture des valeurs de i et de j */ printf("\n Entrer la valeur de i :"); scanf("%d", &i); printf("\n Entrer la valeur de j :"); scanf("%d", &j); /* ecriture du resultat selon les valeurs de i et de j * si i est nul, impression de la valeur de k * si j est nul, impression de la valeur de i + l * impression de la valeur de i +j dans les autres cas */ printf("\n resultat : %d\n", (!i ? k : (!j ? i + l : i + j))); return 0; }
Donnes en entre
126 0
CHAPITRE 5.
OPRATEURS ET EXPRESSIONS
55
Programme 5.9
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
#include <stdio.h> int main (int argc, char *argv[], char **envp){ int i, j, k, l; /* definition des 4 entiers */ /* affectation des entiers */ i = j = k = 1; /* incrementation de i de 4 manieres differentes */ printf(" premiere solution i++ = %d \n", i++); printf(" deuxieme solution ++i = %d \n", ++i); printf(" troisieme solution i = i + 1 = %d \n", i = i + 1); printf(" quatrieme solution i += 1 = %d \n", i += 1); /* affectation de i + j + 1 a k et incrementation de i et de j */ printf(" resultat apres affectation et incrementation\n"); k = i++ + j++ + 1; /* ou i++ + ++j ou ++i+j++ ou ++i+ ++j -1 */ printf(" valeur de k : %d \n", k); printf(" valeur de i : %d \n", i); printf(" valeur de j : %d \n", j); /* ecriture d'une expression qui realise les operations suivantes : * 3 * i dans i et 3 * i + j dans j * et divise k par 2 logiquement et divise j par k * et affecte a l la puissance 2 correspondant la valeur precedente */ l = l << (j += (i *= 3)) / (k >>= l = 1); printf(" Resultat apres calcul de l'expression \n"); printf(" valeur de i ......... %d \n", i); printf(" valeur de j ......... %d \n", j); printf(" valeur de k ......... %d \n", k); printf(" valeur de l ......... %d \n", l); return 0; }
56
Chapitre 6
Instructions de contrle
Les instructions de contrle servent controler le droulement de l'enchanement des instructions l'intrieur d'un programme, ces instructions peuvent tre des instructions conditionnelles ou itratives.
6.1.1 Test
L'oprateur de test se prsente sous les deux formes prsentes dans l'encart suivant :
L'expression n'est pas forcment un test qui retourne la valeur 0 ou +1. Ce peut tre un calcul ou une aectation, car, comme nous l'avons dja dit dans la section5.1.6 , il n'y a pas de type boolen, et une expression est vraie si elle ramne un rsultat non nul ; elle est fausse si le rsultat est nul.
if (a == b) int b = 1 ; if (a = b)
Voici quelques exemples de tests en langage C : usuel comme dans tous les autres langages vrai puisque b est gal 1 (donc non nul), attention car cela met la valeur de b dans a vrai si la fonction getchar ne ramne pas vrai si c n'est pas gal 0 sinon faux
'\0'
Les tests sont souvent imbriqus pour tester si une variable contient une valeur. Par exemple l'ensemble de tests dcrit dans le programme 6.1 permet de tester si un nombre est pair ou impair et si il est suprieur 5 ou non. c Christian Bac 1985-2003
58
Programme 6.1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
#include <stdio.h> int main (int argc, char *argv[]) { int i; scanf ("%d", &i); if (i == 6 || i == 8) { printf ("le nombre est superieur a 5\n"); printf ("le nombre est pair\n"); } else if (i == 4 || i == 2 || i == 0) printf ("le nombre est pair\n"); else if (i == 7 || i == 9) { printf ("le nombre est superieur a 5\n"); printf ("le nombre est impair\n"); } else if (i == 5 || i == 3 || i == 1) printf ("le nombre est impair\n"); else printf ("ceci n est pas un nombre\n"); return 0; }
Donnes en entre
5
switch.
if,
switch
CHAPITRE 6.
INSTRUCTIONS DE CONTRLE
59
switch
{
inst 10 inst 11 inst 12
case value2 :
etc. case valueN : inst N0 inst N1 inst N2 default : inst 30 inst 31 inst 32
}
L'excution du
switch case
1. l'expression est value comme une valeur entire ; 2. les valeurs des sont values comme des constantes entires ;
case
en squence jusqu' la rencontre d'une instruction 4. les instructions qui suivent la condition
break ; ;
5. l'ordre des
default
programme ; 6. l'excution partir d'un n'est pas rencontr ; 7. plusieurs valeurs de 8. le dernier
case continue sur les instructions des autres case tant qu'un break
peuvent aboutir sur les mmes instructions ;
case
break est facultatif. Il vaut mieux le laisser pour la cohrence de l'criture, et pour case est ajout.
Les programmes 6.2, 6.3 et 6.4 sont des exemples d'utilisation de tables de sauts. Le premier exemple 6.2 est symbolique : 1. lorsque l'expression
exp
21,
20, 21 et 22 sont excutes ; 2. lorsque l'expression excutes ; 3. dans tous les autres cas, les instructions 30, 31 et 32 sont excutes. L'exemple 6.3 reprend l'exemple prcdent 6.1 ralis avec des tests imbriqus. L'xcution se droule donc de la mme faon, en utilisant la valeur dans l'expression valeur de
exp
12,
switch,
c'est--dire la
le nombre est superieur a 5, puis crit le nombre est pair ; le nombre est superieur a 5, puis crit
2. lorsque i est gal 0, 2 ou 4, le programme crit 3. lorsque i est gal 9 ou 7, le programme crit
4. lorsque i est gal 1, 3 ou 5, le programme crit 5. dans les autres cas, le programme crit Dans l'exemple 6.4, la slection une lettre, la variable
le nombre est impair ; ceci n'est pas un nombre. incrmente les variables nb_chiffres ou nb_lettres
selon
que le caractre lu au clavier est un chire, ou une lettre. Si le caractre lu n'est ni un chire ni
nb_others
60
6.2.
INSTRUCTIONS ITRATIVES
Tab.
6.1 Syntaxe du
while
Fig.
6.1 Organigramme du
while
6.2.1
Le
while
while
est dcrite dans la table 6.1.
La syntaxe du
while
rpte l'instruction tant que la valeur de l'expression s'interprte comme vraie (dif-
frente de zro). Il correspond l'organigramme de la gure 6.1. Dans l'exemple 6.5, la fonction
getchar() lorsque la n de chier est dtecte sur le clavier (par la frappe du caractre Contrle
D sur un systme de type UNIX par exemple). Nous reparlerons de manire approfondie de
getchar() est une fonction qui lit un seul caractre sur le EOF est connue et correspond ce que retourne la fonction
getchar()
Dans cet exemple 6.5, les caractres sont lus un par un au clavier et sont rangs dans les cases du tableau boucle
tab.
Cet exemple n'est pas scuris en ce sens qu'il n'y a pas de vrication de
dbordement du tableau. Nous verrons (Prog. 6.7) que cet exemple peut tre rcrit l'aide d'une
for
L'exemple 6.6 correspond la recopie de la chane de caractres contenue dans Le test de n de chane correspond correspond nul ('\0') la n de la chane
tab[i] != '\0'. Ce test fonctionne correctement car le compilateur a mis un octet tab (qui sans cela n'en serait pas une).
c Christian Bac 1985-2003
tab[i] == '\0'
CHAPITRE 6.
INSTRUCTIONS DE CONTRLE
61
est quivalent
Tab.
6.2 Comparaison du
for
et du
Fig.
6.2.2
for
for
La syntaxe du
6.2 Organigramme du
for
for s'utilise avec trois expressions, spares par des points virgules, qui peuvent tre vides : l'expression expr1 est ralise une seule fois lors de l'entre dans la boucle, nous l'appellerons
expression d'initialisation ;
2. l'expression
expr2 prend la valeur vraie l'instruction for est excute, sinon la boucle se termine ; expr3 contrle l'avancement de la boucle. Elle permet de manire gnrale de while
expr2
calculer la prochaine valeur avec laquelle la condition de passage va tre retestee, elle est excute aprs l'instruction chaque itration avant le nouveau test de passage. Le
for for
est quivalent un
contrle comme il est montr dans le tableau 6.2. Le correspond l'organigramme 6.2.
Dans le
for
comme dans le
while,
for
62
6.2.
INSTRUCTIONS ITRATIVES
Fig.
3.
6.3 Organigramme du
do while
for ( ; ; ) inst
qui joue le rle
Le premier exemple correspond une boucle de parcours classique d'un tableau de taille 10. Dans cet exemple, l'expression d'initialisation met la valeur 0 dans la variable d'indice pour parcourrir le tableau ; la condition d'excution se fait en testant si l'indice courant est strictement infrieur la taille du tableau (10), et la progression d'indice se fait par pas de 1 en utilisant l'oprateur d'incrmentation (++).
Le deuxime exemple montre comment avoir plusieurs initialisations et plusieurs expressions dans l'expression d'avancement de la boucle, en utilisant l'oprateur de succession
,.
Le troisime exemple est une convention pour crire une boucle innie. Ce type de boucle innie est utilis lorsque l'instruction qu'elle contrle n'est pas une instruction simple mais plutt un bloc d'instructions dans lequel se trouvent des conditions de sortie de la boucle (voir section 6.3 sur les ruptures de squence). L'exemple 6.7 montre l'utilisation d'une boucle
au clavier et l'aectation du tableau avec les caractres lus. L'expression de condition d'excution ralise plusieurs actions. Elle commence par vrier qu'il n'y a pas de risque de dbordement du tableau (indice infrieur la taille du tableau). Puis elle ralise la lecture d'un caractre au clavier qu'elle stocke dans la variable
c.
que la n de chier n'a pas t atteinte (attention au parenthsage il est indispensable la bonne excution). Si les deux conditions sont runies, la valeur de l'indice est infrieure la taille du tableau et le caractre lu n'est contenu dans la variable
rang.
EOF,
6.2.3
do while
do while
est donne dans l'encart suivant :
La syntaxe du
while, le do while place son test en n d'excution, d'o au moins une excution.
Il ressemble aux REPEAT UNTIL d'ALGOL ou de PASCAL. L'organigramme correspond celui au moins une fois. Dans l'exemple donn dans le programme 6.8, les variables modis de la manire suivante : 1. 2.
while mais avec le test en n plutt qu'en dbut, ce qui assure que l'instruction est ralise
i, n
et le tableau d'entiers
sont
s[0] reoit 4 et i reoit 1 puis n reoit 563 ; n tant alors suprieur 10 la boucle continue ; s[1] reoit 3 et i reoit 2 puis n reoit 56 ; n tant alors suprieur 10 la boucle continue ;
c Christian Bac 1985-2003
CHAPITRE 6.
INSTRUCTIONS DE CONTRLE
63
3.
s[2]
reoit 6 et
reoit 3 puis
reoit
5; n
Lorsque la boucle est termine, le tableau d'entier contient les valeurs 4, 3, et 6 respectivement dans les lments de rangs 0, 1 et 2.
continue break goto return void exit(int status) qui termine l'excution void longjmp(jmp_buf env, int val) qui permet de sauter un point de
Deux appels de fonctions de la bibliothque permettent aussi de modier l'ordre d'excution d'un programme. Il s'agit de l'appel aux fonctions du programme et reprise mis dans le programme.
6.3.1
continue
continue
est utilise en relation avec les boucles. Elle provoque le passage
L'instruction
l'itration suivante de la boucle en sautant la n du bloc. Ce faisant, elle provoque la non excution des instructions qui la suivent l'intrieur du bloc. Prenons le programme 6.9, qui compte le nombre de caractres non blancs rentrs au clavier, et le nombre total de caractres. Les caractres sont considrs comme blancs s'ils sont gaux soit l'espace, la tabulation horizontale, le saut de ligne ou le retour la colonne de numro zro. la n de l'excution : 1. i contient une valeur qui correspond au nombre total de caractres qui ont t taps au clavier ; 2. j contient une valeur qui correspond au nombre de caractres non blancs ; 3. et i-j contient une valeur qui correspond au nombre de caractres blancs.
6.3.2
break
break
dans le
switch.
sortir d'un bloc d'instruction associ une instruction rptitive ou alternative controle par les c Christian Bac 1985-2003
64
Fig.
6.4
break
et
continue
dans un
for
Fig.
instructions
6.5
break
et
continue
dans un
while
if, for, un while ou un do while. Il n'est pas aussi gnral qu'en ADA ou en JAVA
puisqu'il ne permet de sortir que d'un niveau d'imbrication. Dans l'exemple 6.10, nous reprenons l'exemple 6.9, de manire crer une boucle qui compte chariot ('\r') est rencontr, le un le nombre de caractres jusqu'au retour chariot en utilisant l'instruction
while
ou un
do while.
break. Lorsque le retour break provoque la sortie de la boucle for. Il en serait de mme avec
Dans l'exemple 6.11, nous reprenons l'exemple 6.5, de manire crer une boucle qui remplit le tableau en vriant qu'il n'y a pas de dbordement de taille. Dans ce cas, nous utilisons le pour sortir de la boucle lorsque la n de chier est rencontre. Les gures 6.4, 6.5 et 6.6 sont des organigrammes qui montre les eets du sur les boucles
break
for, while,
et
do while.
break et du continue
CHAPITRE 6.
INSTRUCTIONS DE CONTRLE
65
Fig.
6.3.3 goto
Le
6.6
break
et
continue
dans un
do while
goto permet d'aller n'importe o l'intrieur d'une fonction. Son utilisation systmatique
nuit la lisibilit des programmes. Il est cependant trs utilis aprs des dtections d'erreur, car il permet de sortir de plusieurs blocs imbriqus. Il est associ une tiquette appele label. Un label est une chane de caractres suivie du double point : . Le programme 6.12 est un extrait de la suite de tests du compilateur
doit retourner 2 si l'argument qui lui est pass est dirent de 0 et 1 sinon. doit retourner 8 si l'argument qui lui est pass est infrieur 10 et 4 sinon.
test_goto2
Les rsultats obtenus par les retours d'appels de fonctions sont cumuls dans la variable
goto_val.
6.3.4
return
return
Nous tudierons de manire plus dtaille les fonctions dans le chapitre 8. L'instruction
provoque la terminaison de l'excution de la fonction dans laquelle elle se trouve et le retour la fonction appelante. Cette instruction peut tre mise tout moment dans le corps d'une fonction ; son excution provoque la n de celle-ci. Cette instruction est appele de manire implicite la n d'une fonction. Le
return
fait en valuant l'expression qui suit le retourne la fonction appelante. Lorsque la fonction est de type que retourne la fonction
return.
void, le return est utilis sans expression associe, dans le cas void, la valeur calcule par le return est celle contenant le return. Les formes possibles du return sont donc : return dans une
fonction, le premier qui est excut dans le contexte
de la fonction provoque : le calcul de la valeur retrouner, la sortie de la fonction, la continuation de l'excution de la fonction appelante. Nous allons crer une fonction (voir prog. 6.13) qui retourne : elle lit une minuscule,
-1
si elle lit
EOF
et
si
66
6.4.
et
j. if
crire celui possdant la plus grande valeur absolue avec l'instruction avec l'oprateur ternaire.
6.4.2 Exercice 2
crire un programme qui imprime le type de lettre(voyelle ou consonne) entre au clavier. Remarque : il peut tre judicieux de transformer les majuscules en minuscules.
6.4.3 Exercice 3
A l'aide d'une boucle
for,
while.
6.4.4 Exercice 4
En utilisant une boucle
do while,
printf()
de chane de caractres.
6.5.2 Exercice 6
Cet exercice consiste en la lecture d'un entier, qui est le rang d'une lettre dans l'alphabet, et en l'criture de la lettre correspondant ce rang. Pour cela il faudra : initialiser un tableau de caractres avec l'alphabet ; faire une boucle de lecture d'un entier ; sortir de la boucle lorsque l'entier lu est 100 ; imprimer la lettre correspondant l'entier lorsque celui-ci est compris entre 1 et 26 ; dans les autres cas reboucler en lecture.
CHAPITRE 6.
INSTRUCTIONS DE CONTRLE
67
/* Extracted from GCC source code: this code is copyrighted see GCC source * code for copyright license */ extern void ERROR (char *, ...); extern void warning (char *, ...); extern void pedwarn (char *, ...); extern int fflag, lflag, imag, pedantic; void exemple (char *p) { switch (*p++) { case 'f': case 'F': if (fflag) ERROR ("more than one 'f' suffix on floating constant"); fflag = 1; break; case 'l': case 'L': if (lflag) ERROR ("more than one 'l' suffix on floating constant"); lflag = 1; break; case 'i': case 'I': case 'j': case 'J': if (imag) ERROR ("more than one 'i' or 'j' suffix on floating constant"); else if (pedantic) pedwarn ("ISO C forbids imaginary numeric constants"); imag = 1; break; default: ERROR ("invalid suffix on floating constant"); }
68
Programme 6.3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
#include <stdio.h> int main (int argc, char *argv[]) { int i; scanf ("%d", &i); switch (i) { case 6: case 8: printf ("le nombre est superieur a 5\n"); case 0: case 2: case 4: printf ("le nombre est pair\n"); break; default: printf ("ceci n est pas un nombre\n"); break; case 9: case 7: printf ("le nombre est superieur a 5\n"); case 5: case 1: case 3: printf ("le nombre est impair\n"); break; } return 0; }
Donnes en entre
5
CHAPITRE 6.
INSTRUCTIONS DE CONTRLE
69
Programme 6.4
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
#include <stdio.h> int main (int argc, char *argv[]) { int c, nb_chiffres = 0, nb_lettres = 0, nb_autres = 0; while ((c = getchar ()) != EOF) { switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': nb_chiffres++; break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': /* toutes les valeurs des */ case 'm': /* lettres doivent etre */ case 'n': /* presentes dans les case */ case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': nb_lettres++; break; default: nb_autres++; break; } } printf ("Chiffres lettres et autres sur le fichier d'entree : %d %d %d\n", nb_chiffres, nb_lettres, nb_autres); return 0; }
Donnes en entre
The quick brown fox jumped over the lazy dog, 1234567890.
70
Programme 6.5
1 2 3 4 5 6 7 8 9 10 11 12
#include <stdio.h> int main (int argc, char *argv[]) { char tab[80]; int c, rang = 0; while ((c = getchar ()) != EOF) tab[rang++] = c; tab[rang]='\0'; printf("Caracteres lus : %s\n",tab); return 0; }
Donnes en entre
The quick brown fox jumped over the lazy dog, 1234567890.
Caracteres lus : The quick brown fox jumped over the lazy dog, 1234567890.
Programme 6.6
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
while #include <stdio.h> int main (int argc, char *argv[]) { char tab[] = "Message initialise"; char tab2[50]; int i = 0; while (tab[i]) { tab2[i] = tab[i]; i++; } tab2[i] = '\0'; printf ("Resultat de la copie de tab : %s \n", tab); printf ("dans tab2 : %s \n", tab2); return 0; }
CHAPITRE 6.
INSTRUCTIONS DE CONTRLE
71
Programme 6.7
1 2 3 4 5 6 7 8 9 10 11 12
#include <stdio.h> int main (int argc, char *argv[]) { char tab[80]; int rang, c; for (rang = 0; rang < 80 && (c = getchar ()) != EOF; rang++) tab[rang] = c; tab[rang]='\0'; printf ("Contenu du tableau tab apres execution :\n\t%s\n", tab); return 0; }
Donnes en entre
The quick brown fox jumped over the lazy dog, 1234567890.
Contenu du tableau tab apres execution : The quick brown fox jumped over the lazy dog, 1234567890.
Programme 6.8
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
#include <stdio.h> int main (int argc, char *argv[]) { int s[10], i = 0, j=0, n = 5634; do s[i++] = n % 10; while ((n /= 10) > 10); printf("Valeurs des entiers dans s : "); for(j=0;j<i;j++){ printf("%d ",s[j]); } printf("\n"); return 0; }
72
Programme 6.9
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
for #include <stdio.h> int main (int argc, char *argv[]) { int i, j, c; for (i = 0, j = 0; (c = getchar ()) != EOF; i++) { if (c == ' ') continue; if (c == '\t') continue; if (c == '\r') continue; if (c == '\n') continue; j++; } printf ("Caracteres lus : %d dont non blancs %d \n", i, j); return 0; }
Donnes en entre
The quick brown fox jumped over the lazy dog, 1234567890.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
#include <stdio.h> int main (int argc, char *argv[]) { int i, j, c; for (i = j = 0; (c = getchar ()) != EOF; i++) { if (c == '\r') break; if (c == ' ') continue; j++; } printf ("Caracteres lus : %d dont non blancs %d \n", i, j); return 0; }
Donnes en entre
The quick brown fox jumped over the lazy dog, 1234567890.
CHAPITRE 6.
INSTRUCTIONS DE CONTRLE
73
Programme 6.11
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
for break #include <stdio.h> int main (int argc, char *argv[]) { char tab[80]; int c, rang; for (rang = 0; rang < 80; rang++) { if ((c = getchar ()) != EOF) tab[rang] = c; else break; } tab[rang]='\0'; printf("Ensemble de caracteres lus :\n %s\n",tab); return 0; }
et
Donnes en entre
The quick brown fox jumped over the lazy dog, 1234567890.
Ensemble de caracteres lus : The quick brown fox jumped over the lazy dog, 1234567890.
74
Programme 6.12
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
goto /* From GCC TestSuite this code is copyrighted see GCC source code for * copyright license */ /* Check the use of goto. */ int goto_val;
Utilisation de l'infme
int test_goto1 (int f) { if (f) /* count(2) */ goto lab1; /* count(1) */ return 1; /* count(1) */ lab1: return 2; /* count(1) */ } int test_goto2 (int f) { int i; for (i = 0; i < 10; i++) /* count(15) */ if (i == f) goto lab2; /* count(14) */ return 4; /* count(1) */ lab2: return 8; /* count(1) */ } /* Added code for test not included in GCC test suite */ #include <stdio.h> int main(int argc, char * argv) { printf("Res1 : %d\n",goto_val += test_goto1 (0)); printf("Res2 : %d\n",goto_val += test_goto1 (1)); printf("Res3 : %d\n",goto_val += test_goto2 (3)); printf("Res4 : %d\n",goto_val += test_goto2 (30)); return 0; }
CHAPITRE 6.
INSTRUCTIONS DE CONTRLE
75
'1': case '2': case '3': case '4': '6': case '7': case '8': case '9': 'b': 'g': 'l': 'q': 'v': case case case case case 'c': 'h': 'm': 'r': 'w': case case case case case 'd': 'i': 'n': 's': 'x': case case case case case 'e': 'j': 'o': 't': 'y':
76
Programme 6.14
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
#include <stdio.h> int main(int argc, char *argv[], char **envp){ int i, j; /* definitions de deux entiers */ printf(" Entrer les valeurs de i et de j "); scanf("%d%d", &i, &j); /* lecture des deux entiers */ /* ecriture de l'entier possedant la plus grande valeur * absolue a l'aide de l'instruction if */ if(i == j || i == -j){ printf("\nles deux entiers i (%d) et j (%d) ", i, j); printf("sont egaux en valeur absolue\n"); return 0; } printf("\nle plus grand en valeur absolue de i (%d) et j (%d)", i, j); printf(" est : "); if(i < 0) if(j < 0) if(i > j) printf(" j : %d\n", j); else printf("i : %d\n", i); else if(-i > j) printf("i : %d\n", i); else printf("j : %d\n", j); else if(j < 0) if(i > -j) printf("i : %d\n", i); else printf("j : %d\n", j); else if(i > j) printf("i : %d\n", i); else printf("j : %d\n", j); /* ecriture de l'entier possedant la plus grande valeur * absolue a l'aide de l'operateur ternaire */ printf("Avec l'operateur ternaire\n"); printf("le plus grand en valeur absolue de i (%d) et j (%d)\n", i, j); printf("est : %c \n", (((i < 0 ? -i : i) > (j < 0 ? -j : j)) ? 'i' : 'j')); printf(" dont la valeur est : %d \n", (((i < 0 ? -i : i) > (j < 0 ? -j : j)) ? i : j)); return 0; }
Donnes en entre
-25 12
CHAPITRE 6.
INSTRUCTIONS DE CONTRLE
77
Programme 6.15
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
#include <stdio.h> int main(int argc, char *argv[], char **envp){ char c; /* definition de la variable */ /* saisie du caractere a analyser */ printf(" Entrer une lettre : "); scanf(" %c", &c); /* transformation des majuscules en minuscules */ if (c >= 'A' && c <= 'Z') c += 'a' - 'A'; /* ecriture du type de lettre */ switch (c){ case 'a': case 'e': case 'i': case 'o': case 'u': case 'y': printf(" la lettre est une voyelle \n"); break; case 'b': case 'c': case 'd': case 'f': case 'g': case 'h': case 'j': case 'k': case 'l': case 'm': case 'n': case 'p': case 'q': case 'r': case 's': case 't': case 'v': case 'w': case 'x': case 'z': printf(" la lettre est une consonne \n\n"); break; default: printf(" pas une lettre !!!\n\n"); break; } return 0; }
Donnes en entre
R
78
Programme 6.16
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
#include <stdio.h> int tab[10]; /* definition du tableau */ int main (int argc, char *argv[], char **envp){ int i; int *pt; /* pointeur pour acceder au tableau */ int nbel = 5; /* premiere solution */ /* remplissage du tableau a l'aide d une boucle for */ printf(" entrer les %d entiers : ", nbel); for(i = 0; i < nbel; i++) scanf("%d", &tab[i]); printf("\n"); /* ecriture du tableau avec une boucle while */ i = 0; while(i < nbel) printf(" l'element %d du tableau est %d \n", i, tab[i++]); /* deuxieme solution a l'aide d'un pointeur */ /* remplissage du tableau a l'aide d'une boucle for */ pt = tab; printf(" entrer les %d entiers : ", nbel); for(i = 0; i < nbel; i++) scanf ("%d", pt++); printf("\n"); /* ecriture du tableau */ i = 0; pt = tab; while(pt < &tab[nbel]){ printf(" l'element %d du tableau est %d \n", i, *pt++); i++; } return 0;
Donnes en entre
1 2 3 4 5 6 7 8 9 10
CHAPITRE 6.
INSTRUCTIONS DE CONTRLE
79
Programme 6.17
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
#include <stdio.h> int main (int argc, char *argv[], char **envp){ char c; int count = 0; /* saisie du caractere a analyser */ printf(" Entrer une lettre : "); count = scanf(" %c", &c); if (count <= 0) return 0; do{ /* transformation des majuscules en minuscules */ if (c >= 'A' && c <= 'Z') c += 'a' - 'A'; /* ecriture du type de lettre */ switch(c){ case 'a': case 'e': case 'i': case 'o': case 'u': case 'y': printf(" la lettre est une voyelle \n"); break; case 'b': case 'c': case 'd': case 'f': case 'g': case 'h': case 'j': case 'k': case 'l': case 'm': case 'n': case 'p': case 'q': case 'r': case 's': case 't': case 'v': case 'w': case 'x': case 'z': printf(" la lettre est une consonne \n"); break; default: printf(" pas une lettre !!!\n\n"); break; } printf(" Entrer une lettre : "); count = scanf(" %c", &c); }while(count == 1); return 0; }
Donnes en entre
qwerty
80
Programme 6.18
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
#include <stdio.h> char tab[100]; /* ligne initiale */ char ntab[100]; /* ligne avec blancs compresses */ int main (int argc, char *argv[], char **envp) { char c; int i = 0; /* indice dans tab */ int j = 0; /* indice dans ntab */ int blk = 0; /* 1 si blanc rencontre 0 sinon */ int s = 0; /* marque de debut de ligne */ /* remplissage du tableau par lecture de la ligne */ printf(" Entrer une chaine avec des tabs et des blancs \n"); while((c = getchar ()) != '\n'){ if (i >= 99) break; tab[i++] = c; } tab[i] = '\0'; /* parcours de tab et passage dans ntab en supprimant */ /* les caracteres inutiles */ i = 0; while((c = tab[i++]) != '\0'){ /* elimination des tabs et des blancs de debut de ligne */ if((c == ' ' || c == '\t') && s == 0) continue; s = 1; /* remplacement de la tabulation par un blanc */ if(c == '\t') c = ' '; /* remplacement de plusieurs blancs par un seul */ if(c == ' ') if(blk != 0) continue; else blk = 1; else blk = 0; ntab[j++] = c; } ntab[j] = '\0'; /* on assure la fin de chaine */ printf("\nAncienne ligne :\n %s\n", tab); printf("Nouvelle ligne :\n %s\n", ntab); return 0; }
CHAPITRE 6.
INSTRUCTIONS DE CONTRLE
81
Programme 6.19
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
#include <stdio.h>
/* Tableau contenant l'alphabet */ char tab[] = "abcdefghijklmnopqrstuvwxyz"; int main(int argc, char *argv[], char **envp){ int i, count; /* boucle de lecture */ while (1){ i = 0; printf("entrer un nombre : "); count = scanf("%d", &i); if(count != 1) break; /* on n'a pas lu un nombre */ if(i == 100) break; /* sortie de la boucle */ if(i < 1 || i > 26) continue; /* nombre n'est pas entre 1 et 26 */ /* ecriture de la lettre correspondante */ printf("\nle nombre %d correspond a la lettre %c \n", i, tab[i - 1]); } printf("\nFini\n"); return 0; }
Donnes en entre
12 4 -2 6 35 26 100
82
Chapitre 7
Programmation structure
La programmation structure est un nom gnrique qui couvre un courant de penses qui s'est dvelopp entre les annes 1965 et 1975. La programmation structure a pour but de faciliter le travail de relecture des programmes et de minimiser le travail de maintenance.
7.1 Historique
L'historique de ce mouvement est peu prs le suivant : 1965 Dijkstra [Dij65] propose la suppression de GOTO dans les langages. Ceci est associ avec les premiers dveloppements d'ALGOL. 1968 Dijkstra [Dij68] propose les 3 structures fondamentales en programmation. 1971 Wirth [Wir71] le pre du langage Pascal crit un article sur la programmation par ranements successifs. 1974 Wirth [Wir74] explicite la manire d'crire un programme bien structur. De nombreux autres articles ont t crits sur ce sujet.
1 :
squence : les instructions sont excutes de manire squentielle. slection : qui reprsente un choix dans le code excuter. La slection peut se prsenter
sous trois formes :
1 Dijkstra
84
3.
if orif : permettant de dcrire un choix multiple. case : destin crer des tables de vrit. itration : pour rpter un traitement tant qu'une
boucles ont t choisies : la boucle la boucle
4.
sortie est destine terminer une sous-tche. Deux types de sortie sont possibles : escape termine la sous-tche. cycle permet de sauter les instructions suivantes d'une boucle et de passer au cycle suivant
de cette boucle.
while : qui place le test avant le traitement. until : qui place le test aprs le traitement.
Il est possible de distinguer trois niveaux dans la structuration d'un programme : la smantique propre au langage et ses restrictions ; le respect des recommandations au niveau de l'utilisation des structures de programme ; la prsentation du texte du programme.
CHAPITRE 7.
PROGRAMMATION STRUCTURE
85
Type
Structures if else
Instruction C correspondante if (expression) instruction else instruction n'existe pas. switch. while(expression) instruction do instruction while(expression) ; for(expression ;expression ;expression) instruction
slection
itration
until
Tab.
de reter ces structures.
le dernier exemple est crit en respectant les structures et avec une mise en page qui tente Nous allons raliser cet exercice avec des tests et une boucles. Sur les systmes de type UNIX, les outils tels que de la mise en page correcte. L'diteur de aussi pour d'autre langages.
cb
ou
indent
mettre en page du code mal prsent. Ils fournissent un bon point de dpart pour avoir des ides
ou
Le programme 7.1 est crit de manire la moins structure possible. La dicult lors de la lecture de ce programme 7.1 est de trouver le chemin qui arrive sur les tiquettes. Pour la recherche d'erreur dans un code de ce type, il faut dterminer comment le programme est arriv sur une ligne. Le programme 7.2 est crit de manire structure mais sans mise en page. Dans ce cas, il est dicile de savoir quelles conditions ont men une ligne. En particulier il est dlicat de trouver la condition correspondant un
else.
Le programme 7.3 est crit de manire structure avec mise en page. La mise en page fait apparatre de manire plus vidente l'imbrication des Une autre faon claire d'crire du code avec des programme 7.4. Certains programmeurs annotent les accolades ouvrantes et fermantes avec des labels identiant le type de la structure et le numro de cette structure en commentaires. Cette technique est illustre dans le programme 7.5. L'avantage de ces solutions apparat lorsque la condition s'tend sur plusieurs pages d'un terminal. Cela vite de remonter dans le source en cherchant le
if else.
et des commentaires pour identier les accolades fermantes. Cette technique est illustre par le
if
correspondant un
else.
Il est possible de raliser la mme tche en utilisant une table de branchement. Dans l'exemple 7.6, le calcul donnant la condition doit tre comment car les direntes valeurs possibles ne sont pas videntes trouver. c Christian Bac 1985-2003
86
'\0'.
Le programme 7.7 ralise ce parcours de tableau, il est crit de manire non structure avec des
goto.
Le programme 7.8 ralise ce parcours de tableau, il est crit de manire structure avec un mais la mise en page laisse dsirer.
for
Le programme 7.9 ralise ce parcours de tableau, il est crit de manire structure avec mise en page.
CHAPITRE 7.
PROGRAMMATION STRUCTURE
87
Programme 7.1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
#include <stdio.h> int main (int argc, char *argv[]) { int i, j; printf ("Veuillez entrer deux valeurs entieres : "); scanf ("%d%d", &i, &j); if (i == j) goto T3; if (i <= 0) goto L1; if (j <= 0) goto L2; if (i > j) goto T2; goto T1; L2:if (i > -j) goto T2; goto T1; L1:if (j <= 0) goto L3; if (-i > j) goto T2; goto T1; L3:if (-i > -j) goto T2; T1:printf (" le plus grand est j : %d\n", j); goto T4; T2:printf (" le plus grand est i : %d\n", i); goto T4; T3:printf (" i et j sont egaux\n"); T4: return 0; }
Donnes en entre
10 12
88
Programme 7.2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
#include <stdio.h> int main (int argc, char *argv[]) { int i, j; printf ("Veuillez entrer deux valeurs entieres : "); scanf ("%d%d", &i, &j); if (i == j) printf (" i et j sont egaux\n"); else if (i < 0) if (j < 0) if (-i > -j) printf (" le plus grand est i : %d\n", i); else printf (" le plus grand est j : %d\n", j); else if (-i > j) printf (" le plus grand est i : %d\n", i); else printf (" le plus grand est j : %d\n", j); else if (j < 0) if (i > -j) printf (" le plus grand est i : %d\n", i); else printf (" le plus grand est j : %d\n", j); else if (i > j) printf (" le plus grand est i : %d\n", j); else printf (" le plus grand est j : %d\n", j); return 0; }
Donnes en entre
10 12
CHAPITRE 7.
PROGRAMMATION STRUCTURE
89
Programme 7.3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
#include <stdio.h> int main (int argc, char *argv[]) { int i, j; printf ("Veuillez entrer deux valeurs entieres : "); scanf ("%d%d", &i, &j); if (i == j) printf (" i et j sont egaux\n"); else if (i < 0) if (j < 0) if (-i > -j) printf ("le plus grand est i : %d\n", i); else printf ("le plus grand est j : %d\n", j); else if (-i > j) printf ("le plus grand est i : %d\n", i); else printf ("le plus grand est j : %d\n", j); else if (j < 0) if (i > -j) printf ("le plus grand est i : %d\n", i); else printf ("le plus grand est j : %d\n", j); else if (i > j) printf ("le plus grand est i : %d\n", i); else printf ("le plus grand est j : %d\n", j); return 0; }
Donnes en entre
10 12
90
Programme 7.4
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
#include <stdio.h> int main (int argc, char *argv[]) { int i, j; printf ("Veuillez entrer deux valeurs entieres : "); scanf ("%d%d", &i, &j); if (i == j) printf (" i et j sont egaux\n"); else{ if (i < 0){ if (j < 0) if (-i > -j) printf ("le plus grand est i : %d\n", i); else printf ("le plus grand est j : %d\n", j); else if (-i > j) printf ("le plus grand est i : %d\n", i); else printf ("le plus grand est j : %d\n", j); }else{ /* i >= 0 */ if (j < 0){ if (i > -j) printf ("le plus grand est i : %d\n", i); else printf ("le plus grand est j : %d\n", j); } /* fin j < 0 */ else{ if (i > j) printf ("le plus grand est i : %d\n", i); else printf ("le plus grand est j : %d\n", j); } /* fin j > 0 */ } /* fin i > 0 */ } /* fin i != j */ return 0; }
Donnes en entre
10 12
CHAPITRE 7.
PROGRAMMATION STRUCTURE
91
Programme 7.5
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
#include <stdio.h> int main (int argc, char *argv[]) { int i, j; printf ("Veuillez entrer deux valeurs entieres : "); scanf ("%d%d", &i, &j); if (i == j) printf (" i et j sont egaux\n"); else { /* ELIF 1 */ if (i < 0) { /* ELIF1.IF1 */ if (j < 0) if (-i > -j) printf (" le plus grand est i : %d\n", i); else printf (" le plus grand est j : %d\n", j); else if (-i > j) printf (" le plus grand est i : %d\n", i); else printf (" le plus grand est j : %d\n", j); } /* fin ELIF 1.IF1 */ else { /* ELIF 1.ELIF1 */ if (j < 0) { if (i > -j) printf (" le plus grand est i : %d\n", i); else printf (" le plus grand est j : %d\n", j); } /* fin j < 0 */ else { if (i > j) printf (" le plus grand est i : %d\n", i); else printf (" le plus grand est j : %d\n", j); } /* fin j > 0 */ } /* fin ELIF1.ELIF1 */ } /* fin ELIF 1 */ return 0; }
Donnes en entre
10 12
92
Programme 7.6
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
#include <stdio.h> int main (int argc, char *argv[]) { int i, j; printf ("Veuillez entrer deux valeurs entieres : "); scanf ("%d%d", &i, &j); if (i == j) printf (" i et j sont egaux\n"); else { /* l'expression (i<0) + 2*(j<0)) donne la valeur : */ /* 0 si i>0 et j>0, 1 si i<0 et j>0 */ /* 2 si i>0 et j<0 3 si i<0 et j<0 */ switch ((i < 0) + 2 * (j < 0)) { case 0: if (i > j) printf ("le plus grand est i : %d\n", i); else printf ("le plus grand est j : %d\n", j); break; case 1: if (-i > j) printf ("le plus grand est i : %d\n", i); else printf ("le plus grand est j : %d\n", j); break; case 2: if (i > -j) printf ("le plus grand est i : %d\n", i); else printf ("le plus grand est j : %d\n", j); break; case 3: if (-i > -j) printf ("le plus grand est i : %d\n", i); else printf ("le plus grand est j : %d\n", j); } /* switch */ } /* fin i != j */ return 0; }
Donnes en entre
10 12
CHAPITRE 7.
PROGRAMMATION STRUCTURE
93
int mystrlen (char tabc[]) { int i; for (i = 0; i < 100; i++) if (tabc[i] == '\0') break; return i; }
94
Chapitre 8
Fonctions
Les fonctions sont des parties de code source qui permettent de raliser le mme type de traitement plusieurs fois et/ou sur des variables direntes. Les mots procdure et fonction sont employs dans le reste de ce chapitre de manire quasi indirente. Une fonction en langage C peut : modier des donnes globales. Ces donnes sont dans une zone de mmoire qui peut tre modie par le reste du programme. Une fonction peut dans ces conditions raliser plusieurs fois le mme traitement sur un ensemble de variables dni la compilation ; communiquer avec le reste du programme par une interface. Cette interface est spcie la compilation. L'appel de la fonction correspond un change de donnes travers cette interface, au traitement de ces donnes (dans le corps de fonction), et un retour de rsultat via cette interface. Ainsi, une fonction permet de raliser le mme traitement sur des ensembles de variables dirents.
Fig.
96
8.2.
RETOUR DE FONCTION
Code C
Explications fonction plus qui retourne un rsultat de type entier et qui accepte deux arguments
int plus(int a,int b) { a = a + b; return a ; } void add(int a,int b,int *c) { *c = a + b; } long push(double X, int Y) {
...
et
de type entier.
fonction et
add
et
push
de type
double
long
de type entier
Tab.
une parenthse fermante.
L'interface d'une fonction peut tre incomplte si elle ne contient pas le nom des paramtres comme nous le verrons dans le prochain chapitre, cette interface est aussi appele signature de la fonction, et est utilises lorsque des fonctions proviennent de dirents chiers sources ou de bibliothques. Le corps de fonction est un bloc, c'est--dire : une accolade ouvrante ; des dclarations de variables locales au bloc ; des instructions ; une accolade fermante. Le tableau 8.1 donne des exemples de dnitions de fonctions en C.
void
retourne un rsultat. Le
celui de la fonction. La gnration du retour de fonction est provoque par l'appel de l'instruction
return
return expression ;
est value, et la valeur obtenue est retourne. Au niveau de la fonction appelante, le retour de fonction peut tre utilis comme la valeur d'une expression. Si nous prenons le cas de la fonction une variable (dans cet exemple la variable z).
plus() vue dans le tableau 8.1, la valeur du retour de cette fonction peut tre utilise pour aecter int x=12,y=5,z; z = plus(x,y);
Nous pouvons utiliser ce retour de fonction dans toute expression telle que dnie dans le chapitre 5. Ce qui nous permet d'crire par exemple : c Christian Bac 1985-2003
CHAPITRE 8.
FONCTIONS
97
Dnition
Appel
Tab.
z = z * plus(x,y) ;
appelante fait une copie de la valeur passe en paramtre et passe cette copie la fonction appele l'intrieur d'une variable cre dans l'espace mmoire gr par la pile d'excution (voir chap. ). Cette variable est accessible de manire interne par la fonction partir de l'argument formel correspondant. Le tableau 8.2 donne deux exemples d'appels la fonction
plus()
z = plus(1,23) ;.
tape 1 tape 2
x, y
et
z,
z.
n'a pas t initialise nous n'en connaissons pas la valeur ; dont les types corres-
pondent aux types de paramtres de la fonction : dans ce cas deux entiers ; la fonction
plus() est appele, ce qui se traduit par l'empilement de l'adresse de retour La fonction plus() dispose de deux variables qu'elle
les noms a et b. Ces deux variables sont les copies des valeurs dont nous
avons parl l'tape prcdente. Elles ont donc pour valeurs initiales respectivement 1 et
la fonction
en excutant la ligne
a=a+b ;, elle
met donc la valeur 24 dans a ; la fonction se termine en retournant cette valeur 24, cette valeur est stocke dans un
registre du processeur rserv cet eet ; les variables cres par l'appel sont dtruites (l'espace sur la pile est restitu, le pointeur
de pile est remis sa valeur initiale). la valeur stocke dans le registre du processeur est aecte la variable z (correspondant
l'aectation). La vision donne par les schmas de la gure 8.2, de mme que les autres dessins de ce chapitre, est simpliste en ce sens qu'elle considre que les cases mmoire sur la pile font toutes la mme taille et permettent de stocker des adresses ou des entiers. Elle devrait tre rane pour tenir compte de la taille des types mais alors elle deviendrait spcique une architecture. De mme, elle considre que le sommet de pile est au dessus du bas de pile, et que la taille de la pile est susante pour mettre tout nouvel lment. c Christian Bac 1985-2003
98
8.3.
Fig.
CHAPITRE 8.
FONCTIONS
99
Dclaration
Appel
Tab.
z = plus(x,y) ;
et
tape 1
(4 et 6)
plus() plus()
et
prcdente. Ces deux variables ont donc pour valeurs initiales 4 et 6 ; la fonction modie la valeur de la variable "a" en y mettant la valeur 10 ;
la fonction se termine en retournant cette valeur 10 ; les variables cres par l'appel sont dtruites.
Ces deux exemples montrent, que la fonction appele peut modier les paramtres (sauf s'ils sont qualis par
const),
mais ces paramtres sont dans son univers local. Les modications des
paramtres formels par une fonction n'ont aucune inuence sur la valeur des paramtres utiliss lors de l'appel. Par exemple, lorsque lors du deuxime appel, la fonction "a" cela ne modie pas la variable "x".
plus()
interne de cette mme fonction des variables. Dans le cas d'une adresse, la promotion en variable
deux entiers et une adresse d'entier. Cette fonction utilise le troisime argument pour communiquer
add(x,y,&z);
La gure 8.4, montre les dirents tats de la pile lors de l'excution du premier appel qui modie la variable
z en lui add(43,4,&x) ; la
(43+4). Seules les tapes premires tapes de cet appel sont reprsentes sur la gure. Ces tapes de 6 8 correspondent l'appel de fonction et l'excution de l'aectation en utilisant le pointeur. Le retour de la fonction appele la fonction appelante n'est pas reprsent. Il sut de reprendre les tapes numrots 4 et 5 en changeant la che qui va du pointeur la variable associe (ici x au lieu de z) et la valeur de la case mmoire correspondante (x doit contenir 47).
1 Vous
trouvez ici l'explication rationnelle de la formule magique qui consiste mettre un "et commercial" devant
snf@A.
100
Fig.
CHAPITRE 8.
FONCTIONS
101
Fig.
102
Type du paramtre
Tab.
double, d'autre part sur tout les types entier dont la taille est plus
petite que l'entier naturel. Lors de l'appel d'une fonction, les paramtres subissent les conversions de type un-aire telles que dcrites dans le tableau 8.4. Les plus importantes sont les suivantes : les paramtres du type les paramtres du type
Les conversions de type ayant lieu lors de l'appel d'une fonction sont dcrites dans le tableau 8.4. Les variables ou les constantes des types suivants sont utilises dans une expression, les valeurs de ces variables ou constantes sont transformes en leur quivalent en entier avant de faire les calculs. Ceci permet d'utiliser des caractres, des entiers courts, des champs de bits et des numrations de la mme faon que des entiers. Le principe permet d'utiliser la place d'un entier : des caractres et des entiers courts signs ou non signs ; des champs de bits et des numrations signs ou non signs. La norme C99 maintient ce comportement pour des questions de compatibilits si les fonctions n'ont pas d'interface connue avant l'appel. Dans le cas normal (les fonctions ont une interface connue avant leur utilisation) les valeurs des variables sont passes en maintenant leur type.
8.6 Rcursivit
En C, toute fonction peut appeler toute fonction dont elle connat le nom (nous reviendrons sur ces problmes dans le chapitre 9 sur la visibilit). En particulier, elle peut s'appeler elle-mme. Il est donc possible d'crire des fonctions rcursives. Prenons l'exemple le plus connu en matire de rcursivit : la factorielle. Cette fonction factorielle peut s'crire de la manire suivante :
Pour montrer la concision du langage, voici une factorielle crite en une seule ligne :
CHAPITRE 8.
FONCTIONS
103
main()
systme d'exploitation, en particulier le systme UNIX. Dans un systme de type UNIX, les paraune des fonctions du type de la manire suivante :
main() sont passs par le shell dans la majorit des cas. Ils sont passs par exec(3). Ces paramtres ont une structure prdnie. Ils sont dcrits
int main(int argc,char *argv[], char *envp[]) Les noms argc, argv et envp sont des noms mnmoniques. Ils signient argument count, argument values et environment pointer.
La fonction
main()
systme. Ces paramtres sont un entier et deux tableaux de pointeurs sur des caractres. La signication de ces arguments est la suivante :
argc argv
contient le nombre d'arguments qui ont t passs lors de l'appel (nombre de mots dans la ligne de commande) ; contient les arguments de la ligne de commande au niveau du dcoups en mots par le
du binaire excutable
shell
shell.
Il y a toujours au moins un argument qui correspond au nom du binaire excutable appel ; le nombre de pointeurs valides dans le premier tableau est donn par le variable entire (nombre d'arguments elle-mme. contient les variables d'environnement du
argc) ;
envp
shell au
Contrairement au premier tableau, la taille de ce deuxime tableau n'est pas donne par un nombre de mots valides. La n de ce deuxime tableau est donne par un marqueur. Ce marqueur est un pointeur NULL, c'est--dire, un pointeur qui contient l'adresse 0. Dans ce cas, cette adresse est du type (char
*)
ou
Les programmes 8.1 et 8.2 donnent deux exemples d'utilisation des arguments du des variables d'environnement, en utilisant l'impression de chane de caractres par utilisant le format
%s
une copie de cette constante et l'on obtient une variable de type compatible. Ceci explique pourquoi vous pouvez passer une constante et manipuler cette constante comme une variable dans la fonction appele. En C ANSI vous avez cependant la possibilit de dire que la fonction considre ses arguments comme constants. c Christian Bac 1985-2003
104
Fig.
8.5 Arguments de
main()
CHAPITRE 8.
FONCTIONS
105
Programme 8.1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
main() #include <stdio.h> int main (int argc, char *argv[],char **envp) { int i; printf("Nous avons %d arguments : \n",argc); for(i=0;i<argc;i++){ printf("argument %d == %s \n",i,argv[i]); } printf("Nous affichons les 5 premires variables d'environnement \n"); printf("mais nous les comptons toutes. \n"); for(i=0; envp[i] ;i++){ if(i<5) printf("Envp[%d] : %s \n",i,envp[i]); } printf("Il y a %d variables d'environnement : \n",i); return 0; }
Si les paramtres sont des variables, la fonction appelante empile formel peut tre direntes de celle de son argument rel.
partir de la valeur courante de la variable. Ceci explique pourquoi la valeur d'un argument
positionne son pointeur de contexte dans la pile tout en sauvegardant l'ancien fonction, de l'autre les variables locales la tape est appe-
pointeur de contexte. Ce pointeur de contexte servira pendant toute l'excution de la fonction retrouver d'un cot les arguments de la fonction. Elle fait ensuite grandir la pile de manire pouvoir ranger une copie des registres qu'elle va utiliser et les variables locales qui ne sont pas en registre. Cette ralisation faits par les concepteurs du compilateur. le le prologue de la fonction. Ce prologue dpend du type du processeur et des choix de
jusqu' rencontrer un
return, ce return provoque le passage return est associ une valeur cette valeur
est conserve dans un registre de calcul (qui sert aussi pour valuer les expressions).
106
8.10.
restitue le contexte de la fonction appelante au niveau des registres du processeur (sauf les registres scratch dnitions de restaure les registres qu'il avait sauvegards (correspondants aux registres demands par les variables de type register), puis il restaure le contexte de pile en
l'ancienne valeur dans la pile. Enn, il replace le pointeur qu'il avait avant le prologue. Finalement,
dans le pointeur d'instruction la valeur qui avait t sauvegarde sur la pile lors de l'appel. L'xcution continue alors dans la fonction appelante.
i, j, k
globadd()
et
dans
k. j,
fait appel la fonction
main()
k.
et
8.10.2 Exercice 2
Mme exercice que le prcdent mais en utilisant le passage de paramtres et le retour de fonction. Les trois variables
i, j, k
main().
La fonction d'addition est une fonction retournant un entier. Elle accepte deux paramtres entiers (p1 etp2) et retourne la somme de ces deux paramtres. La fonction
main()
et
k.
aprs
8.10.3 Exercice 3
Mme exercice que le prcdent mais en utilisant le passage de paramtres et un pointeur pour modier une variable dans la fonction appelante. Les trois variables La fonction d'addition
(p1 etp2) et un paramtre de type pointeur vers un entier qui sert pour aecter la variable dont la fonction appelante passe l'adresse avec la somme de ces deux premiers paramtres. La fonction
i, j, k de type entier sont declares localement dans la fonction main(). ptadd() est une fonction sans retour. Elle accepte trois paramtres entiers
main()
k.
et
2 Ce
sont les registres les plus utiliss, ils sont considrs par le compilateur comme utilisables pour l'valuation
CHAPITRE 8.
FONCTIONS
107
Programme 8.2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
main() #include <stdio.h> int main (int argc, char *argv[],char **envp) { int i; register char *ptc; printf("Nous avons %d arguments : \n",argc); for(i=0;i<argc;i++){ printf("argument %d == ",i); for(ptc=argv[i];*ptc;ptc++) printf("%c",*ptc); printf("\n"); } printf("Nous affichons les 5 premires variables d'environnement \n"); printf("mais nous les comptons toutes. \n"); for(i=0; envp[i] ;i++){ if(i<5){ printf("Environnement %d == ",i); for(ptc=envp[i];*ptc;ptc++) printf("%c",*ptc); printf("\n"); } } printf("Il y a %d variables d'environnement : \n",i); return 0; }
Arguments de
caractres un--un
108
8.10.
Programme 8.3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
#include <stdio.h>
/* fonction addition */
int main(int argc, char *argv[], char **envp){ /* saisie des valeurs */ printf("entrer 1 entier\n"); scanf("%d", &i); printf("entrer un autre entier\n"); scanf("%d", &j); /* appel de add et impression du resultat */ globadd(); printf(" i + j = %d\n", k); return 0; }
Donnes en entre
24 67
CHAPITRE 8.
FONCTIONS
109
Programme 8.4
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
#include <stdio.h> /*
fonction addition
int add(int p1, int p2){ return (p1 + p2); } int main(int argc, char *argv[], char **envp){ /* declarations des variables locales */ int i, j, k; /* saisie des valeurs */ printf("entrer 1 entier :"); scanf("%d", &i); printf("entrer un autre entier :"); scanf("%d", &j); /* appel de add */ k = add (i, j); printf(" i + j = %d\n", k); return 0; }
Donnes en entre
24 67
110
8.10.
Programme 8.5
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
#include <stdio.h> /*
fonction addition
void ptadd(int p1, int p2, int *pti) { *pti = p1 + p2; return; } int main(int argc, char *argv[], char **envp) { /* declarations des variables locales */ int i, j, k; /* saisie des valeurs */ printf("entrer 1 entier :"); scanf("%d", &i); printf("entrer un autre entier :"); scanf("%d", &j); /* appel de add */ ptadd(i, j, &k); printf(" i + j = %d\n", k); return 0; }
Donnes en entre
24 67
Chapitre 9
Compilations spares
La compilation spare permet de fragmenter un grand programme en des parties qui peuvent tre compiles indpendamment les unes des autres. Dans ce chapitre nous allons voir comment cette possibilit est exploitable en langage C. partir de maintenant, nous appellerons :
dclaration : une association de type avec un nom de variable ou de fonction (dans ce cas
la dclaration contient aussi le type des arguments de la fonction),
dnition
pour cette variable, si c'est une fonction la dnition du corps de fonction contenant les instructions associes cette fonction.
9.1 Programme
de chiers destins tre compils sparment.
Comme nous l'avons dj dit dans le chapitre 1, un programme en langage C est un
ensemble
La structure d'un programme, crit en langage C, est rsume dans la gure 9.1.
1,
des dnitions de fonctions, des directives de pr-compilation et des commentaires. Les directives de pr-compilation et les commentaires sont traits par le pr-processeur. Le compilateur ne voit que les quatre premiers types d'objets. Les chiers inclus par le pr-processeur ne doivent contenir que des dclarations externes ou des dnitions de types et de modles de structures.
1 Ces
dnitions de variables globales sont en fait transformes par l'diteur de liens en des demandes de rser-
112
Fig.
Fig.
CHAPITRE 9.
COMPILATIONS SPARES
113
Rgle fondamentale :
Tab.
Fig.
9.3 Visibilit
La compilation spare des direntes parties d'un programme implique le respect de certaines rgles que nous appellerons et de fonctions). Comme il a t crit dans le chapitre 1, le compilateur ne lit le chier source qu'une seule fois, et du dbut jusqu' la n. Lorsqu'il rencontre l'utilisation d'une variable ou d'une fonction, il doit connatre son type et sa classe d'adresse. Par convention, dans le cas o une fonction n'est pas connue, le compilateur considre qu'elle retourne une valeur de type
appels postrieurs devront se conformer ce premier appel). La fonction peut tre dnie plus loin dans le chier. Si l'interface est conforme ce que le compilateur a devin, le compilateur n'met pas de message d'erreur et utilise l'adresse de la fonction pour les appels suivants, mais il ne peut pas modier ce qu'il a dj gnr. La liaison du premier appel avec la fonction est laisse l'diteur de liens. Nous allons nous servir de l'exemple de la gure 9.3 pour continuer expliquer la visibilit des noms. Pour cet exemple, les rgles de visibilit de noms que nous venons d'noncer nous permettent de dire : 1. la fonction f4 peut appeler les fonctions f4, f3, f2, et f1 ; 2. la fonction f3 peut appeler les fonctions f3, f2, et f1 ; 3. la fonction f2 peut appeler la fonction f2, et f1 ; c Christian Bac 1985-2003
114
9.3.
VISIBILIT
4. la fonction f1 ne peut que s'appeler elle-mme ; 5. les fonctions f1, f2, f3, et f4, peuvent appeler des fonctions inconnues, dans ce cas le compilateur utilise la rgle par dfaut et suppose que le rsultat de la fonction appele est un entier.
de type
long
l'intrieur de la fonction
f1()
masque
50
f1()
a =
modie la
a = 10
f2()
de type
float
f3()
f3()
et
prg1.c.
des autres modules du programme qui les auront dclares. fonctions dnies dans
a est dclare en tte du chier prg2.c ; elle peut donc tre utilise par toutes les prg2.c. Le compilateur fait la liaison avec cette dclaration lors de l'utilisation de la variable dans les fonctions f2() et f3(). Il demande l'diteur de liens de trouver la variable a. de mme, la variable b est dclare localement dans la fonction f3() et peut tre utilise
par cette fonction. Le compilateur fait les vrications grce aux informations fournies par la dclaration et demande l'diteur de liens de trouver la variable. c Christian Bac 1985-2003
CHAPITRE 9.
COMPILATIONS SPARES
115
Fig.
printf()
et
scanf())
le langage C utilise
void
116
Fig.
Fig.
prg2.c,
f1()
prg2.c,
prg1.c
le prototype
CHAPITRE 9.
COMPILATIONS SPARES
117
le type des arguments passs lors de l'appel. Lorsqu'on travaille avec des vieux chiers sources en langage C, la programmation doit donc tre trs soigne. L'utilitaire
lint, souvent prsent avec la chane de compilation, fait ce genre des vrications.
La normalisation du langage C a introduit de manire complte l'utilisation des prototypes de manire garantir une bonne prise en compte des prototypes.
extern
lateur demande l'diteur de liens de rsoudre les conits potentiels. Il ne peut bien sr n'y avoir qu'une seule initialisation qui transforme la dclaration candidate en dnition. Pour des questions de lisibilit, les compilateurs acceptent donc les dnitions candidates de variables, ils acceptent ces dnitions de manire multiple si le type est identique. Le compilateur ne fait la demande de rservation d'espace qu'une seule fois. Il considre les dnitions ultrieures comme des dclarations. Cette facilit permet au programmeur de mettre des dclarations de variables prs des endroits o elles sont manipules. L'exemple 9.2 montre l'utilisation de plusieurs dclarations candidates devenir une dnition d'une mme variable. Dans cet exemple les deux fonctions maninpulent la mme variable
a.
plusplus()
et
moinsmoins()
Nous recommandons : d'viter les dclarations candidates la dnition, de toujours associer la dnition avec une initialisation, d'utiliser le mot
extern
Le programme 9.3 reprend notre programme 9.2 en tant conforme ces recommandations.
} }
118
Fig.
defs.h contient les dclarations des variables globales et des fonctions qui peuvent prg1.c ; a
et
tre utilises dans plusieurs chiers sources participant au programme ; les variables qui peuvent tre utilises par plusieurs modules sont dans le module les fonctions utilisables sont dnie dans le module le module fonction fonction
prg2.c, demande l'inclusion du chier defs.h qui fournit la f3() lors de la compilation. Ceci permet l'utilisation de cette f2() sans ambigut.
f1() prg2.c ;
prg1.c
f3()
qui est
2 Ce
sont des dclarations et non des dnitions. En eet, les chiers d'inclusion sont associs plusieurs chiers
source et si ces chiers contiennent des dnitions, les variables risquent d'tre dnies plusieurs fois.
CHAPITRE 9.
COMPILATIONS SPARES
119
Fig.
static permet de masquer des noms de donnes ou de fonctions aux global static n'est visible que du module
qui la dclare. Elle n'est accessible qu'aux fonctions dnies aprs elle dans le mme chier. Ceci permet, entre autre, de manipuler des donnes qui ont le mme nom dans plusieurs chiers avec des dnitions direntes dans chacun d'entre-eux. Comme le montre la gure 9.8, une fonction peut aussi tre dclare
accessible aux fonctions des autres chiers constituant le programme. Une tentative de dclaration
extern
locales
120
Fig.
Le langage C donne la possibilit d'avoir des variables internes un bloc dont la dure de vie est la mme que celle des variables globales. Le prdicat
static
modie le lieu o cette variable est implante ; elle est, alors, mise avec les variables globales. Son nom reste invisible l'extrieur de la fonction. Le prdicat static peut tre utilis pour des structures ou des tableaux de grande taille internes une fonction. Ceci permet de minimiser le surcot caus par la cration et la destruction de l'espace mmoire pour stocker ces variables de grande taille l'entre et la sortie de la fonction. L'isolation de la variable est smantique, son nom n'tant pas connu du reste du programme. Cette isolation n'est pas totale en eet : si une fonction retourne un pointeur contenant l'adresse d'une variable peut tre utilis par le reste du programme. Le contrle statique, celui-ci d'accs la variable est vri variable
la compilation mais non l'excution. Une variable locale statique peut aussi tre modie par des eets de bord (par exemple un dbordement de tableau peut craser la statique locale que l'diteur de lien a plac aprs le tableau) ; la dure de vie d'une variable locale statique est la mme que celle des variables globales. A chaque appel, une fonction retrouve la valeur d'une variable locale statique qu'elle a modie lors des appels prcdents. Nous pouvons donc avoir une variable interne une fonction qui compte le nombre d'appels cette fonction. l'initialisation d'une variable statique interne une fonction non l'entre dans la fonction. Lorsque le programme de la gure 9.9 s'excute la variable entire successivement les valeurs : 1,2,3,4,5,6,7,8,9 et la variable valeurs : 1,11,21,31,41,51,61,71,81,91. est faite la compilation, et
http ://www.gnu.org/prep/standards.
CHAPITRE 9.
COMPILATIONS SPARES
121
sleep() ;
appel(), qui ralise la lecture de l'tage de la demande ; saisie(), qui ralise la lecture de l'tage atteindre ; une boucle dans la fonction main() qui controle la validit des saisies et termine le programme
a x2 + b x + c.
Le programme contient 4 fonctions : calcul du discriminant ; calcul de la racine double ; calcul des racines rlles ; calcul des racines complexes. le programme principal saisit les coecients le bon sous-programme.
a, b
et
c,
122
#include <stdio.h> /* PROGRAMME DE SIMULATION DE LA MARCHE D UN ASCENSEUR */ int appel (){ int etg; printf ("Appel ascenseur\n"); printf ("A quel etage etes-vous? de -3 a 10 fin : 11\n"); scanf ("%d", &etg); return etg; } int selection (){ int selec; printf ("Selection etage ? de -3 a 10\n"); scanf ("%d", &selec); return (selec); } int deplacement (int a, int asc){ /* si etage demande > etage d appel */ if(a > asc){ do{ printf ("Etage : %d\n", asc); sleep (2); } while(++asc < a); printf("Arrivee etage %d\n", asc); } /* si etage demande < etage d appel */ else{ do{ printf ("Etage : %d\n", asc); sleep (1); }while(--asc > a); printf("Arrivee etage %d\n", asc); } return asc; }
CHAPITRE 9.
COMPILATIONS SPARES
123
Programme 9.5
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
#include <stdio.h>
extern int appel (); extern int selection (); int deplacement (int, int); int main (int argc, char *argv[], char **envp) { int etg = 0, selec; /* boucle generale */ do{ /* boucle appel */ do selec = appel (); while(selec > 11 || selec < -3); if(selec != 11){ /* deplacement vers l etage d appel */ etg = deplacement (selec, etg); /* boucle de selection */ do selec = selection (); while(selec > 10 || selec < -3); /* deplacement vers l etage destination */ etg = deplacement (selec, etg); } } while(selec != 11); /* test fin */ printf("Arret ascenseur\n"); return 0; }
Donnes en entre
2 4 11
124
CHAPITRE 9.
COMPILATIONS SPARES
125
Programme 9.7
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
float dis (float, float, float); void rac2 (float, float); void complex (float, float); void racd (float);
int main (int argc, char *argv[], char **envp){ float a, b, c, r, r1; double rdis; float res; printf ("calcul des racines de ax2 + bx + c\n\n"); printf ("saisie des valeurs de a b et c"); scanf ("%f", &a); scanf ("%f", &b); scanf ("%f", &c); if (a == 0){ printf (" Equation du premier degre \n"); printf (" La solution est x = %f \n", -c / b); return 0; } r = -b / (2 * a); res = dis (a, b, c); switch (res < 0 ? -1 : (res > 0 ? 1 : 0)){ case 1: rdis = sqrt (res); r1 = rdis / (2 * a); rac2 (r, r1); break; case -1: rdis = sqrt (-res); r1 = rdis / (2 * a); complex (r, r1); break; case 0: racd (r); break; } return 0;
Donnes en entre
2 -4 2
126
CHAPITRE 9.
COMPILATIONS SPARES
127
Programme 9.9
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
int main (int argc, char *argv[], char **envp){ float a, b, c, r, r1; double rdis; float res; printf ("calcul des racines de ax2 + bx + c\n\n"); printf ("saisie des valeurs de a b et c \n"); scanf ("%f %f %f", &a, &b, &c); if(a == 0){ printf (" Equation du premier degre \n"); printf (" La solution est x = %f \n", -c / b); return 0; } r = -b / (2 * a); res = dis (a, b, c); switch (res < 0 ? -1 : (res > 0 ? 1 : 0)){ case 1: rdis = sqrt (res); r1 = rdis / (2 * a); rac2 (r, r1); break; case -1: rdis = sqrt (-res); r1 = rdis / (2 * a); complex (r, r1); break; case 0: racd (r); break; } return 0; }
Donnes en entre
2 -4 2
128
Chapitre 10
Pointeurs et tableaux
Ce chapitre est consacr aux tableaux et leur manipulation travers l'utilisation de pointeurs. Cette utilisation des pointeurs pour accder aux contenus des tableaux est une des dicults du langage pour les dbutants, elle s'avre cependant l'une des techniques les plus utilises par les programmeurs expriments.
Comme le montrent les exemples du programme 10.1, il est possible de ne pas spcier la taille du tableau ou (exclusif ) de ne pas initialiser tous les lments du tableau. Dans ce programme,
tb1
tb2
Fig.
130
10.2.
Fig.
10 entiers dont les 6 premiers sont initialiss. Depuis la normalisation du langage, l'initialisation des premiers lments d'un tableau provoque l'initialisation de l'ensemble des lments du tableau y compris pour les tableaux locaux. Les lments pour lesquels des valeurs ne sont pas prcises sont initialiss avec la valeur 0 (ensemble des octets zro quelle que soit la taille des lments).
Les noms de tableaux tant des constantes, il n'est pas possible de les aecter
1.
tb1
l'exemple de la gure 10.2 en le compltant par les adresses de chaque lment. Ces adresses sont
tab pris en exemple dans la gure 10.3, les &tab[0] et &tab[9]. Pour une question de test
&tab[10]
mais rien ne garantit que l'expression ne provoque pas une accde. Le compilateur garanti qu'il calcule
erreur si le rang dpasse la taille plus un. La zone mmoire correspondante au rang du tableau plus un ne doit cependant pas tre
1 tb1=
1= .
est une hrsie qui mrite l'exclusion de la communaut des utilisateurs du langage C au mme titre que
CHAPITRE 10.
POINTEURS ET TABLEAUX
131
Fig.
Fig.
correctement l'adresse mais il ne garantit pas que le fait d'essayer d'accder la zone mmoire correspondante soit possible. selon ces conditions, l'addition d'un entier une adresse retourne une adresse qui est celle ime du n objet contenu dans le tableau partir de l'adresse initiale. Dans ces conditions, tab + n est l'adresse du nime entier partir du dbut du tableau. Dans notre exemple variable partir de l'adresse (*) ne peut cependant s'appliquer que pour et 9. Ainsi, Ainsi, de tableau de dix lments,
L'oprateur d'accs la
*(tab +n)
valant entre 0
compris entre 0 et 9.
l'addition ou la soustraction d'un entier est possible pour toute adresse dans un tableau.
&tab[3] + 2
&tab[1].
&tab[5].
De mme,
&tab[3] - 2
donne
il est aussi possible de raliser une soustraction entre les tenant un mme tableau.
correspond au nombre d'objets entre les deux adresses. Ainsi, ner la valeur 2 exprime dans le type la valeur -2 exprime dans le type
ptrdiff_t. ptrdiff_t.
De mme,
int tab[8][5];.
132
10.4.
POINTEURS ET TABLEAUX
Instruction
Interprtation px reoit l'adresse du premier lment du tableau. y reoit la valeur de la variable pointe par px px est incrment de la taille de l'objet point (4 octets). Il contient &x[1]. px reoit l'adresse du ime objet partir de l'objet courant.
Tab.
pointeur
est une variable destine contenir une adresse mmoire. Il est reconnu syn-
d'objet. Ce type est celui des objets qui sont manipuls grce au pointeur. L'objet peut tre une variable ou une fonction. Contrairement ce que beaucoup d'apprentis esprent, la dclaration d'un pointeur n'implique pas la dclaration implicite d'une variable associe et l'aectation de l'adresse de la variable au pointeur. Il faut donc dclarer une variable du type correspondant et initialiser le pointeur avec l'adresse de cette variable. Par convention, l'adresse 0 est invalide et si le programme cherche l'accder, il obtient une erreur d'excution du type bus-error sur UNIX. Ce comportement implique que l'utilisation de pointeurs globaux sans initialisation mne ce rsultat, car les pointeurs (comme les autres variables) dclars en variables globales sont initialiss 0. Les pointeurs dclars en variable locale (comme toutes les variables locales) ont des valeurs initiales dpendantes du contenu de la pile cet instant, qui dpend de l'excution prcdent du programme mais correspond en gnral n'importe quoi. Le comportement du programme qui utilise un pointeur local sans l'avoir aect convenablement peut donner des comportements tels que violation de l'espace mmoire, mais parfois le pointeur reoit une adresse valide et le programme se droule sans erreurs agrante mais en donnant des rsultats faux (ce que d'aucuns appellent un eet de bord indsirable, ce que d'autres appellent un bug dicile reproduire). Voici deux exemples de dnition de pointeurs :
int *ptint; pointeur sur un entier char *ptchar; pointeur sur un caractre.
Le compilateur C vrie le type des adresses qui sont aectes un pointeur. Le type du pointeur conditionne les oprations arithmtiques sur ce pointeur. Les oprations possibles sur un pointeur sont les suivantes : aectation d'une adresse au pointeur ; utilisation du pointeur pour accder l'objet dont il contient l'adresse ; addition d'un entier (n) un pointeur ; la nouvelle adresse est celle du l'adresse initiale ; soustraction de deux pointeurs du mme type. Le calcul est ralis dans les mmes conditions que la dirence entre Le rsultat de type rsultat est indni. Le tableau 10.1 est un exemple de manipulations en relation avec les pointeurs et les tableaux en utilisant les variables : deux adresses de variables contenues dans un mme tableau. La n'est valide que si les adresses contenues dans les deux soustraction calcule le nombre de variables entre les adresses contenues dans les pointeurs.
ne
objet partir de
ptrdiff_t
L'addition dcrite dans la dernire ligne du tableau 10.1 se traduit par les conversions suivantes :
CHAPITRE 10.
POINTEURS ET TABLEAUX
133
Instruction
Interprtation pt1 reoit l'adresse du premier lment du tableau. pt2 reoit l'adresse du dixime lment du tableau. i reoit la dirence des deux pointeurs pt1 et pt2. soit le nombre d'objets entre pt2 et pt1. i contiendra 10 la n de cette instruction.
Tab.
Le tableau 10.2 est un exemple de soustraction partir des dnitions de variables suivantes :
Par convention, le nom d'une variable utilis dans une partie droite d'expression donne le contenu de cette variable dans le cas d'une variable simple. Mais un nom de tableau donne l'adresse du tableau qui est l'adresse du premier lment du tableau. Nous faisons les constatations suivantes : un tableau est une un pointeur est une les variables :
Ceci nous amne regarder l'utilisation de pointeurs pour manipuler des tableaux, en prenant
long i, tab[10], *pti ; tab est l'adresse du tableau (adresse du premier lment du tableau &tab[0] ; pti = tab ; initialise le pointeur pti avec l'adresse du dbut de tableau. Le & ne sert rien dans le cas d'un tableau. pti = &tab est inutile et d'ailleurs non reconnu ou ignor par
certains compilateurs ;
&tab[1] est l'adresse du 2e lment du tableau. pti = &tab[1] est quivalent : pti = tab ; o pti pointe sur le 1er lment du tableau. pti += 1 ; fait avancer, le pointeur d'une case ce qui fait
2me lment du tableau. De mme,
+ i).
*(pti+i)
La gure 10.5 est un exemple dans lequel sont dcrites les direntes faons d'accder au lments d'u tableau
type *nom[taille] ;
argv et envp de la fonction main() que nous avons eu l'occasion d'aborder dans la section 8.7 et que nous
contiennent les adresses des lments du tableau de variables. C'est le cas des arguments avons reprsents dans la gure 8.5. La gure 10.6 est un exemple d'utilisation de tableau de pointeurs partir des dnitions de variables suivantes :
Le premier cas d'utilisation d'un tel tableau est celui o les lments du tableau de pointeurs
134
Fig.
Fig.
CHAPITRE 10.
POINTEURS ET TABLEAUX
135
Fig.
(*nom)[taille] ;
type
La gure 10.7 dcrit les direntes faons d'accder aux variables d'un tableau de six fois cinq entiers (certains diraient un tableau de 6 lignes et 5 colonnes) partir d'un pointeur qui peut contenir une adresse de sous-tableau (de cinq entiers).
136
La sparation entre nombres pairs et impairs est faite dans une fonction qui reoit en arguments les adresses des trois tableaux (adresse de l'lment de rang 0 du tableau), cette fonction termine les tableaux pairs et impairs par des zros. Le tri de chaque tableau est realis par une fonction permet de vrier la validit de l'ensemble. Le programme doit tre compos d'un chier source qui contient les fonctions etd'un autre qui contient la fonction
tri(int *)
tri simple, un exemple d'algorithme est donn la n de ce texte. La rcriture des tableaux tris
main()
compilateur entre les deux chiers. Le fait de mettre des zros en n de tableau peut vous suggrer de manipuler ces tableaux avec des pointeurs. Le programme 10.3 est un exemple d'algorithme de tri d'un tableau termin par un zro.
CHAPITRE 10.
POINTEURS ET TABLEAUX
137
Programme 10.2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
#include <stdio.h>
int main (int argc, char *argv[]) { int tab[6][5]; int (*pt)[5]= tab; int i,j; for(i=0;i<6;i++) for(j=0;j<5;j++) tab[i][j]= i*10+j; for(i=2;i<6;i++) for(j=3;j<5;j++){ printf("tab[%d][%d] = %d\t",i,j,tab[i][j]); printf("%d\t",*(tab[i]+j)); printf("%d\t",*(*(tab+i)+j)); printf("%d\t",*(*(pt+i)+j)); printf("%d\t",*(pt[i]+j)); printf("%d\n",pt[i][j]); } return 0;
138
extern int saisie(int []); /* fonction de saisie de tableau * retourne le nombre d'entiers saisis */ extern void tri(int []); /* fonction de tri de tableau pointe */ extern void imptab(int [],int); /* fonction d'impression du tableau */ extern int separ(int [],int [],int []); /*separation pairs/impairs */
CHAPITRE 10.
POINTEURS ET TABLEAUX
139
140
Programme 10.6
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
main #include <stdio.h> #include "c10c01a.h" /* programme principal realisant les operations suivantes : * - saisie du tableau * - separation des nombres pairs et impairs * - appel de la fonction de tri * - appel de la fonction impression. */ int tab[100], imp[100], pair[100]; int main (int argc, char *argv[], char **envp){ register int count; /* definition de 3 pointeurs */ /* saisie du tableau a manipuler */ count = saisie (tab); printf (" Vous avez saisi %d nombres dans le tableau\n", count); /* separation des pairs et des impairs en deux tableaux */ count = separ (tab, pair, imp); printf (" Nous avons spar %d nombres dans le tableau\n", count); tri (tab); /* tri et impression */ imptab (tab, 0); tri (imp); /* tri et impression */ imptab (imp, 1); tri (pair); /* tri et impression */ imptab (pair, 2); return 0; }
Donnes en entre
1 -2 4 7 -6 29 123 -345 -12 3 0
CHAPITRE 10.
POINTEURS ET TABLEAUX
141
1 void 2 tri (int ti[]){ /* fonction de tri de tableau pointe par ptint */ 3 register int tamp, *ptrj, *ptint = ti; 4 while(*ptint){ 5 ptrj = ptint + 1; 6 while(*ptrj){ 7 if(*ptrj < *ptint){ 8 tamp = *ptint; 9 *ptint = *ptrj; 10 *ptrj = tamp; 11 } 12 ptrj++; 13 } 14 ptint++; 15 } 16 }
142
Chapitre 11
Structures
Une structure est une variable compose de plusieurs champs qui sert reprsenter un objet rel ou un concept. Par exemple une voiture peut tre reprsente par les renseignements suivants : la marque, la couleur, l'anne, . . .
11.1 Dnition
Le langage C permet de dnir des modles de structures comme les autres langages volus. Cela se fait selon la dnition donne par l'encart suivant.
struct
nom_de_structure type1 nom_champ1 ; type2 nom_champ2 ; type3 nom_champ3 ; type4 nom_champ4 ; typeN nom_champ_N ; variables ;
...
Une dnition de ce type sert dnir un modle de structure associ un nom de modle, qui est optionnel, et dnir des variables construites partir de ce modle (cette dnition est optionnelle aussi). Comme le montre l'exemple 11.1 dans les lignes 2 4, il est possible de ne pas dclarer de
variable la dnition de la structure, dans ce cas, le modle de structure doit tre associ un nom de manire pouvoir utiliser celui-ci pour dnir des variables ultrieurement. La dnition d'une structure ne rserve pas d'espace mmoire. Il faut dnir les correspondant ce modle de structure (ligne 6). Il est aussi possible de ne pas associer un nom de modle la dnition de la structure. Les objets de ce type devront tre dclars immdiatement (lignes 8 11). Ce modle de structure ne peut pas tre rfrenc par la suite, puisqu'il n'a pas de nom. Il est dit anonyme. c Christian Bac 1985-2003
variables
144
11.2.
UTILISATION
Objet
Pointeur
Tab.
11.2 Utilisation
Les structures peuvent tre manipules champ par champ ou dans leur ensemble.
pointeur
nom_de_variable.nom_du_champ.
ture, il faut remplacer le point par un moins suivi d'un suprieur (qui symbolise une che) :
nom_de_variable->nom_du_champ.
le montre le tableau 11.1.
Une fois ces dnitions ralises, nous pouvons utiliser les variables
obdate
et
ptdate
comme
En prenant les dnitions de donnes dans le programme 11.1 dans les lignes 2 6, le tableau 11.1, donne les direntes possibilits d'aectation pour chaque champ. Nous remarquerons l'quivalence entre :
(*ptdate).jour
et
ptdate->jour
Pour le compilateur, l'accs un champ d'une structure consiste faire un calcul de dplacement par rapport au dbut de la structure puis accder une variable cette adresse.
En prenant les dnitions de variables et de fonctions du programme 11.2, les oprations suivantes sont possibles sur les structures : c Christian Bac 1985-2003
CHAPITRE 11.
STRUCTURES
145
obdate = obdate2 ; retour d'une structure par une fonction comme obdate = newdate() ; passage en argument d'une structure une fonction. resul = checkdate(obdate2).
Note sur les pointeurs de structures : nous avons vu dans le chapitre prcdent sur l'aritmthique des adresses que l'incrmentation d'un pointeur le faisait passer sur l'lment suivant lorsque le pointeur contient une adresse qui correspond un tableau d'lments correspondants au type de variable associ au pointeur. Il en est de mme pour un pointeur qui contient une adresse de structure. Un pointeur incrment permet l'accs la structure suivante lorsque les structures sont dans un tableau. Reprenons le programme 11.3 dans lequel nous avons dni un tableau de structures et un pointeur sur la structure noeud.
ptnoeud
tab[1].
: longueur
chaque
lment de la structure. Les structures de champs de bits sont dclares selon le modle de l'encart
146
11.5.
struct nom_de_structure unsigned nom_champ1 unsigned nom_champ2 unsigned nom_champ3 unsigned nom_champ4
...
: : : :
unsigned nom_champ_N
: longueurN ; objets ;
Il est recommand de n'utiliser que des lments de type unsigned. La norme X3J11 n'impose pas que d'autres types soient supports. Un champ sans nom, avec simplement la taille, est un champ de remplissage pour cadrer sur des frontires de mot machine. Le programme 11.4 donne quelques exemples de dnitions de modles de structures correspondant des champs de bits :
struct flottant { unsigned exposant:7; unsigned signe:1; unsigned mantisse:24; }; struct mixte { unsigned exposant:7; unsigned signe:1; unsigned mantisse:24; unsigned comp:7; unsigned : 9; };
CHAPITRE 11.
STRUCTURES
147
Programme 11.5
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
#include <stdio.h> struct date /* declaration du modele de structure date */ { int jour; int mois; int annee; };
int main (int argc, char *argv[], char **envp) { struct date dat, *ptdate = &dat; /* saisie de la date */ printf (" Entrez une date ( jj mm aaaa ) :"); scanf ("%d %d %d", &dat.jour, &dat.mois, &dat.annee); /* impression de la date */ printf (" La date est : %d\t%d\t%d\n", dat.jour, dat.mois, dat.annee); /* impression de la date avec le pointeur */ printf (" La date est : %d\t%d\t%d\n", ptdate->jour, ptdate->mois, ptdate->annee); return 0; }
Donnes en entre
01 04 2003
11.5.2 Exercice 2
Dnir un tableau de structures date. Dnir un pointeur sur ce tableau. Initialiser ce tableau. Imprimer le contenu du tableau.
148
11.5.
Programme 11.6
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
#include <stdio.h> /* declaration du modele de structure date */ struct date{ int jour, mois, annee;}; int main (int argc, char *argv[], char **envp) { struct date dat[5], *ptdate=dat; int i = 0; /* remplissage du tableau */ printf ("Entrez 5 dates au format ( jj mm aaaa )\n"); while (i < 5){ scanf ("%d %d %d", &dat[i].jour, &dat[i].mois, &dat[i].annee); i++; } /* impression du tableau */ for (i = 0; i < 5; i++, ptdate++) { /* sans pointeur */ printf (" Date numero %d : %d\t%d\t%d\n", i + 1, dat[i].jour, dat[i].mois, dat[i].annee); /* avec pointeur */ printf (" Date numero %d : %d\t%d\t%d\n", i + 1, ptdate->jour, ptdate->mois, ptdate->annee); } return 0; }
Donnes en entre
01 03 09 02 11 04 05 08 09 11 2003 2003 2003 2003 2003
Chapitre 12
Unions
Les
unions
permettent l'utilisation d'un mme espace mmoire par des donnes de types
12.1 Dnition
La dnition d'une union respecte une syntaxe proche de celle d'une structure et qui est donne dans l'encart suivant.
union
nom_de_union type1 nom_champ1 ; type2 nom_champ2 ; type3 nom_champ3 ; type4 nom_champ4 ; typeN nom_champ_N ; variables ;
z1
et
...
z2
peut contenir soit un entier, soit un entier long, soit un nombre avec point dcimal, soit un nombre
Lorsque l'on dnit une variable correspondant un type union, le compilateur rserve l'espace mmoire ncessaire pour stocker le plus grand des champs appartenant l'union. Dans notre exemple, le compilateur rserve l'espace mmoire ncessaire pour stocker un des variables
z1
et
z2.
150
12.2.
1 2 3 4 5 6 7 8 9 10 11 12 13
#include <stdio.h> int main (int argc, char *argv[]) { union etiq { short int ent; unsigned short int ent1; } lmot = { -1, }; printf ("Valeur de lmot.ent : %hd\n", lmot.ent); printf ("Valeur de lmot.ent1 : %hd\n", lmot.ent1); return 0; }
lmot peut tre vue sans signe -1 est aecte lmot.ent. Cette valeur peut tre considre comme lmot.ent1.
Ainsi le programme 12.1 donne le rsultat suivant :
plus grande que zro (puisque gale USHRT_MAX ou 65535U) ou plus petite suivant qu'elle
lmot.ent
ou
CHAPITRE 12.
UNIONS
151
lire une valeur correspondante au clavier ; acher l'adresse du membre ; puis acher son contenu.
Programme 12.3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
#include <stdio.h> union test { /* definition du modele de l'union */ char un_char; int un_int; float un_float; } ; int main (int argc, char *argv[], char **envp) { union test un_test; /* saisie du caractere et impression */ printf(" Entrer un caractere : "); scanf("%c",&un_test.un_char); printf(" caractere : %c \t adresse : %x \n", un_test.un_char, &un_test.un_char); /* saisie de l'entier et impression */ printf(" Entrer un entier : "); scanf("%d",&un_test.un_int); printf(" entier : %d \t adresse : %x \n", un_test.un_int, &un_test.un_int); /* saisie du flottant et impression */ printf(" Entrer un flottant : "); scanf("%f",&un_test.un_float); printf(" flottant : %f \t adresse : %x \n", un_test.un_float, &un_test.un_float); return 0; }
Donnes en entre
c 22 3.14159
12.3.2 Exercice 2
Denir un champ de bits compos de : 2 bits, 7 bits pour un premier caractre, 7 bits pour un deuxime caractre, 16 bits pour un entier. Initialiser ce champ de bits. Imprimer ce champ en hexadcimal. c Christian Bac 1985-2003
152
12.3.
Programme 12.4
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
#include <stdio.h> struct champ_bit { /* definition du champ de bits */ unsigned left : 2; unsigned car1 : 7; unsigned car2 : 7; unsigned nbre : 16; } champ = { 01, 'a', 'Z', 4532 }; /* initialisation */ int main (int argc, char *argv[], char **envp) { /* impression du champ globalement */ printf(" Valeur du champ : %x\n", champ); /* impression de chaque partie du champ */ printf(" Caractere 1 : %c\n", champ.car1); printf(" Caractere 1 : %x\n", champ.car1); printf(" Caractere 2 : %c\n", champ.car2); printf(" Caractere 2 : %x\n", champ.car2); printf(" Nombre : %d\n", champ.nbre); printf(" Nombre : %x\n", champ.nbre); printf(" Bits de gauche : %x\n", champ.left); return 0; }
Chapitre 13
numrations
Les numrations servent orir des possibilits de gestion de constantes numres dans le langage C. Ces numrations sont un apport de la norme ANSI et permettent d'exprimer des valeurs constantes de type entier en associant ces valeurs des noms. Les numrations orent une alternative l'utilisation du pr-processeur dans la description de constantes (voir chap. 15).
13.1 Dnition
La dnition d'une numration respecte la syntaxe donne dans l'encart suivant.
enum
numrateurN variables ;
Les dirents numrateurs sont des constantes symboliques. Les valeurs associes aux numrateurs sont, par dfaut, dnies de la manire suivante : la premire constante est associe la valeur
0,
Il est possible de xer une valeur chaque numrateur en faisant suivre l'numrateur du signe gal et de la valeur entire exprime par une constante ; si l'numrateur suivant n'est pas associ une valeur, la progression de 1 reprend la valeur courante. Nous baserons nos exemples sur le programme 13.1. Les lignes 2 et 3 de cet exemple d'numration dnissent les constantes symboliques : 1. 2. 3.
rvb
154
13.2.
UTILISATION
Les lignes 5 7 xent les valeurs de certains numrateurs eet dnissent les constantes symboliques suivantes : 1. 2. 3.
+ 1) ;
arcenciel
autrescouleurs.
Les lignes 8 16 montrent une utilisation des numrations pour direncier les types de chiers dans les inodes d'un systme de chiers de type UNIX.
13.2 Utilisation
Les numrateurs peuvent tre utiliss dans des expressions du langage la mme place que des constantes du type entier. Ainsi, ils peuvent se situer dans des calculs, pour aecter des variables et pour raliser des tests. c Christian Bac 1985-2003
CHAPITRE 13.
NUMRATIONS
155
156
13.3.
Chapitre 14
typedef de dnir un type nouveau qui est un type sytypedef comme premier mot d'une ligne de dnitions typedef.
provoque le fait que les noms qui seraient des noms de variables sur la mme ligne sans ce mot rserv deviennent des noms de types synonymes. Chaque nom de type synonyme correspond au type qu'aurait eu la variable sur la mme ligne sans Ainsi la dnition suivante :
Une fois cette dnition ralise, nous pouvons utiliser ce nouveau type pour dnir des variables et nous pouvons mlanger les variables de ce type avec des variables entires pour raliser des expressions.
tt
tab
int.
La
est un tableau de 10 entiers. est trs semblable une directive du pr-processeur (chap. 15) mais il s'adresse au
typedef
compilateur.
Attention : typedef ne rserve pas d'espace mmoire. Les noms sont des types ; ils sont donc
inaccessibles comme variables. c Christian Bac 1985-2003
158
L'utilisation de
typedef
programmeurs d'crire du code plus lisible. Il est aussi possible de dnir un type quivalent une structure :
struct.
date obdate, *ptdate ; obdate est un objet correspondant au type date qui est synonyme d'une structure anonyme jour, mois et annee. La variable ptdate est un pointeur qui peut contenir l'adresse d'une variable du type date mais qui dans l'exemple n'est pas initialis.
Ainsi contenant trois variables entires appeles
()
reprsentant le regroupement est de priorit la plus leve et une associativit de gauche correspondant l'identication d'une fonction et
droite ;
() *
[]
tableau sont de priorit gale et immdiatement infrieure au regroupement avec une associativit de gauche droite ; est de priorit la plus basse parmi nos quatre oprateurs avec une associativit de droite gauche. Le tableau 14.1 donne un ensemble de dnitions de variables et dcrit le type de chaque variable.
CHAPITRE 14.
159
Dclaration
Objet tableau de 10 pointeurs d'entier tableau de 10 pointeurs sur des pointeurs d'entier pointeur sur un tableau de 10 entiers pointeur sur un tableau de 10 pointeurs sur un entier fonction qui retourne un pointeur sur un entier pointeur sur une fonction qui retourne un entier Modle d'union de deux structures de type t1 et t2
int *tab[10] ; int **ta[10] ; int (*tb)[10] ; int *(*tb)[10] ; int *fp() ; int (*fp)() ; union u { struct t1 u1 ; struct t2 u2 ; } int tt()[10] ; int tt[10]() ; int (*t1[10])() ; int *(*t2[10])() ; int t3[] ; int *t4[] ; int t5[][] ; int **t7 ; float (*pf[5])()= {sin,cos}
dnition illgale fonction qui retourne un tableau. dnition illgale tableau de fonctions Tableau de 10 adresses de fonctions qui retournent un entier Tableau de 10 adresses de fonctions qui retournent un pointeur d'entier tableau de taille inconnue la dnition de l'objet est obligatoirement externe tableau de pointeurs externe dclaration illgale il faut xer la taille de la 2 dimension Pointeur sur un pointeur d'entier (Souvent utilis pour dcrire un tableau de pointeurs d'entier) Tableau de pointeurs sur des fonctions qui retournent des initialises par les adresses de
float
et
cos
sin
Tab.
160
Le premier exemple dnit un tableau de 10 pointeurs qui peuvent recevoir des adresses de fonctions qui retournent un entier. Le second exemple dnit un tableau de 10 pointeurs de fonctions qui peuvent recevoir des adresses de fonctions qui retournent un pointeur sur un entier. En langage C, le nom d'une fonction est considr comme une adresse et l'appel d'une fonction consiste d-rfrencer son adresse pour provoquer un saut du pointeur de programme courant cette adresse.
Programme 14.1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
struct date /* definition du modele de structure date */ { int jour, mois, annee; }; /* definition des types synonymes typedef struct date tdate; typedef tdate * ptdate; */
#include <stdio.h> int main (int argc, char *argv[], char **envp) { tdate dat; ptdate ptd=&dat; /* saisie de la date */ printf (" Entrez une date ( jj mm aaaa ) :"); scanf ("%d %d %d", &dat.jour, &dat.mois, &dat.annee); /* impression de la date */ printf (" La date est : %d\t%d\t%d\n", dat.jour, dat.mois, dat.annee); /* impression de la date avec le pointeur */ printf (" La date est : %d\t%d\t%d\n", ptd->jour, ptd->mois, ptd->annee); return 0;
Donnes en entre
01 04 2003
CHAPITRE 14.
161
14.4.2 Exercice 2
Dnir un type correspondant la dnition suivante : Une union pouvant contenir : un tableau de 10 pointeurs sur des entiers, un tableau de 10 pointeurs sur des ottants, un tableau de 10 entiers, un tableau de 10 ottants.
14.4.3 Exercice 3
Cet exercice a pour but de manipuler le remplissage d'un tableau de structures date et de permettre son dition, partir d'un menu en utilisant l'appel de fonction travers des pointeurs. Pour cela il faut crire trois fonctions : une fonction de saisie, une fonction de consultation, une fonction de permettant de sortir de l'application. La fonction
main()
contient une boucle innie donnant un menu qui ore le choix entre saisie
162
Programme 14.2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
/* declaration des differents types de tableaux */ typedef int int_10[10]; typedef int *ptint_10[10]; typedef float float_10[10]; typedef float *ptfloat_10[10]; /* definition des differents objets pouvant etre contenus dans l'union */ union u1 { int_10 o1; ptint_10 o2; float_10 o3; ptfloat_10 o4; }; /* definition du type union */ typedef union u1 utab; /* definition d'un objet de ce type */ utab my_union ; #include <stdio.h> int main (int argc, char *argv[], char **envp){ int i; /* initialisation des entiers avec leur rang */ for(i=0; i < 5;i++ ) my_union.o1[i] = i; /* impression du tableau */ for(i=0; i < 5;i++ ) printf("my_union.o1[%d] = %d \n", i, my_union.o1[i]); /* initialisation des pointeurs avec leurs propres adresses */ for(i=0; i < 5;i++ ) my_union.o2[i] = & my_union.o1[i]; /* impression du tableau de pointeurs */ for(i=0; i < 5;i++ ) printf("my_union.o2[%d] = %x \n", i, my_union.o2[i]); return 0; }
CHAPITRE 14.
163
void saisie(struct date *); void edition(struct date *); void sortie();
void saisie(struct date * ptd) { int i; /* rang dans le tableau de dates */ printf(" Entrez le rang dans le tableau date :"); scanf("%d", &i); ptd += i; /* saisie de la date */ printf(" Entrez une date ( jj mm aaaa ) :"); scanf("%d%d%d", &ptd->jour, &ptd->mois, &ptd->annee); } void edition(struct date * ptd) { int i; /* rang dans le tableau de dates */ printf("Entrez le rang dans le tableau date :"); scanf("%d", &i); ptd += i; /* edition de la date */ printf("Date dans le tableau :"); printf("%d %d %d\n", ptd->jour, ptd->mois, ptd->annee); } void sortie() { exit(0); }
164
Programme 14.5
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
static struct date dat[10]; int main (int argc, char *argv[], char **envp) { int i; static void (*f[3])() = { saisie, edition, sortie }; for(;;) { printf("\tsaisie\t1\n"); printf("\tedition\t2\n"); printf("\tarret\t3\n"); printf("Choix :"); scanf("%d",&i); f[i-1](dat); /* on peut aussi ecrire : (*f[i-1])(dat); */ }
Donnes en entre
1 1 1 4 2003 2 1 1 2 12 08 1998 3
Chapitre 15
Prprocesseur
Comme nous l'avons dit dans la section 1.4, le pr-processeur ou pr-compilateur (alias C Pre Processor ou CPP) traite le chier source avant le compilateur. Il ne manipule que des chanes de caractres. Il retire les parties commentaires (entre /* et */). Il prend en compte les lignes commenant par un # pour crer le code que le compilateur analysera. Ses possibilits sont de 4 ordres : inclusion de chier en utilisant la directive dnition de variables de prcompilation :
#include
15.1 Commentaires
Les commentaires sont destins faciliter la comprhension du source lors de la relecture. Ils ne sont d'aucune utilit au compilateur, et il est naturel qu'ils n'apparaissent pas dans le source qui lui est destin. Le pr-processeur retire les caractres compris entre /* et */. Il ne gre pas les imbrications de commentaires. La mise en commentaire d'une section source peut alors crer des erreurs de compilation comme le montre le programme 15.2. Le tableau 15.1 montre le retrait des commentaires dans un chier source avant le passage vers le compilateur. La gure15.2 montre le retrait des commentaires dans un chier source aprs l'introduction du nouveau commentaire ce qui provoque une erreur de syntaxe sur la ligne voit
*/ a = 2 ;.
a = 2 ; car le compilateur
166
15.2.
INCLUSION DE FICHIERS
Programme 15.1
1 2 3 4 5 6 7 8 9 10 11 12
int main (int argc, char *argv[]) { int a,b,c; a=1; b=1; c=1; /* ajout a+b a c */ c += a +b ; a=2; return 0; }
#include nom_de_fichier
Par convention, les chiers inclure ont des noms termins par .h pour signier header. Il existe trois faons de nommer un chier inclure. Ces faons dterminent l'endroit o le pr-processeur cherche le chier. 1. par son chemin absolu, ce qui se traduit dans un systme de type UNIX par le fait que le nom de chemin correspondant au chier commence par / ;
#include "/users/chris/essai/header.h" #include < /users/chris/essai/header.h > #include "header.h" #include "h/mem.h" #include "../h/uucp.h"
2. partir du catalogue courant, si le nom de chier est entour par des guillemets ;
3. partir d'un catalogue prdni correspondant l'installation du compilateur, si le nom de chier est entour par un infrieur et un suprieur. Ce catalogue est de manire standard
/usr/include dans les systmes #include < stdio.h > #include < sys/dir.h >
UNIX.
Il est possible de demander au pr-processeur d'ajouter d'autres catalogues sa recherche, en utilisant une option de compilation l'appel de l'en-chaneur de passes. Cette option est dans un c Christian Bac 1985-2003
CHAPITRE 15.
PRPROCESSEUR
167
Programme 15.2
1 2 3 4 5 6 7 8 9 10 11 12 13 14
int main (int argc, char *argv[]) { int a,b,c; a=1; b=1; /* Ceci ne nous interesse plus c=1; /* ajout a+b a c */ c += a +b ; */ a=2; return 0; }
c += a +b ; */ a=2; return 0;
manire spcier plusieurs catalogues de recherche. Lorsque le chier inclure est spci entre guillemets, le pr-processeur cherche le chier : 1. dans le catalogue courant, 2. puis dans les catalogues spcis par les options
-I.
Si le nom du chier include est entre < et >, le pr-processeur cherche le chier : 1. dans les catalogues spcis par les options
-I,
2. puis dans le catalogue par dfaut du compilateur. Les chiers inclus sont traits par le pr-processeur. Ils peuvent contenir d'autres inclusions de chiers. c Christian Bac 1985-2003
168
Tab.
#define nom_de_la_variable
est suivi d'une parenthse ouvrante, de la liste des arguments, d'une parenthse fermante, et de la
Il faut faire attention l'ordre d'valuation pour des macro-expressions complexes, et la technique la plus simple est l'utilisation intensive du parenthsage en encadrant les noms des pseudoc Christian Bac 1985-2003
CHAPITRE 15.
PRPROCESSEUR
169
Programme 15.3
1 2 3 4 5 6 7 8 9 10 11 12
int main (int argc, char *argv[]) { int i,t[LG]; for (i=0; i<LG; i++){ printf("Valeur de PI \%d",t[i] = PI); } return 0; }
int main (int argc, char *argv[]) { int i,t[20]; for (i=0; i<20; i++){ printf("Valeur de PI \%d",t[i] = 3.14159); } return 0; }
variables par des parenthses mais aussi en encadrant la macro-expression elle-mme. Comme le montre l'exemple 15.4, le parenthsage garantit que l'expression rsultante est correctement interprte, la ligne 16 de l'exemple montre que l'expression
m(a+b)
170
15.7.
SLECTION DE CODE
directive
en utilisant l'option
nom
par la valeur
Il existe des variables de prcompilation qui sont prdnies. Elles sont associes au type de la machine, au compilateur et l'environnement. Elles sont la plupart du temps d'une part xes par la compilation de l'enchaneur de passe lui-mme ou par la dtection de de l'environnement par ce dernier. Par exemple, sur un PC au 05/04/2003 les variables suivantes sont prdnies par l'enchaneur de passes :
dumpspecs
avec
gcc
ou
cpp
__STDC__.
Il est possible d'eacer ces dnitions au niveau de l'appel l'enchaneur de passes, en utilisant l'option
-Unom.
Ceci ne peut pas inhiber les dnitions qui apparaissent dans le code par des
#define.
Toute condition de slection de code commence par un avec ventuellement une partie
#else.
#if[n[def]], et se termine par #endif, #if[n[def]] et le #else est pass #else et le #endif. S'il n'y a pas
#else
CHAPITRE 15.
PRPROCESSEUR
171
#if
C. Cette expression
ne peut mettre en jeu que des constantes et des variables de prcompilation. Le programme 15.5 quelques exemples d'utilisaiton de
#if.
En plus des expressions du langage C, le prprocesseur permet de tester l'existence d'une variable en utilisant le mot
defined
#define DEBUG #if defined DEBUG code passe #endif #if defined(DEBUG) code passe #endif
#ifdef et #ifndef est semblable celle avec #if defined ou #if !defined. sendmail, le test de compilation avec LOG permet xalloc()
dpend du fait que le compilateur soit du
de dterminer si des informations sont envoyes au systme de trace du systme d'exploitation. type standard ANSI ou non. Comme le montre le programme 15.7, lui aussi extrait du code de
sendmail,
15.8.2 Exercice 2
Reprendre l'exercice sur le calcul des racines d'une quation du second degr, pour ajouter des lignes de debug imprimant la valeur du discriminant et les calculs intermdiaires. Ces lignes doivent se trouver dans des test du prprocesseur de manire n'tre prsente que lorsqu'on passe l'option -DDEBUG la compilation. c Christian Bac 1985-2003
172
15.8.
Le chier d'inclusion est identique celui du programme 9.8 et les fonctions sont les mmes que dans le programme 9.6.
CHAPITRE 15.
PRPROCESSEUR
173
Programme 15.4
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
#define add(x1,x2) ((x1) += (x2)) #define m(x) 128*x+342*x*x #define y(x) (128*(x)+342*(x)*(x)) int main (int argc, char *argv[]) { int a,b,c; int e,f,g; a = b = c = 1; d = e = f = 2; add(a,b); add(a,b+1); d = m(a); e = y(a); d = m(a+b); d = y(a+b); f = m(add(a,b)); f = y(add(a,b)); return 0; }
int main (int argc, char *argv[]) { int a,b,c; int e,f,g; a = b = c = 1; d = e = f = 2; ((a) += (b)); ((a) += (b+1)); d = 128*a+342*a*a; e = (128*(a)+342*(a)*(a)); d = 128*a+b+342*a+b*a+b; d = (128*(a+b)+342*(a+b)*(a+b)); f = 128*((a) += (b))+342*((a) += (b))*((a) += (b)); f = (128*(((a) += (b)))+342*(((a) += (b)))*(((a) += (b)))); return 0; }
174
15.8.
Programme 15.5
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
#define vrai 1 #define faux 0 #if vrai vrai_est_vrai #else vrai_est_faux #endif #if faux faux_est_vrai #else faux_est_faux #endif #if vrai || faux vrai_ou_faux_est_vrai #endif #if !faux not_faux_est_vrai #endif #if vrai && !faux vrai_et_not_faux_est_vrai #endif
vrai_est_vrai
CHAPITRE 15.
PRPROCESSEUR
175
(void) unlink(PidFile); /* try to be safe :-) */ if ((f = dfopen(PidFile, "w")) != NULL) { fprintf(f, "%d\\n", getpid()); (void) chmod(PidFile, 0444); (void) fclose(f); } # ifdef LOG else syslog(LOG_NOTICE, "Could not log daemon " "pid %d to file %s: %m", getpid(), PidFile); # endif /* LOG */ } #endif /* _PATH_SENDMAILPID */
176
15.8.
: (a3) : \ : (a3) : \
: \ (a2)) : \ (a1)) : \
#define max_abs2bis(a1,a2) \ (((a1) < 0 ? -(a1) : (a1)) > ((a2) < 0) ? (-a2) : (a2)) ? \ (((a1) < 0 ? -(a1) : (a1)) : ((a2) < 0) ? (-a2) : (a2)) #define max_abs3(a1,a2,a3) max3(abs(a1),abs(a2),abs(a3))
CHAPITRE 15.
PRPROCESSEUR
177
Programme 15.9
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
int main (int argc, char *argv[], char **envp) { int i,j,k; printf("Rentrez les valeurs de i j et k :"); scanf("%d%d%d",&i,&j,&k); printf("Valeurs printf("Minimum printf("Maximum printf("Minimum printf("Maximum printf("Minimum printf("Maximum printf("Maximum return 0; absolues : %d %d %d \n", abs(i), abs(j), abs(k)); i et j : %d \n", min(i,j)); i et k : %d \n", max(i,k)); i j et k : %d \n", min3(i,j,k)); i j et k : %d \n", max3(i,j,k)); des valeurs absolues : %d \n", min_abs(i,j)); des valeurs absolues : %d \n", max_abs2(i,j)); des trois en valeur absolue : %d \n",max_abs3(i,j,k));
Donnes en entre
12 -23 7
178
15.8.
#include <stdio.h> #include <math.h> #include "c09c03a.h" int main (int argc, char *argv[], char **envp){ float a,b,c,r,r1; double rdis; float res; printf("calcul des racines de ax2 + bx + c\n\n"); /* saisie des coefficients */ printf("saisissez les coefficients a b et c\n"); scanf("%f %f %f",&a,&b,&c); if( a == 0 ){ printf(" Equation du premier degre \n"); printf(" La solution est x = %f \n", -c / b); exit(0); } r = -b/(2 * a); #ifdef DEBUG printf(" -b/2*a : %f \n", r); #endif res = dis(a,b,c); #ifdef DEBUG printf(" discriminant : %f \n", res); #endif switch ( res < 0 ? -1 : (res >0 ? 1 : 0 )) { case 1: rdis = sqrt(res); #ifdef DEBUG printf(" racine du discriminant : %f \n", rdis); #endif r1 = rdis / ( 2 * a); #ifdef DEBUG printf(" r1 : %f \n", r1); #endif rac2(r,r1); break; case -1: rdis = sqrt(-res); #ifdef DEBUG printf(" racine du discriminant : %f \n", rdis); #endif r1 = rdis / ( 2 * a); #ifdef DEBUG printf(" r1 : %f \n", r1); #endif complex(r,r1); break; case 0: racd(r); break; } return 0; }
c Christian Bac 1985-2003
Chapitre 16
Entres-sorties de la bibliothque
Comme nous l'avons vu, le langage C est de bas niveau. Pour permettre aux programmeurs de raliser des programmes sans tre oblig de rinventer les fonctionalits les plus courantes, la bibliothque du langage C fournit des fonctions de plus haut niveau ainsi que des fonctions qui permettent la ralisation des entre-sorties. La bibliothque standard contient : 1. des fonctions permettant la gestion des entres-sorties (E/S) ; 2. des fonctions de manipulation de chanes de caractres ; 3. des fonctions d'allocation dynamique de mmoire ; 4. des fonctions caractre gnral qui permettent l'accs au systme. L'ensemble des fonctions qui permettent de faire des entre-sorties standards de bas niveau est appell BIO (Basic Input Output). Ces fonctions et les structures associes sont dcrites dans le
...;
Le langage C donne une vision "UNIXienne " des entre-sorties. En langage C, un chier est une suite d'octets (un caractre = 1 octet). Le chier n'a pas de structure propre qui lui est attache. Il est cependant possible au niveau programme de considrer un chier comme une suite d'enregistrements correspondant une structure. Le principe de la manipulation d'un chier est le suivant : 1. ouverture du chier ; 2. lecture, criture, et dplacement dans le chier ; 3. fermeture du chier.
180
stdin
pour chier standard d'entre ; ce chier est le plus souvent associ au clavier ; pour chier de standard sortie ; ce chier dsigne le plus souvent l'cran et les fonctions
stdout
stderr
pour chier standard d'erreur, ce chier correspond lui aussi le plus souvent l'cran mais
les critures sont non tamponnes. Ces chiers peuvent tre redirigs au niveau de l'interprte de commandes [Bou78] par l'utilisation des symboles
>
et
<
les commandes sont enchanes par des tubes en utilisant le symbole non exaustifs d'utilisation des redirections :
|.
prog >fichier : lorsque prog crit, les octets sont dirigs vers le chier fichier prog <fichier : prog lit dans le chier fichier prog 2 >fichier : prog crit ses messages d'erreur dans le chier fichier prog1 | prog2 : la sortie standart de prog1 est associe l'entre standard de prog2.
ces chiers standards sont associes des fonctions prdnies qui permettent de raliser les oprations suivantes : lecture et criture caractre par caractre ; lecture et criture ligne par ligne ; lecture et criture formates.
int getchar(void) ;
synopsis :
unsigned char ;
stdin s'il
y en a un. Ce caractre
L'entier contient soit la valeur du caractre lu soit en n de chier la fonction retourne la valeur
EOF ;
conditions d'erreur :
int putchar(int ) ;
EOF.
synopsis : cette fonction permet d'crire un caractre sur stdout ; argument : Elle est dnie comme recevant un entier2 pour tre conforme getchar().
Ceci permet d'crire
putchar(getchar()).
retour : Elle retourne la valeur du caractre crit toujours considr comme un entier. conditions d'erreur : en cas d'erreur la fonction retourne EOF.
Le programme 16.1 ralise la lecture de son chier standard d'entre caractre par caractre et reproduit les caractres de son chier standard d'entre sur son chier standard de sortie. Son rle est similaire celui de l'utilitaire
cat(1)
1 Souvent 2 Avant
nomm par l'anglicisme buer, ce tampon permet de ne pas trop solliciter le systme d'exploitation
lors des critures. Sa taille la plus courante est un kilo-octets. la norme C99, la promotion implicite des arguments de fonctions (voir 3.8.1) faisait que de toute faon la valeur d'un caractre tait convertie en une valeur d'entier lors du passage d'arguments une fonction.
CHAPITRE 16.
ENTRES-SORTIES DE LA BIBLIOTHQUE
181
standards
1 2 3 4 5 6 7 8 9
Programme 16.1
#include <stdio.h> int main (int argc, char *argv[]) { int c; while ((c = getchar ()) != EOF) putchar (c); return 0; }
Donnes en entre
The quick brown fox jumped over the lazy dog, 1234567890.
The quick brown fox jumped over the lazy dog, 1234567890.
Dans ces changes, l'unit de base est la ligne de caractres. La ligne est considre comme une suite de caractres l'abrviation
char
n du chier. Le caractre de n de ligne a une valeur entire gale 10 et est reprsent par
'\n'.
char *gets(char *) ;
synopsis :
nul
lire une ligne sur stdin ; les caractres de la ligne sont rangs (un caractre par en argument la fonction. Le mmoire, puisse tre utilise
retour chariot est lu mais n'est pas rang en mmoire. Il est remplac par un caractre
'\0'
argument :
lus.
l'adresse d'une zone mmoire dans laquelle la fonction doit ranger les caractres
retour :
Si des caractres ont t lus, la fonction retourne l'adresse de son argument pour les appels de fonction. pointeur de caractre de valeur 0 (NULL dni dans l'appel (aucun caractre
conditions d'erreur :
< stdio.h >).
remarque :
Cette fonction ne peut pas vrier que la taille de la ligne lue est infrieure
la taille de la zone mmoire dans laquelle il lui est demand de placer les caractres. Il faut lui prfrer la fonction
fgets()
int puts(char *) ;
synopsis : criture d'une chane de caractres, suivie d'un retour chariot sur stdout. argument : l'adresse d'une chane de caractres. retour : une valeur entire non ngative en cas de succs. conditions d'erreur : Elle retourne la valeur EOF en cas de problme.
La version 16.2 reprend le programme prcdent de lecture et rcriture entre le chier standard d'entre et le chier standard de sortie mais ralise ces entres-sorties ligne par ligne. Le choix d'un c Christian Bac 1985-2003
182
tableau de 256 caractres permet d'esprer qu'aucune ligne lue ne provoquera un dbordement par la fonction
gets().
une ligne de plus grande taille, dans ce cas le comportement du programme est non dni .
Programme 16.2
1 2 3 4 5 6 7 8 9
#include <stdio.h> int main (int argc, char *argv[]) { char BigBuf[256]; while (gets (BigBuf) != NULL) puts (BigBuf); return 0; }
Donnes en entre
The quick brown fox jumped over the lazy dog, 1234567890.
The quick brown fox jumped over the lazy dog, 1234567890.
synopsis : lecture formate sur stdin. arguments : comme l'indique la spcication ...,
guments variable partir du second argument. des variables saisir.
1. le premier argument est une chane de caractres qui doit contenir la description
2. les autres arguments sont les adresses des variables (conformment la description donne dans le premier argument) qui sont aectes par la lecture.
synopsis : criture formate sur stdout arguments : chane de caractres contenant des commentaires et
ments crire, suivie des valeurs des variables.
retour : nombre de caractres crits. conditions d'erreur : la valeur EOF est retourne
standard ferm.
3 Cette
fonction est l'un des points faibles des programmes crits en langage C face une attaque de type
fgets@A
que nous verrons plus loin et qui permet d'viter ces dbordements
CHAPITRE 16.
ENTRES-SORTIES DE LA BIBLIOTHQUE
183
Des exemples de formats sont donns dans le tableau 4.2. Les possibilits en matire de format sont donnes de manire exhaustive dans la partie sur les entre-sorties formates (voir section 16.5).
fopen()
synopsis :
le systme de chiers sous forme d'une chane de caractres) selon le mode d'ouverture dcrit par le second argument (chane de caractres).
arguments :
1. la premire chane de caractres contient le nom du chier de manire rfrencer le chier dans l'arborescence. Ce nom est dpendant du systme d'exploitation dans lequel le programme s'excute. 2. Le deuxime argument est lui aussi une chane de caractres. Il spcie le type d'ouverture.
retour :
FILE
conditions d'erreur :
le pointeur
tre ouvert (problmes d'existence du chier ou de droits d'accs). Le type d'ouverture est spci partir d'un mode de base et de complments. Sans prcision, le chier est considr comme une chier de type texte (c'est--dire qu'il ne contient que des caractres ASCII). Le type d'ouverture de base peut tre :
Si le chier n'existe pas, la fonction ne le cre pas. Si le chier n'existe pas, la fonction le cre. Si le chier
le chier est ouvert en ajout. Si le chier n'existe pas, la fonction le cre. Les critures auront lieu la n du chier.
"b" "+"
le chier est considr en mode binaire. Il peut donc contenir des donnes qui sont transfres sans interprtation par les fonctions de la bibliothque. le chier est ouvert dans le mode complmentaire du mode de base. Par exemple s'il est ouvert dans le mode "r+" cela signie qu'il est ouvert en mode lecture et plus, soit lecture et criture.
La combinaison des modes de base et des complments donne les possibilits suivantes :
"r+" "w+"
pas. Le chier peut tre lu, modi et agrandi. le chier est ouvert en criture plus lecture. Si le chier n'existe pas, la fonction le cre. Si le chier existe, la fonction le vide. Le chier peut tre manipul en criture et relecture.
184
16.3.
Les
critures auront lieu la n du chier. Le chier peut tre lu. le chier est ouvert en lecture et en mode binaire. Si le chier n'existe pas, la fonction ne le cre pas. le chier est ouvert en criture et en mode binaire. cre. Si le chier existe, la fonction le vide. Si le chier n'existe pas, la fonction le
le chier est ouvert en ajout et en mode binaire. Si le chier n'existe pas, la fonction le cre. Les critures auront lieu la n du chier.
ou
"rb+"le "wb+"
Si le chier
n'existe pas, la fonction ne le cre pas. Le chier peut tre lu, modi et agrandi. ou le chier est ouvert en criture plus lecture et en mode binaire. Si le chier
fopen() retourne une rfrence vers une structure de donnes qui sert pour toutes FILE *)
doit tre dclar comme dans le programme 16.3 Si le systme
les autres oprations. Le pointeur qui reoit cette rfrence (souvent appel pointeur de chier par une traduction de
#include <stdio.h> int main (int argc, char *argv[]) { FILE *MyFich; MyFich = fopen ("/etc/passwd", "r"); /* ... */ return 0; } NULL. Si un
d'exploitation ne peut pas ouvrir le chier, il retourne une rfrence gale au pointeur
chier qui n'existe pas est ouvert en mode criture ou ajout, il est cr par le systme.
int fclose(FILE *) ;
synopsis :
la structure
FILE
fopen() ;
elle dtruit
et le chier
arguments : une rfrence de type FILE valide. retour : 0 dans le cas normal. conditions d'erreur : la fonction retourne EOF en cas d'erreur.
fopen()
Tout programme manipulant un chier doit donc tre encadr par les deux appels de fonctions et
fclose()
CHAPITRE 16.
ENTRES-SORTIES DE LA BIBLIOTHQUE
185
int fgetc(FILE *) ;
synopsis : lecture d'un caractre (unsigned char) dans le chier associ ; argument : une rfrence de type FILE valide correspondant un chier ouvert en lecture ;
retour : la valeur du caractre lu promue dans un entier ; conditions d'erreur : la rencontre de la n de chier, la fonction retourne EOF et positionne les indicateurs associs (voir 16.8).
int getc(FILE *) ;
synopsis : synopsis :
fgetc()
dnie dans
synopsis :
argument : retour :
unsigned char ;
rfrence de type
FILE
du chier ouvert ;
la valeur du caractre crit promue dans un entier sauf en cas d'erreur ; c Christian Bac 1985-2003
186
conditions d'erreur :
int putc(int , FILE *) ;
synopsis :
dans
Les fonctions (macro-expressions) getc() et putc() sont en fait la base de getchar() et putchar que nous avons utilises jusqu'ici. putchar(c) est dni comme putc(c,stdout) ; getchar() est dni comme getc(stdin). Comme getchar() la fonction getc() retourne un entier pour pouvoir retourner la valeur EOF en n de chier. Dans le cas gnral, l'entier retourn correspond un octet lu dans le chier et rang dans un entier en considrant l'octet comme tant du type caractre non sign (unsigned
char).
Le programme 16.5 est un exemple d'criture l'cran du contenu d'un chier dont le nom est donn en argument (comportement identique la commande comme tant en mode texte.
cat(1)
comme argument un seul nom de chier). Le chier est ouvert en mode lecture et il est considr
Programme 16.5
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
#include <stdio.h> int main (int argc, char *argv[]) { FILE *MyFic; int TheCar; if (argc != 2) return 1; MyFic = fopen (argv[1], "r"); if (MyFic == NULL) { printf ("Impossible d ouvrir le fichier %s \n", argv[1]); return 2; } while ((TheCar = fgetc (MyFic)) != EOF) fputc (TheCar, stdout); fclose (MyFic); return 0; }
Donnes en entre
The quick brown fox jumped over the lazy dog, 1234567890.
The quick brown fox jumped over the lazy dog, 1234567890.
CHAPITRE 16.
ENTRES-SORTIES DE LA BIBLIOTHQUE
187
synopsis :
lit une ligne de caractres ou au plus le nombre de caractres correspondant dans le chier associ au troisime argument. Les dans la mmoire partir de l'adresse donne en le retour chane de
premier argument. Si le nombre de caractres lu est infrieur la taille, chariot est lu et rang en mmoire. Il est suivi par un caractre nul caractres.
'\0'
de manire
ce que la ligne une fois place en mmoire, puisse tre utilise comme une
arguments :
1. adresse de la zone de stockage des caractres en mmoire, 2. nombre maximum de caractres (taille de la zone de stockage), 3. et la rfrence de type
retour : adresse reue en entre sauf en cas d'erreur ; conditions d'arrt : un ligne est lue (rencontre du conditions d'erreur : synopsis :
sitionne les indicateurs associs (voir 16.8).
FILE
du chier ouvert.
rencontre, le nombre de caractre lu est gal la taille du buer moins un. la rencontre de la n de chier, la fonction retourne
NULL
et po-
argument :
argument
les caractres crire. Cette zone doit tre un chane de caractres (termine par un caractre nul). Elle doit contenir un retour chariot pour obtebir un passage la ligne suivante. 2. le second argument contient la rfrence de type les caractres seront crits.
FILE
retour : une valeur positive si l'criture s'est correctement droule. conditions d'erreur : en cas d'erreur d'criture, la fonction retourne EOF et positionne les
indicateurs associs (voir 16.8). Pour la lecture ligne ligne, il est ncessaire de donner l'adresse d'un tableau pouvant contenir la ligne. De plus, il faut donner la taille de ce tableau pour que la fonction du tableau. La fonction
fgets()
aprs le dernier caractre qu'elle a mis dans le tableau. La rencontre du caractre de n de ligne ou de la n de chier provoque la n de la lecture. Le caractre de n de ligne n'est pas mis dans le tableau avant le caractre nul. par un caractre nul ('\0'). Il faut mettre explicitement la n de ligne dans ce tableau pour qu'elle soit prsente dans le chier. Le programme 16.6 ralise la lecture du chier correspondant au nom pass en argument sur la ligne de commande et l'criture de ces lignes sur le chier standard de sortie. Les oprations sont ralises ligne par ligne. Les dirences entre et La fonction
fputs()
crit une ligne dans le chier. Le tableau de caractres doit tre termin
gets()
et
fgets(),
d'une part, et
stdout
puts() et fputs(), d'autre part, puts et gets agissent sur les pseudo-chiers stdin
gets()
1. ne ncessite pas que lui soit fournie la taille du tableau de lecture. Il faut esprer que les lignes saisies seront plus courtes que la taille du tableau. Comme ces lignes viennent a priori d'un terminal, elles font souvent moins de 80 caractres. c Christian Bac 1985-2003
188
Programme 16.6
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
#include <stdio.h> int main (int argc, char *argv[]) { FILE *TheFic; char BigBuf[256];
if (argc != 2) return 1; TheFic = fopen (argv[1], "r"); if (TheFic == NULL) { printf ("Impossible d ouvrir le fichier %s \n", argv[1]); return 2; } while (fgets (BigBuf, sizeof BigBuf, TheFic) != NULL) fputs (BigBuf, stdout); fclose (TheFic); return 0;
Donnes en entre
The quick brown fox jumped over the lazy dog, 1234567890.
The quick brown fox jumped over the lazy dog, 1234567890.
2. ne met pas le caractre de n de ligne dans le tableau. Ce caractre le caractre de n de chane. la fonction
tableau.
size_t fread(void *Zone, size_t Taille, size_t Nbr, FILE *fp) ; size_t fwrite(void *Zone, size_t Taille, size_t Nbr, FILE *fp) ;
Ces fonctions ont une interface homogne. Elles acceptent une liste identique d'arguments, et retournent le mme type de rsultat. Les arguments sont les suivants : 1. le premier argument, que nous avons appel duquel l'change
Zone,
avec le chier est fait. L'espace mmoire correspondant reoit les enregis-
trements lus, ou fournit les donnes crire dans les enregistrements. Il faut, bien entendu, que l'espace mmoire correspondant l'adresse soit de taille susante pour supporter le transfert des donnes, c'est--dire d'une taille au moins gale c Christian Bac 1985-2003
(Taille * Nbr).
CHAPITRE 16.
ENTRES-SORTIES DE LA BIBLIOTHQUE
189
2. le deuxime argument, que nous avons appel nombre d'octets. 3. le troisime argument, que nous avons appel dsire changer. 4. le dernier argument, que nous avons appel
Taille,
Nbr,
FILE
fp,
correspondant
Ces deux fonctions retournent le nombre d'enregistrements changs. Ces fonctions ont t conues de manire permettre l'change de plusieurs structures, ce qui explique la prsence des deux arguments qui fournissent la taille totale des donnes transfrer. Le programme 16.7 est un exemple, d'utilisation de la fonction la lecture du contenu d'un chier appel un tableau en mmoire
ParcAuto.
fread(). Cet exemple ralise FicParcAuto avec stockage du contenu de ce chier dans
#include <stdio.h> #include <stddef.h> struct automobile { int age; char couleur[20], numero[10], type[10], marque[10]; } ParcAuto[20];
int main (int argc, char *argv[]) { FILE *TheFic; int i; size_t fait; TheFic = fopen ("FicParcAuto", "rb+"); if (TheFic == NULL) { printf ("Impossible d ouvrir le fichier FicParcAuto\n"); return 1; } for (i = 0; i < 20; i++) { fait = fread (&ParcAuto[i], sizeof (struct automobile), 1, TheFic); if (fait != 1) { printf ("Erreur lecture fichier parcauto \n"); return 2; } } fclose (TheFic); return 0; }
Il est possible de demander la lecture des vingt enregistrements en une seule opration, en remplaant les lignes 18 24 par les lignes suivantes :
190
printf()
et
scanf().
connaissances sur ces fonctions et sur les autres fonctions qui font des conversions de format. Les fonctions que nous allons tudier utilisent des formats de conversion entre le modle des donnes machines et le modle ncessaire la vision humaine (chane de caractres). Les lectures formates ncessitent : le format de description des lectures faire ; une adresse Les critures formates ncessitent : le format de description des critures faire ; les valeurs des variables simples crire. Comme dans le cas de la du premier caractre. lecture, l'criture d'un ensemble de caractres est une opration particulire qui peut se faire partir de l'adresse
lorsque des caractres blancs (espace, tabulation, retour chariot) sont lus ils sont consomms
%).
3. des spcications de conversion, commenant par le caractre Une conversion consiste en : 1. un caractre de pourcentage (%) ;
%.
2. un caractre (optionnel) d'eacement (*) ; dans ce cas la donne lue est mise la poubelle ; 3. un champ (optionnel) dnissant la taille de la donne lire exprime par une valeur entire en base dix ; 4. un caractre (optionnel) de prcision de taille qui peut tre : sur les modes de spcication de la manire suivante : (a) si le format initial est du type qu'entier ordinaire (int) . que la donne est du type entier long (long
d ou i ou n, les caractres l et h prcisent respectivement int) ou entier court (short int) plutt
(c)
o ou x ou u, les caractres l et h prcisent respectivement long int) ou entier court non sign (unsigned short int) plutt qu'entier non sign (unsigned int). si le format initial est du type e ou f ou g, les caractres l et L prcisent respectivement que la donne est du type nombre avec point dcimal de grande prcision double) ou nombre avec point dcimal de trs grande prcision (long double) plutt que du type nombre avec point dcimal (float).
que la donne est du type entier long non sign (unsigned
4 Ce 5
qui explique pourquoi il faut un & devant les noms de donnes lire quand ces noms ne sont pas des
tableaux. Des formats particuliers permettent la lecture de plusieurs caractres l'intrieur d'un tableau de caractres.
CHAPITRE 16.
ENTRES-SORTIES DE LA BIBLIOTHQUE
191
code % d i o u x e f g c s
conversion ralise lit un % entier sign exprim en base dcimale entier sign exprim en base dcimale entier non sign exprim en base octale entier non sign exprim en base dcimale entier non sign exprim en hexadcimal nombre avec partie dcimale en notation point dcimal ou exponentielle caractre mots ou chane de caractres sans blanc chane de caractres parmi un alphabet adresse, pour faire l'opration inverse de l'criture avec %p permet d'obtenir le nombre d'octets lus dans cet appel
[spcication]
p n
Tab.
5. un code de conversion.
scanf()
spcication entre les crochets dnit un alphabet6 de caractres. La donne lue doit tre
scanf()
conforme cette spcication. La lecture avec un format de spcication retourne une chane de caractres.
(c) pour une chane de caractre, si la taille est prcde de 0, la chane est cadre droite et est prcde de zros ; 4. un point suivi de la prcision. La prcision dnit le nombre de chires signicatifs pour de
une donne de type entier, ou le nombre de chires aprs la virgule pour une donne type ottant. Elle indique le nombre de caractres pour une chane ; 5. un
ou un
ou un
(a) dans le cas d'une conversion d'un entier (format est un entier court (h) ou long (l) ;
d, i, o, u, x, ou X)
6 Cet
un
alphabet est dni soit par la liste des caractres signicatifs, soit par le premier caractre suivi d'un tiret et
le dernier caractre dans l'ordre croissant de la table ASCII. La ngation de l'alphabet peut tre obtenue en mettant
aprs le crochet ouvrant. Pour que le crochet fermant soit dans l'alphabet, il faut qu'il suive immdiatement
le crochet ouvrant.
192
code % d i o u x, X e, E f g, G c s p n
conversion ralise crit un % entier sign exprim en base dcimale entier sign exprim en base dcimale entier non sign exprim en base octale entier non sign exprim en base dcimale entier non sign exprim en hexadcimal nombre avec partie dcimale en notation exponentielle nombre avec partie dcimale en notation point dcimal nombre avec partie dcimale, plus petit en taille des formats f ou e caractre chane de caractres la valeur passe est une adresse permet d'obtenir le nombre d'octets crits
Tab.
drapeau + blanc 0 ' #
printf()
modication apporte la donne convertie est cadre gauche si la donne est positive le signe + est mis si le rsultat de la conversion ne commence pas par un signe, un blanc est ajout remplissage avec des 0 devant plutot que des blancs pour les conversions dcimales groupement des chires par 3 pour format o augmente la prcision de manire forcer un 0 devant la donne pour format x et X force 0x devant la donne pour format e, E, f, g, et G force le point dcimal pour format g et G les zros aprs le point dcimal sont conservs
Tab.
double).
(b) dans le cas d'une conversion d'un nombre avec partie dcimale (format
que le nombre crire est un nombre avec point dcimal de trs grande prcision (long
e, f, g, E, ou G)
6. un code de conversion. Les champs taille et prcision peuvent contenir une un argument
*. Dans ce cas la taille doit tre passe dans [sf]printf. Par exemple les lignes suivantes d'appel printf() sont quivalentes :
et
Dans le premier cas, elles sont crites en minuscule (a-f ), dans le second cas, elles sont crites en majuscule (A-F). De mme, le caractre les formats
et
g.
et
G.
Selon la norme [ISO89], Le nombre maximum de caractres qui peuvent tre construits dans un appel aux fonctions de type
fprintf()
509.
Les drapeaux sont dcrits dans la table 16.3. c Christian Bac 1985-2003
CHAPITRE 16.
ENTRES-SORTIES DE LA BIBLIOTHQUE
193
int printf(const char *format, ...) ; int scanf(const char *format, ...) ;
sprintf
et
sscanf.
en chane de caractres.
retour :
retour : nombre de variables saisies. conditions d'erreur : la valeur EOF est retourne en cas d'erreur empchant toute lecture.
rsultat dans
. . .,
argn
sscanf
extrait d'une chane de caractres des valeurs qui sont stockes dans des
printf
et
retour : nombre de caractres crits. conditions d'erreur : une valeur ngative est retourne en cas d'erreur d'criture.
int fscanf(FILE *,const char *, ...) ;
c Christian Bac 1985-2003
194
16.6.
sateurs) et qui extrait les dirents champs dont les numros d'utilisateur et de groupe, en mettant ces numros dans des variables de type entier. Rappelons qu'une ligne de ce chier contient les champs suivants spars par le caractre deux points le nom de l'utilisateur, le mot de passe (crypt) ou un les mots de passe, le numro d'utilisateur, le numro de groupe dans lequel l'utilisateur est plac la connexion, un champ servant mettre des informations complmentaires appel champ champ peut contenir des caractres blancs) ; le rpertoire de connexion de l'utilisateur, le chier binaire excutable charger lors de la connexion (le plus souvent un shell). GCOS (ce
le dplacement est relatif au dbut du chier ; le dplacement est relatif la position courante ; le dplacement est relatif la n du chier ;
retour : 0 en cas de succs conditions d'erreur : une valeur dirente de zro est retourne si le dplacement ne peut
pas tre ralis.
long ftell(FILE *) ;
synopsis : retourne la valeur de la position courante dans le chier. argument : rfrence vers la structure dcrivant le chier ouvert ;
c Christian Bac 1985-2003
CHAPITRE 16.
ENTRES-SORTIES DE LA BIBLIOTHQUE
195
retour :
1. sur les chiers binaires : nombre d'octets entre la position courante et le dbut du chier. 2. sur les chiers texte : une valeur permettant courant l'endroit actuel.
conditions d'erreur :
la valeur
-1L
fpos_t
errno
est
retour : 0 en cas de succs conditions d'erreur : une void rewind(FILE *) ; synopsis : si la rfrence
modie .
fgetpos() ;
errno
est
(void)fseek(fp,0L,0).
fp
Pour illustrer le dplacement l'intrieur d'un chier, nous allons prendre pour exemple la modication de l'ge des voitures dans le chier
ralise la modication d'un enregistrement dans un chier en procdant de la manire suivante : 1. il lit un enregistrement du chier dans une zone en mmoire ; 2. il modie la zone en mmoire ; 3. il replace le pointeur courant du chier sur le dbut de l'enregistrement pour pouvoir rcrire cet enregistrement ; 4. il crit la zone mmoire dans le chier. Cette modication est ralise par le programme 16.9 selon les instructions C suivantes : la ligne 19 correspond une lecture d'un enregistrement du chier
UneAuto
du type
struct automobile.
age
la ligne 25 modie la position courante du chier pour positionner le pointeur courant l'adress de dbut de l'enregistrement qui est en mmoire. la ligne 28 crit dans le chier le contenu de la zone mmoire la modication de l'enregistrement sur disque. Ce mme exemple peut aussi tre ralis avec les fonctions
fsetpos()
comme
le montre la gure 16.10. La dirence majeure entre ces deux exemples vient du fait que dans la version 16.10 le programme conserve l'information permettant de repositionner le pointeur courant dans le chier, alors que dans le programme 16.9 le programme revient en arrire de la taille d'un enregistrement. Les fonctions
fgetpos()
et
fsetpos()
dplacements dans un chier avec des tailles d'enregistrement variables. c Christian Bac 1985-2003
196
16.7.
7 (sauf
stderr).
Dans le cas gnral, l'allocation du tampon se fait de manire automatique lors de la premire entre-sortie, la taille de ce tampon est de l'ordre du kilo-octet. Il est cependant possible d'associer un buer avec un chier ouvert par les fonctions dcrites ci-aprs, pour par exemple optimiser la taille de ce tampon par rapport aux critures ralises par le programme. Cette association doit tre faite avant tout change dans le chier ouvert. Le buer se trouve dans l'espace adressable de l'utilisateur. Les appels de fonctions associes la prsence d'un buer sont :
synopsis :
NULL,
les
entre-sorties du chier sont non buerises (chaque change donne lieu un appel
arguments :
systme).
1. rfrence vers la structure dcrivant le chier ouvert ; 2. adresse d'une zone mmoire destine devenir le buer d'entre-sortie associ au chier ouvert, cette zone doit avoir une taille prdnie dont la valeur est Elle peut tre gale au pointeur buerises.
NULL,
BUFSIZE.
synopsis : contrle la gestion de la buerisation d'un chier ouvert avant son utilisation. arguments :
1. rfrence vers la structure dcrivant le chier ouvert ; 2. adresse d'une zone mmoire destine devenir le buer d'entre-sortie associ au chier ouvert, cette zone doit l'adresse est gale avoir la taille donne en quatrime argument. Si
NULL,
la taille correspondante. 3. le type de buerisation, ce paramtre peut prendre les valeurs suivantes dnies
< stdio.h > : _IOFBF signie que les entre-sorties de ce chier seront totalement buerises (par
dans exemple les critures n'auront lieu que lorsque le tampon sera plein).
signie que les entre-sorties seront buerises ligne par ligne (i.e. dans le les entre-sorties sur le chier sont non buerises.
synopsis : vide le buer associ au chier ; argument : rfrence vers la structure dcrivant le chier ouvert
mode mise--jour. Cette rfrence peut tre gale sur l'ensemble des
NULL
en mode criture ou en
retour : 0 dans le cas normal et EOF en cas d'erreur. conditions d'erreur : la fonction retourne EOF si l'criture physique s'est mal passe.
Les entre-sorties sur les terminaux sont buerises ligne par ligne. La fonction permet de forcer l'criture des dernires informations.
fflush()
7 Anglicisme
que l'on peut traduire par tamponnes. Prenons le cas des critures. Elles sont d'abord ralises
dans un espace mmoire local au programme que l'on appelle tampon (buer en anglais). Les caractres sont ensuite transfrs au systme d'exploitatin en bloc. Ceci permet de minimiser les appels au systme d'exploitation (car le tampon de caractres est dans l'espace mmoire du programme) et en gnral d'amliorer les performances. Cette gestion de tampons intermdiaires peut se traduire par une reprsentation non exacte de l'tat du programme par les critures. En eet, les critures sont dires et le tampon d'criture n'est vid que lorsqu'une n de ligne est transmise.
CHAPITRE 16.
ENTRES-SORTIES DE LA BIBLIOTHQUE
197
errno.
fonctions de bibliothque servant raliser les appels systme. La valeur de spciant l'chec. Les fonctions associes la gestion des erreurs sont :
que lorsqu'une opration a chou et que l'appel de fonction correspondant a retourn une valeur
int ferror(FILE *) ;
synopsis :
Cette fonction retourne une valeur dirente de zro si la variable qui sert m-
moriser les erreurs sur le chier ouvert correspondant a t aecte lors d'une opration prcdente.
argument : retour :
d'erreur est faite. une valeur dirente de zro si une erreur s'est produite.
int feof(FILE *) ;
synopsis :
argument : retour :
void clearerr(FILE *) ;
synopsis :
argument :
dsire
eacer les valeurs de la variable mmorisant les erreurs et de la variable servant mmoriser la rencontre de la n de chier.
synopsis : Cette fonction fait la correspondance entre la valeur contenue dans la variable errno et une chane de caractres qui explique de manire succincte l'erreur correspondante.
argument :
de personnaliser le message. Le programme 16.11 illustre cette gestion d'erreur, par l'ajout des tests d'erreur dans l'exemple de parcours du chier "FicParcAuto" avec modication de l'ge dans les dirents champs.
198
Programme 16.8
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
#include <stdio.h> int main (int argc, char *argv[]) { FILE *pwf; int i, res; char nom[10], passwd[16], gcos[128], rep[255], shell[255]; int uid, gid; pwf = fopen ("passwd", "r"); if (pwf == NULL){ printf ("Impossible d ouvrir le fichier %s \n", "/etc/passwd"); return 1; } while (!feof (pwf)){ res = fscanf (pwf, " %[^:]:", nom); if (res != 1) break; res = fscanf (pwf, "%[^:]:", passwd); if (res != 1) break; res = fscanf (pwf, "%d:", &uid); if (res != 1) break; res = fscanf (pwf, "%d:", &gid); if (res != 1) break; for (i = 0; i < 128; i++){ res = fgetc (pwf); if (res == ':'){ gcos[i] = '\0'; break; } else gcos[i] = res; } res = fscanf (pwf, "%[^:]:", rep); if (res != 1) break; res = fgetc (pwf); if (res != '\n'){ ungetc (res, pwf); res = fscanf (pwf, "%s", shell); if (res != 1) break; } else shell[0] = '\0'; printf ("%s %s %d %d %s %s %s\n", nom, passwd, uid, gid, gcos, rep, shell); } fclose (pwf); return 0;
CHAPITRE 16.
ENTRES-SORTIES DE LA BIBLIOTHQUE
199
#include <stdio.h> #include <stddef.h> struct automobile { int age; char couleur[20], numero[10], type[10], marque[10]; } uneauto;
int main (int argc, char *argv[]) { FILE *fparc; int i; size_t fait; fparc = fopen ("FicParcAuto", "r+b"); if (fparc == NULL){ printf ("Impossible d ouvrir le fichier FicParcAuto \n"); return 1; } for (i = 0; i < 20; i++) { fait = fread (&uneauto, sizeof uneauto, 1, fparc); if (fait != 1) { printf ("Erreur lecture fichier FicParcAuto \n"); return 2; } uneauto.age++; fait = fseek (fparc, (long) -sizeof uneauto, SEEK_CUR); if (fait != 0){ printf ("Erreur deplacement fichier FicParcAuto \n"); return 3; } fait = fwrite (&uneauto, sizeof uneauto, 1, fparc); if (fait != 1) { printf ("Erreur ecriture fichier FicParcAuto fait = %d \n", fait); return 4; } } fclose (fparc); return 0; }
200
#include <stdio.h> #include <stddef.h> struct automobile { int age; char couleur[20], numero[10], type[10], marque[10]; } parc[20];
int main (int argc, char *argv[]) { FILE *fparc; int i; size_t fait; fpos_t curpos; fparc = fopen ("FicParcAuto", "r+b"); if (fparc == NULL){ printf ("Impossible d ouvrir le fichier FicParcAuto \n"); return 1; } for (i = 0; i < 20; i++) { fait = fgetpos (fparc, &curpos); if (fait != 0) { printf ("Erreur acquisition Position \n"); return 2; } fait = fread (&parc[i], sizeof (struct automobile), 1, fparc); if (fait != 1) { printf ("Erreur lecture fichier FicParcAuto \n"); return 3; } parc[i].age++; fait = fsetpos (fparc, &curpos); if (fait != 0) { printf ("Erreur restitution Position \n"); return 4; } fait = fwrite (&parc[i], sizeof (struct automobile), 1, fparc); if (fait != 1) { printf ("Erreur ecriture fichier parcauto fait = %d \n", fait); return 5; } } fclose (fparc); return 0; }
CHAPITRE 16.
ENTRES-SORTIES DE LA BIBLIOTHQUE
201
Programme 16.11
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
#include <stdio.h> #include <stddef.h> #include <unistd.h> struct automobile { int age; char couleur[20], numero[10], type[10], marque[10]; } parc;
int main (int argc, char *argv[]) { FILE *fparc; size_t fait; fparc = fopen ("FicParcAuto", "r+b"); if (fparc == NULL) { perror ("Impossible d ouvrir FicParcAuto"); return 1; } while (1){ fait = fread (&parc, sizeof parc, 1, fparc); if (fait != 1) { if (feof (fparc)) fprintf (stderr, "Fin de fichier FicParcAuto \n"); else fprintf (stderr, "Erreur lecture FicParcAuto\n"); break; } parc.age++; fait = fseek (fparc, (long) -sizeof (parc), SEEK_CUR); if (fait != 0) { perror ("Erreur deplacement FicParcAuto"); break; } fait = fwrite (&parc, sizeof parc, 1, fparc); if (fait != 1) { fprintf (stderr, "Erreur ecriture FicParcAuto fait = %d \n", fait); break; } fflush (fparc); } clearerr (fparc); fclose (fparc); return 0; }
202
Chapitre 17
changer le type d'un caractre. Ces macros expressions de test retournent un rsultat non nul si
isalpha(c) isupper(c) islower(c) isdigit(c) isspace(c) ispunct(c) isalnum(c) isprint(c) isgraph(c) iscntrl(c)
vrai si c est une lettre (alphabtique). vrai si c est une majuscule (upper case). vrai si c est une minuscule (lower case). vrai si c est un chire. vrai si c est un blanc, interligne ou tab. vrai si c est un caractre de ponctuation. vrai si c est alphabtique ou numrique. vrai si c est achable de 040 0176. vrai si c est graphique de 041 0176. vrai si c est del (0177) ou un caractre de contrle (<040).
Dclaration
Travail
Retour
char *s1, *s2 ; int n ; char *strcat (s1, s2) char *strncat (s1, s2, n) int strcmp (s1, s2) int strncmp (s1, s2, n) char *strcpy (s1, s2) char *strncpy (s1, s2, n) char *s ; int strlen (s)
ajoute la chane s2 derrire s1 ajoute au plus n caractres compare s1 et s2 compare au plus n caractres copie s2 dans s1 copie sur au plus n caractres
pointeur sur s1 pointeur sur s1 nombre positif, nul, ngatif s1>s2 , s1==s2 , s1<s2
taille de s
Tab.
204
17.3.
Dclaration
Travail
Retour
char *s1, *s2 ; int n ; int c ; char *strchr (s, c) char *strrchr (s, c) char *index(s, c) char *rindex(s, c) char *strpbrk (s1, s2) int strspn (s1, s2) int strcspn (s1, s2)
cherche caractre c dans s idem idem que strchr idem que strrchr cherche 1 caractre de s2 dans s1 1
er
er
aucun caractre de s2
Tab.
vrai si c est ASCII (<0200). retourne le caractre majuscule correspondant c. retourne le caractre minuscule correspondant c. masque c avec 0x7f.
system("date") ; calloc()
o et
Nous avons peu parl d'implantation de donnes en mmoire. Il est possible de grer une partie de l'espace dynamiquement par les fonctions
cfree(). n objets
cfree(p)
a t obtenu par un
calloc().
17.3.2
exit()
exit() comme une rupture de squence. L'instruction return provoque exit() provoque la n du programme. Cette
Bien que n'tant pas une instruction du langage mais un appel une fonction du systme, il est intressant de considrer le fonction la n d'une fonction ; de mme l'appel la fonction
exit() peut tre aussi associe une expression. Cette expression est value et la valeur
obtenue est retourne au processus pre. La valeur 0 signie que le programme s'est bien pass. Prenons le cas du programme 17.1 qui doit lire un chier. Si ce chier est absent, la fonction qui est charge de l'ouvrir peut dcider l'arrt du programme. Nous allons crire cette fonction.
CHAPITRE 17.
205
int ouvre (const char *nom_fichier) { int o; o = open (nom_fichier, 0); if (o == -1) { printf ("impossible d'ouvrir %s\n", nom_fichier); exit (1); } return o; }
206
17.3.
Preamble
The purpose of this License is to make a manual, textbook, or other written document free in the sense of freedom : to assure everyone the eective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modications made by others. This License is a kind of copyleft, which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software. We have designed this License in order to use it for manuals for free software, because free software needs free documentation : a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals ; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference.
208
The Invariant Sections are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. The Cover Texts are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A Transparent copy of the Document means a machine-readable copy, represented in a format whose specication is available to the general public, whose contents can be viewed and edited directly and straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent le format whose markup has been designed to thwart or discourage subsequent modication by readers is not Transparent. A copy that is not Transparent is called Opaque. Examples of suitable formats for Transparent copies include plain ASCII without markup, AT X input format, SGML or XML using a publicly available DTD, and Texinfo input format, L E standard-conforming simple HTML designed for human modication. Opaque formats include PostScript, PDF, proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the machine-generated HTML produced by some word processors for output purposes only. The Title Page means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, Title Page means the text near the most prominent appearance of the work's title, preceding the beginning of the body of the text.
17.7.
MODIFICATIONS
209
If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a publicly-accessible computer-network location containing a complete Transparent copy of the Document, free of added material, which the general network-using public has access to download anonymously at no charge using public-standard network protocols. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public. It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document.
17.7 Modications
You may copy and distribute a Modied Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modied Version under precisely this License, with the Modied Version lling the role of the Document, thus licensing distribution and modication of the Modied Version to whoever possesses a copy of it. In addition, you must do these things in the Modied Version : Use in the Title Page (and on the covers, if any) a title distinct from that of the Document, and from those of previous versions (which should, if there were any, be listed in the History section of the Document). You may use the same title as a previous version if the original publisher of that version gives permission. List on the Title Page, as authors, one or more persons or entities responsible for authorship of the modications in the Modied Version, together with at least ve of the principal authors of the Document (all of its principal authors, if it has less than ve). State on the Title page the name of the publisher of the Modied Version, as the publisher. Preserve all the copyright notices of the Document. Add an appropriate copyright notice for your modications adjacent to the other copyright notices. Include, immediately after the copyright notices, a license notice giving the public permission to use the Modied Version under the terms of this License, in the form shown in the Addendum below. Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document's license notice. Include an unaltered copy of this License. Preserve the section entitled History, and its title, and add to it an item stating at least the title, year, new authors, and publisher of the Modied Version as given on the Title Page. If there is no section entitled History in the Document, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modied Version as stated in the previous sentence. Preserve the network location, if any, given in the Document for public access to a Transparent copy of the Document, and likewise the network locations given in the Document for previous versions it was based on. These may be placed in the History section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission. In any section entitled Acknowledgements or Dedications, preserve the section's title, and preserve in the section all the substance and tone of each of the contributor acknowledgements and/or dedications given therein. Preserve all the Invariant Sections of the Document, unaltered in their text and in their titles. Section numbers or the equivalent are not considered part of the section titles.
210
Delete any section entitled Endorsements. Such a section may not be included in the Modied Version. Do not retitle any existing section as Endorsements or to conict in title with any Invariant Section. If the Modied Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modied Version's license notice. These titles must be distinct from any other section titles. You may add a section entitled Endorsements, provided it contains nothing but endorsements of your Modied Version by various parties for example, statements of peer review or that the text has been approved by an organization as the authoritative denition of a standard. You may add a passage of up to ve words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modied Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another ; but you may replace the old one, on explicit permission from the previous publisher that added the old one. The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modied Version.
17.10.
211
17.11 Translation
Translation is considered a kind of modication, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License provided that you also include the original English version of this License. In case of a disagreement between the translation and the original English version of this License, the original English version will prevail.
17.12 Termination
You may not copy, modify, sublicense, or distribute the Document except as expressly provided for under this License. Any other attempt to copy, modify, sublicense or distribute the Document is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.
212
17.13.
Copyright c YEAR YOUR NAME. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation ; with the Invariant Sections being LIST THEIR TITLES, with the Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST. A copy of the license is included in the section entitled GNU Free Documentation License. If you have no Invariant Sections, write with no Invariant Sections instead of saying which ones are invariant. If you have no Front-Cover Texts, write no Front-Cover Texts instead of Front-Cover Texts being LIST ; likewise for Back-Cover Texts. If your document contains nontrivial examples of program code, we recommend releasing these examples in parallel under your choice of free software license, such as the GNU General Public License, to permit their use in free software.
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
16 17 17 24 24 24 25 26 28 31 32 33 34 35 38 42 43 50 51 52 53 54 55 58 67 68 69 70 70 71 71 72 72 73 74 75 76 77 78 79 80 81
Suggestion de corrig chapitre 3 exercice 1 . . . . . . . . . . . . . . . . . . . . . . . Suggestion de corrig chapitre 3 exercice 1 second chier . . . . . . . . . . . . . . . Suggestion de corrig chapitre 3 exercice 2 . . . . . . . . . . . . . . . . . . . . . . . Suggestion de corrig chapitre 3 exercice 3 . . . . . . . . . . . . . . . . . . . . . . . Suggestion de corrig chapitre 3 exercice 4 . . . . . . . . . . . . . . . . . . . . . . . Lecture et criture de chane par Lectures multiples avec
scanf()
scanf()
et
printf()
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . .
Suggestion de corrig chapitre 4 exercice 1 . . . . . . . . . . . . . . . . . . . . . . . Suggestion de corrig chapitre 4 exercice 2 . . . . . . . . . . . . . . . . . . . . . . . Suggestion de corrig chapitre 4 exercice 3 . . . . . . . . . . . . . . . . . . . . . . . Suggestion de corrig chapitre 4 exercice 4 . . . . . . . . . . . . . . . . . . . . . . . Dnitions de variables et d'un pointeur . . . . . . . . . . . . . . . . . . . . . . . . Utilisation des oprateurs de masquage . . . . . . . . . . . . . . . . . . . . . . . . . Utilisation des oprateurs de dcalage . . . . . . . . . . . . . . . . . . . . . . . . . Suggestion de corrig chapitre 5 exercice 1 . . . . . . . . . . . . . . . . . . . . . . . Suggestion de corrig chapitre 5 exercice 2 . . . . . . . . . . . . . . . . . . . . . . . Suggestion de corrig chapitre 5 exercice 3 . . . . . . . . . . . . . . . . . . . . . . . Suggestion de corrig chapitre 5 exercice 4 . . . . . . . . . . . . . . . . . . . . . . . Suggestion de corrig chapitre 5 exercice 5 . . . . . . . . . . . . . . . . . . . . . . . Suggestion de corrig chapitre 5 exercice 6 . . . . . . . . . . . . . . . . . . . . . . . Exemple de tests imbriqus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Exemple de table de sauts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Exemple de table de sauts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Exemple de table de sauts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Lecture d'une ligne avec
while
. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
while for
. . . . . . . . . . . . . . . . . . . . . .
Lecture d'une ligne avec for . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Dcomposition des puissances de dix d'un nombre avec un Utilisation du continue dans une boucle
do while
. . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
6.10 Utilisation des ruptures de squence dans une boucle 6.11 Lecture d'une ligne avec 6.12 Utilisation de 6.13 Utilisation de
for
. . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.14 Suggestion de corrig chapitre 6 exercice 1 . . . . . . . . . . . . . . . . . . . . . . . 6.15 Suggestion de corrig chapitre 6 exercice 2 . . . . . . . . . . . . . . . . . . . . . . . 6.16 Suggestion de corrig chapitre 6 exercice 3 . . . . . . . . . . . . . . . . . . . . . . . 6.17 Suggestion de corrig chapitre 6 exercice 4 . . . . . . . . . . . . . . . . . . . . . . . 6.18 Suggestion de corrig chapitre 6 exercice 5 . . . . . . . . . . . . . . . . . . . . . . . 6.19 Suggestion de corrig chapitre 6 exercice 6 . . . . . . . . . . . . . . . . . . . . . . . c Christian Bac 1985-2003
214
7.1 7.2 7.3 7.4 7.5 7.6 7.7 7.8 7.9 8.1 8.2 8.3 8.4 8.5 9.1 9.2 9.3 9.4 9.5 9.6 9.7 9.8 9.9
Ensemble de tests non structur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ensemble de tests structur non mis en page Ensemble de tests structur et mis en page . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
87 88 89 90 91 92 93 93 93 105 107 108 109 110 115 117 117 122 123 124 125 126 127 130 137 138 138 139 140 141 144 145 145 146 147 148 149 150 151 152 154 160 162 163 163 164 166 167 169 173 174 175 175 176
Ensemble de tests structur et mis en page avec commentaires . . . . . . . . . . . . Ensemble de tests structur, mis en page et tiquet Ensemble de tests par table de branchement . . . . . . . . . . . . . . . . . . . . . . Boucle ralise par des tests et sauts . . . . . . . . . . . . . . . . . . . . . . . . . . Boucle ralise par un for() Achage des arguments de Arguments de . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Boucle ralise par un for() et mise en page . . . . . . . . . . . . . . . . . . . . . .
main()
main()
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
caractres un--un
Suggestion de corrig chapitre 8 exercice 1 . . . . . . . . . . . . . . . . . . . . . . . Suggestion de corrig chapitre 8 exercice 2 . . . . . . . . . . . . . . . . . . . . . . . Suggestion de corrig chapitre 8 exercice 3 . . . . . . . . . . . . . . . . . . . . . . . Exemples de prototypes de fonctions . . . . . . . . . . . . . . . . . . . . . . . . . . Dclarations candidates multiple d'une variable . . . . . . . . . . . . . . . . . . . . Dclaration explicite et dclaration candidate d'une variable . . . . . . . . . . . . . Suggestion de corrig chapitre 9 exercice 1 fonctions Suggestion de corrig chapitre 9 exercice 1 Suggestion de corrig chapitre 9 exercice 2 Suggestion de corrig chapitre 9 exercice 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10.1 Dnition de tableaux et initialisations . . . . . . . . . . . . . . . . . . . . . . . . . 10.2 Accs un tableau deux dimensions avec un pointeur 10.3 Algorithme d'un tri simple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10.4 Suggestion de corrig chapitre 10 exercice 1 chier d'inclusion . . . . . . . . . . . . 10.5 Suggestion de corrig chapitre 10 exercice 1 fonctions . . . . . . . . . . . . . . . . . 10.6 Suggestion de corrig chapitre 10 exercice 1 11.1 Dnition de structures 11.2 Dnition de structures
main
. . . . . . . . . . . . . . . . . . .
11.5 Suggestion de corrig chapitre 11 exercice 1 11.6 Suggestion de corrig chapitre 11 exercice 2
12.1 Utilisation d'une union . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.2 Utilisation d'une union . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.3 Suggestion de corrig chapitre 12 exercice 1 12.4 Suggestion de corrig chapitre 12 exercice 2 14.1 Suggestion de corrig chapitre 14 exercice 1 14.2 Suggestion de corrig chapitre 14 exercice 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
14.3 Suggestion de corrig chapitre 14 exercice 3 chier d'inclusion . . . . . . . . . . . . 14.4 Suggestion de corrig chapitre 14 exercice 3 fonctions . . . . . . . . . . . . . . . . . 14.5 Suggestion de corrig chapitre 14 exercice 3 15.1 Traitement des commentaires 15.2 Erreur due au traitement des commentaires 15.4 Evaluation de macros par CPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15.5 Exemple d'utilisation du #if . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15.6 Exemples de slection de code par 15.7 Slection de code par
#ifdef
#ifdef
. . . . . . . . . . . . . . . . . . . . . . .
imbriqus
. . . . . . . . . . . . . . . . . . . . . . . .
15.8 Suggestion de corrig chapitre 15 exercice 1 dnition des macros . . . . . . . . . . c Christian Bac 1985-2003
215
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
177 178 181 182 184 185 186 188 189 198 199 200 201 205
16.1 Lecture et criture caractre par caractre sur les chiers standards . . . . . . . . . 16.2 Lecture ligne par ligne sur les chiers standards . . . . . . . . . . . . . . . . . . . . 16.3 Ouverture d'un chier . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16.4 Ouverture et fermeture d'un chier . . . . . . . . . . . . . . . . . . . . . . . . . . . 16.5 Lecture caractre par caractre d'un chier aprs ouverture 16.6 Lecture ligne ligne d'un chier aprs ouverture 16.7 Lecture d'enregistrements dans un chier 16.8 Lecture avec format dans un chier texte . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
16.9 Modications par dplacement dans un chier . . . . . . . . . . . . . . . . . . . . . 16.10Dplacements dans un chier avec fgetpos() . . . . . . . . . . . . . . . . . . . . . . 16.11Gestion des cas d'erreurs pendant la manipulation d'un chier . . . . . . . . . . . . 17.1 Utilisation de l'appel systme
exit() .
. . . . . . . . . . . . . . . . . . . . . . . . .
216
cc
. . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.1
. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15
4.1
27
5.1 5.2
Exemple de relation entre pointeur et variable . . . . . . . . . . . . . . . . . . . . . Mise en relation d'un pointeur et d'une variable . . . . . . . . . . . . . . . . . . . .
38 38
while for
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
60 61 62 64 64 65
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
do while .
dans un dans un dans un
et et et
for
while
do while
main()
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Exemple de visibilit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Visibilit des variables entre modules . . . . . . . . . . . . . . . . . . . . . . . . . . Visibilit des fonctions entre modules . . . . . . . . . . . . . . . . . . . . . . . . . . Visibilit des fonctions dans un module . . . . . . . . . . . . . . . . . . . . . . . .
218
9.9
120
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10.2 Tableau de dix entiers initialis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10.3 Adresses dans un tableau de dix entiers 10.4 Tableau deux dimensions . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10.5 Pointeur et tableau . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10.6 Tableau de pointeurs sur des variables dans un tableau . . . . . . . . . . . . . . . . 10.7 Accs un tableau deux dimensions avec un pointeur . . . . . . . . . . . . . . .
4.1 4.2
printf scanf
et
scanf
. . . . . . . . . . . . . . . . . . . . . . . .
29 30
printf
et
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Liste des oprateurs unaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Liste des oprateurs binaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Liste des oprateurs binaires d'aectation . . . . . . . . . . . . . . . . . . . . . . .
37 41 44 45 45 46
6.1 6.2
Syntaxe du
while
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . et du
60 61
Comparaison du
for
while
. . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.1
C et Structures Fondamentales
. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
85
96 97 99 102
9.1
113
. . . . . . . . . . . . . . . . . . . . . . . . . . .
132 133
. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
144
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
159
220
168
scanf() . printf()
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . .
203 204
Bibliographie
[BK78] D.M. Ritchie B.W. Kernighan.
glewood Clis, New Jersey, Mars 1978. [BK88] D.M. Ritchie B.W. Kernighan.
Prentice
Hall Inc., Englewood Clis, New Jersey, 1988. [Bou78] S. Bourne. The UNIX Shell. 57(6) :19711990,
July/August 1978. [Dax92] P. Dax. 1992. [Dij65] E.W. Dijkstra. Programming Considered as a Human Activity. In pages 213217, 1965. [Dij68] E.W. Dijkstra. GO TO Statements Considered Harmful. 11(3) :147148, Mars 1968. [DR78]
S.C. Johnson D.M. Ritchie. Portabilty of C Programs and the UNIX Operating System. 57(6) :20212048, July/August 1978. ISO/IEC, 1989. ISO/IEC, 1999.
M.E. Lesk S.C. Johnson. Language Development Tools. 57(6) :21552176, July/August 1978.
[Str86]
B. Stroustrup.
New Jersey, 1986. [Wir71] N. Wirth. Program Development by Stepwise Renement. 14(4) :221227, Avril 1971. [Wir74] N. Wirth. On the Composition of Well Structured Programs. 6(4) :247259, Decembre 1974.
222
INDEX
Index
#dene, 165, 168, 170 #else, 165, 170 #endif, 165, 170 #if, 165, 170, 171 #ifdef, 165, 170, 171 #ifndef, 165, 170, 171 #include, 165, 166, 179 #undef, 165, 169 accolade, 5, 10, 21, 28, 47, 85, 96, 129 adresse, 11, 15, 19, 20, 23, 24, 29, 38, 39, 48, 97, 99, 103, 105, 106, 113, 120, 129 133, 135, 136, 144, 145, 150, 151, 157, 158, 160, 181, 182, 187, 188, 190, 193, 194, 196 aectation, 3, 15, 17, 19, 20, 29, 37, 43, 44, 47, 49, 57, 62, 99, 114, 132, 144 alias, 7, 165 appel, 13, 5, 11, 17, 19, 22, 23, 28, 29, 39, 40, 42, 43, 46, 63, 65, 9597, 99, 102, 103, 105, 106, 113115, 117, 119 121, 157, 158, 160, 161, 166, 168 170, 180182, 184, 185, 188, 189, 192 197, 204 argument, 11, 23, 27, 28, 65, 97, 99, 102, 103, 105, 111, 114117, 121, 133, 136, 144, 145, 168, 180189, 192197 associativit, 46, 47, 158 bibliothque, 3, 7, 27, 28, 63, 96, 179, 183, 197, 203 binaire, 2, 5, 4042, 44, 46, 47, 103, 114, 145, 170, 183, 184, 188, 189, 194, 195 bit, 2, 3, 1113, 15, 20, 22, 4044, 47, 49, 102, 145, 146, 151, 180 bloc, 5, 17, 47, 62, 63, 65, 95, 96, 114, 119, 120, 196 boolen, 57, 168 boucle, 5, 6064, 66, 8486, 121, 161 caractre, 13, 7, 911, 1315, 1925, 2729, 31, 32, 44, 59, 60, 6266, 86, 102, 103, 132, 150, 151, 165, 168, 179 183, 185194, 196, 197, 203, 204 case, 46, 59, 99, 133 crire, 1, 3, 12, 15, 23, 24, 27, 29, 31, 32, 37, 43, 44, 48, 49, 62, 66, 8385, 96, 102, c Christian Bac 1985-2003 champs de bit, 22, 102, 145, 146 char, 1, 103, 132, 182, 183, 187, 193, 196, 197 chargeable, 7 classe, 10, 11, 17, 106, 113, 114 commentaire, 7, 85, 111, 165, 182 compilateur, 13, 5, 79, 1113, 15, 16, 18 21, 27, 28, 40, 41, 46, 60, 65, 84, 105, 106, 111, 113, 114, 116, 117, 130, 132, 133, 136, 144, 149, 150, 155, 157, 165168, 170, 171 compilation, 2, 5, 8, 9, 18, 25, 28, 84, 95, 111, 113, 114, 117, 118, 120, 165, 166, 168171 constante, 911, 1315, 17, 22, 37, 40, 59, 99, 102, 103, 129, 130, 133, 153155, 168, 170, 171, 179 continue, 10, 59, 62, 86, 106 contrle, 1, 5, 7, 27, 43, 47, 57, 6062, 114, 116, 120, 193, 196, 203 conversion, 21, 22, 29, 99, 102, 132, 150, 190 194 corps, 5, 23, 65, 95, 96, 111, 116, 168 chane, 2, 3, 7, 10, 14, 15, 21, 23, 28, 29, 31, 32, 60, 65, 66, 86, 103, 117, 165, 168, 179, 181183, 187191, 193, 197, 203, 204 champ, 9, 22, 102, 143146, 149151, 190 192, 194, 195, 197
dclaration, 3, 18, 23, 29, 95, 96, 111, 114 119, 129, 132, 135, 157, 158, 160 default, 10 dnition, 3, 5, 7, 11, 12, 1521, 23, 28, 38, 40, 43, 47, 83, 95, 96, 106, 111, 114, 116119, 129, 131133, 143146, 149, 153, 157, 158, 161, 165, 168171, 179, 203 double, 10, 43, 65, 121 dure de vie, 17, 18, 120
INDEX
223
115, 130, 155, 158, 161, 180, 182, 185, 187, 188, 190192, 195, 204 criture, 2, 28, 29, 31, 42, 59, 66, 135, 136, 179188, 190193, 195, 196 dition de lien, 3, 7, 8, 23, 103, 114 else, 10, 57 enchaneur de passe, 169, 170 entier, 1, 1113, 15, 19, 20, 2225, 29, 31, 3844, 48, 49, 62, 63, 66, 85, 97, 99, 102, 103, 106, 114, 129132, 135, 146, 149151, 153155, 157, 160, 161, 171, 180, 185, 186, 189191, 194, 195, 197 entry, 10 numration, 22, 102, 153155 tiquette, 9, 10, 65, 85 excutable, 2, 5, 8, 42, 103, 114, 170, 194 excution, 5, 11, 15, 1719, 39, 40, 59, 6163, 65, 97, 99, 102, 105, 119, 120, 132, 170, 183, 204 expression, 5, 7, 10, 11, 2123, 3747, 49, 57, 5962, 65, 96, 102, 106, 130, 133, 154, 155, 157, 165, 168, 169, 171, 179, 180, 203, 204 extern, 10 externe, 3, 23, 111, 190, 191
instruction, 2, 5, 7, 10, 20, 23, 28, 29, 38, 39, 42, 43, 47, 49, 5766, 83, 84, 95, 96, 103, 106, 111, 168, 170, 195, 204 int, 10, 41, 63, 116, 117, 132, 186, 196 interface, 5, 27, 28, 95, 96, 102, 113, 115, 119, 188 langage, 13, 5, 812, 16, 23, 27, 29, 37, 40, 41, 44, 46, 47, 57, 59, 8385, 95, 97, 102, 103, 111, 115117, 119, 129, 130, 143145, 153, 154, 160, 171, 179, 182, 185, 204 lecture, 7, 15, 28, 29, 31, 32, 42, 46, 62, 63, 66, 83, 85, 121, 135, 158, 165, 179187, 189191, 193195 lire, 2729, 32, 44, 66, 121, 135, 150, 171, 180, 181, 188, 190, 204 local, 18, 23, 114, 132, 196 long, 10, 15, 22, 25, 40, 114, 190, 191 main, 5, 23, 28, 31, 65, 102, 103, 106, 121, 133, 136, 161 mmoire, 1, 11, 12, 15, 1720, 28, 38, 42, 95, 97, 99, 102, 111, 114, 120, 129132, 143, 149, 150, 157, 179, 181, 187 189, 193, 195, 196, 204 norme, 13, 8, 9, 11, 12, 15, 21, 22, 40, 102, 115, 146, 153, 170, 180, 192, 194 objet, 2, 8, 1820, 28, 29, 99, 111, 114, 118, 130132, 143, 146, 158, 160, 183, 188, 204 octet, 13, 11, 12, 14, 15, 38, 40, 60, 130, 145, 179, 180, 186, 189, 194196 oprateur, 12, 16, 20, 29, 32, 3748, 57, 62, 66, 131, 158 optimiseur, 5, 7 paramtre, 5, 95, 97, 99, 102, 103, 105, 106, 113, 196 pile, 17, 97, 99, 102, 103, 105, 106, 132 pointeur, 1, 11, 1820, 23, 24, 38, 39, 48, 97, 99, 103, 105, 106, 120, 121, 129, 131133, 135, 136, 145147, 158, 160, 161, 181, 183185, 194196, 204 prcdence, 45, 46, 158 prprocesseur, 168171, 180 printf, 28, 29, 31, 66, 103, 115, 182, 190, 192, 193 procdure, 95 programmation, 2, 3, 5, 63, 66, 83, 84, 117, 179, 182 prototype, 3, 114118, 158, 179, 184
faux, 40, 57, 132 chier, 2, 3, 5, 7, 8, 11, 15, 16, 18, 23, 27, 28, 31, 4043, 60, 62, 64, 96, 103, 111, 113, 114, 116119, 121, 136, 154, 165 171, 179189, 193197, 203, 204 oat, 10, 114 ottant, 2325, 31, 32, 161, 171, 191 fonction, 3, 5, 7, 911, 1618, 22, 23, 27 29, 31, 46, 57, 60, 63, 65, 86, 9597, 99, 102, 103, 105, 106, 111, 113121, 132, 133, 135, 136, 144, 145, 158, 160, 161, 165, 168, 171, 172, 179 190, 192197, 203, 204 for, 3, 10, 61 format, 7, 9, 28, 29, 31, 103, 180, 182, 183, 185, 190194 fortran, 10
if, 10, 19, 57, 158 initialisation, 10, 11, 17, 20, 21, 61, 62, 117, 120, 129, 130, 132
224
INDEX
qualicatif, 11, 12, 15, 18 rfrence, 2, 3, 7, 18, 23, 40, 114, 116, 168, 184, 185, 187, 189, 193197 register, 10 relogeable, 7 retour, 11, 14, 31, 45, 6366, 9597, 99, 105, 106, 145, 171, 180185, 187, 190, 193 197 return, 10, 65, 96, 102, 204 rupture, 5, 10, 62, 63, 66, 204 scanf, 28, 29, 31, 99, 115, 182, 190, 191, 193 short, 10, 41, 190 sizeof, 10, 12, 40, 132, 204 source, 2, 3, 5, 7, 18, 43, 46, 85, 95, 96, 111, 113, 117, 118, 136, 165, 168, 170 static, 120 statique, 18, 23, 102, 119, 120 struct, 10, 19 structure, 13, 9, 1921, 47, 8385, 103, 111, 118, 120, 135, 143147, 149, 150, 158, 160, 161, 179, 184, 188, 189, 193 197 structur, 83, 84, 121, 144, 188 systme, 1, 2, 5, 7, 8, 15, 27, 28, 41, 42, 60, 84, 85, 102, 103, 121, 154, 166, 170, 171, 179, 180, 183, 184, 186, 194, 196, 197, 204 table de branchement, 58, 85 tableau, 12, 15, 1825, 28, 29, 37, 41, 44, 46, 48, 6064, 66, 84, 86, 96, 97, 99, 102, 103, 120, 129133, 135, 136, 144, 145, 147, 157, 158, 160, 161, 165, 168, 179, 181, 183, 187190 ternaire, 45, 47, 66 test, 5, 4245, 47, 57, 5962, 65, 84, 85, 130, 154, 168, 171, 197, 203 type, 13, 5, 7, 923, 2729, 31, 3844, 47, 57, 60, 62, 63, 65, 66, 84, 85, 9597, 99, 102, 103, 105, 106, 111, 113120, 130133, 135, 143146, 149, 150, 153 155, 157, 158, 160, 161, 166, 168, 170, 171, 179, 180, 182192, 194 197, 203 typedef, 10 types prdnis, 11, 16 unaire, 12 union, 149, 150, 161 UNIX, 1, 2, 5, 7, 8, 27, 28, 41, 42, 60, 85, 103, 132, 154, 166, 180, 186, 194
unsigned, 10 valeur, 2, 1114, 16, 17, 1923, 25, 28, 3845, 4749, 57, 5963, 65, 66, 85, 96, 97, 99, 102, 105, 106, 113, 120, 129132, 150, 153155, 168171, 180182, 185 187, 190, 192197, 204 variable, 3, 5, 7, 912, 1520, 22, 23, 2729, 31, 32, 3745, 47, 49, 57, 59, 62, 65, 9597, 99, 102, 103, 105, 106, 111, 113115, 117120, 130133, 135, 143 146, 149, 150, 153155, 157, 158, 165, 167171, 182, 190, 193195, 197 visibilit, 3, 11, 17, 18, 113, 115, 120 void, 10 vrai, 40, 57, 197, 203 while, 62