• Aucun résultat trouvé

Conservatoire National des Arts et Métiers

N/A
N/A
Protected

Academic year: 2022

Partager "Conservatoire National des Arts et Métiers"

Copied!
250
0
0

Texte intégral

(1)

Conservatoire National des Arts et Métiers

Polycopié de cours ELE002

Version du 19/03/2007

Outils Logiciels de base

C.ALEXANDRE – C.PAUTOT

(2)
(3)

1. INTRODUCTION ... 1

1.1 L’informatique... 1

1.2 Le système de traitement de l’information ... 1

1.3 Le codage de l’information... 2

1.4 L’ordinateur ... 5

1.5 Le système d’exploitation... 6

1.6 Les applications logicielles... 9

1.7 Le système de fichiers ... 10

1.8 Les répertoires (syntaxe Unix) ... 10

1.9 Partitionnement et montage ... 11

1.10 Informations associées aux fichiers... 13

1.11 Protection des fichiers (Unix)... 14

1.12 Tableau comparatif des systèmes de fichiers ... 16

1.13 Les fichiers textes ... 16

2. LANGAGES DE PROGRAMMATION... 19

2.1 Définitions ... 19

2.2 Méthodologie pour l’écriture d’un programme ... 20

2.3 Le langage C... 21

3. BASES DU LANGAGE C ... 23

3.1 Les variables ... 23

3.2 L’instruction d’affectation... 24

3.3 Les types entier... 27

3.4 Les types flottants (réels)... 29

3.5 Les conversions de type... 30

3.6 Les types char ... 32

3.7 Communiquer avec le programme : les entrées-sorties standard ... 33

3.8 L’instruction printf ... 37

3.9 L’instruction scanf... 40

3.10 Structure de choix : l’instruction if... 42

3.11 Structure de choix : les conditions en C ... 45

3.12 Structure de choix : l’instruction switch... 49

3.13 Structure de répétition conditionnelle : l’instruction do... while ... 51

(4)

3.14 Structure de répétition conditionnelle : l’instruction while... ... 52

3.15 Structure de répétition inconditionnelle : l’instruction for... 53

3.16 Algorithmes élémentaires ... 56

4. LES FONCTIONS ...59

4.1 Introduction... 59

4.2 Premier exemple ... 60

4.3 Fonction sans résultat ou sans paramètres ... 64

4.4 L’instruction return... 66

4.5 Variables globales et locales ... 67

4.6 Variable statique ... 70

4.7 La récursivité... 71

4.8 Passage des paramètres par valeur. ... 72

4.9 Les pointeurs ... 74

4.10 Passage de pointeurs comme paramètres d’une fonction... 83

5. LES TABLEAUX ...85

5.1 Tableaux à une dimension... 85

5.2 Remarques importantes sur les tableaux... 90

5.3 Les tableaux à deux dimensions... 93

5.4 Passage d’un tableau comme paramètre d’une fonction... 97

5.5 Relations entre tableaux et pointeurs ... 100

5.6 Allocation dynamique de la mémoire ... 104

6. LES CHAINES DE CARACTERES ... 107

6.1 Déclaration ... 107

6.2 Lire ou écrire des chaînes... 110

6.3 Connaître la longueur d’une chaîne ... 117

6.4 Copier une chaîne dans une autre chaîne ... 118

6.5 Comparer deux chaînes... 119

6.6 Concaténer deux chaînes... 120

6.7 Rechercher un caractère dans une chaîne ... 121

6.8 Rechercher une chaîne dans une autre chaîne... 121

6.9 Fonctions diverses... 123

6.10 Le passage d’une chaîne comme paramètre d’une fonction. ... 124

(5)

6.11 Les tableaux de chaînes de caractères. ... 126

7. LES PARAMETRES DE LA FONCTION MAIN... 129

8. LES STRUCTURES ... 133

8.1 Définition... 133

8.2 Transmission d’une structure en paramètre d’une fonction ... 137

8.3 La définition de types nouveaux... 140

9. LES FICHIERS... 143

9.1 Introduction ... 143

9.2 Ouverture et fermeture d’un flux... 145

9.3 Buffers associés aux flux... 149

9.4 Lecture et écriture dans un flux ... 150

9.4.1 Les lectures et écritures par caractère... 150

9.4.2 Les lectures et écritures par ligne ... 151

9.4.3 Les lectures et écritures formatées... 153

9.4.4 Les lectures et écritures binaires... 155

9.5 Positionnement dans un flux ... 158

9.6 Utilisation d’un fichier de configuration ... 160

10. DIVERS ... 163

10.1 Exécution de commandes ... 163

10.2 Les opérateurs binaires ... 164

10.3 Les énumérations... 165

10.4 Les opérateurs d’incrémentation et de décrémentation ... 166

10.5 L’opérateur virgule ... 168

10.6 L’opérateur conditionnel ? ... 168

10.7 Les macros avec paramètres ... 169

10.8 Ce que vous ne verrez pas ... 172

10.9 Définition de macro à l’invocation du compilateur... 172

10.10 Compilation conditionnelle ... 173

11. EDITION DE LIEN ... 179

11.1 Les pointeurs de fonction ... 179

11.2 Notion de processus... 182

11.3 Les zones mémoires d’un processus... 183

(6)

11.4 Projets multi-fichiers : édition de liens ... 186

12. LES LIBRAIRIES...195

12.1 Les bibliothèques statiques (archive)... 195

12.2 Les bibliothèques dynamiques (partagées) ... 196

12.3 Avantages et inconvénients des bibliothèques dynamiques ... 200

12.4 La bibliothèque standard du C ... 202

12.4.1 Les entrées-sorties <stdio.h> ... 202

12.4.2 Les fonctions mathématiques <math.h> ... 203

12.4.3 Les manipulations de caractères <ctype.h> ... 204

12.4.4 Les manipulations de chaînes <string.h>... 204

12.4.5 Manipulations de l’heure <time.h>... 205

12.4.6 Diverses fonctions utilitaires <stdlib.h> ... 205

13. INTRODUCTION A LA PROGRAMMATION EN C++ ...207

13.1 Généralités ... 207

13.2 Intérêt de la conception objet ... 207

13.3 Un exemple de programmation classique ... 208

13.4 Les classes... 213

13.4.1 Définition ... 213

13.4.2 Syntaxe... 213

13.4.3 Constructeur ... 214

13.4.4 Destructeur ... 214

13.4.5 Restriction d’accès ... 214

13.4.6 Les fonctions (méthodes) de la classe... 215

13.4.7 Organisation en fichiers source et header ... 216

13.5 Création d’un objet... 217

13.5.1 Au moyen d’une déclaration ... 217

13.5.2 Avec l’opérateur new ... 217

13.6 Manipulation des objets ... 219

13.6.1 Accès à une variable ... 219

13.6.2 Accès à une fonction ... 219

13.7 Surcharge des fonctions et des opérateurs ... 221

13.8 Passage par référence ... 224

13.9 Héritage et composition ... 225

(7)

13.9.1 Introduction ... 225

13.9.2 La composition ... 226

13.9.3 L’héritage ... 226

13.9.3.1 Principe de l’héritage... 226

13.9.3.2 Restriction d’accès... 228

13.9.3.3 Substitution des membres hérités ... 229

13.9.3.4 Gestion des constructeurs ... 230

13.9.3.5 Fonctions virtuelles ... 232

13.10 Les flux d’entrée sortie ... 235

13.10.1 Généralités ... 235

13.10.2 Opérateur d'insertion et d’extraction de flux ... 235

13.10.2.1 Extraction de flux >>... 235

13.10.2.2 Insertion de flux >>... 235

13.10.3 Modification des formatages ... 236

13.10.3.1 Liste des drapeaux ... 236

13.10.3.2 Fonctions permettant de modifier les drapeaux... 237

13.10.3.3 Formatage de la sortie... 237

13.10.4 Manipulateurs non paramétriques ... 238

13.10.5 Entrée et sortie non formatées ... 239

13.10.5.1 La fonction get()... 239

13.10.5.2 La fonction getline()... 240

13.10.5.3 La fonction read()... 240

13.10.6 Fonctions de sortie non formatées ... 241

13.10.6.1 La fonction put... 241

13.10.6.2 La fonction write... 241

13.10.7 Les fonctions de manipulations évoluées ... 241

13.11 Bibliographie ... 242

(8)
(9)

1. Introduction

1.1 L’informatique

C’est la manipulation de l’information à l’aide d’un ordinateur.

Ordinateur : machine électronique programmable destinée au traitement de l’information numérique.

Information : texte, son, image, données binaires (produites par un système électronique, utilisées par un système électronique), …

1.2 Le système de traitement de l’information

ordinateur

Système d’exploitation

Dispositif électronique matériel (hardware) Logiciels (software)

Applications Logicielles

Interface de programmation

Interface matériel/logiciel

Interface de programmation, l’Application Programming Interface (API) : exemple, l’API Win32 pour Windows.

Interface matériel/logiciel : exemple, le Basic Input Output System (BIOS). Jusqu’à MS- DOS, le BIOS sert d’interface entre l’ordinateur et le système d’exploitation. Cette méthode n’est plus utilisée aujourd’hui, l’interface est intégrée au système d’exploitation (voir HAL sous NT).

(10)

1.3 Le codage de l’information

Un bit (contraction de Binary digIT) est un chiffre pouvant prendre la valeur 0 ou 1 (base 2).

Dans un ordinateur, un bit est représenté par deux niveaux de tension électrique. Un nombre binaire est une suite de bits (comme un nombre décimal est une suite de chiffres compris entre 0 et 9).

En décimal (base 10) :

Le nombre 259 = 2*102 + 5*101 + 9*100 = 2*100 + 5*10 + 9*1

En binaire (base 2) :

Le nombre 10101 = 1*24 + 0*23 + 1*22 + 0*21 + 1*20 = 1*16 + 1*4 + 1*1

Un octet (ou byte) est une suite de 8 bits :

L’octet 10000001 = 1*27 + 1*20 = 129

La valeur d’un octet est comprise entre 0 et 255. Pour raccourcir l’écriture, on utilise la notation hexadécimale (base 16).

Un chiffre en base 16 peut prendre 16 valeurs allant de 0 à 15. Il peut être codé avec 4 bits.

Comme les chiffres s’arrêtent à 9 en décimal, on utilise les lettre a, b, c, d ,e et f pour représenter les derniers états.

(11)

décimal binaire hexadécimal

0 0000 0

1 0001 1

2 0010 2

3 0011 3

4 0100 4

5 0101 5

6 0110 6

7 0111 7

8 1000 8

9 1001 9

10 1010 a

11 1011 b

12 1100 c

13 1101 d

14 1110 e

15 1111 f

L’octet 10000001 = 81 en hexa

Notation pour les bases :

(10000001)b = (81)h = (129)d

101011002 = ac16 = 17210

On utilise couramment les multiples suivants :

multiple valeur

Kilo 210 = 1024

Méga 220 = 1048576 = 1024 kilo

Giga 230 = 1073741824 = 1024 méga

Tera 240 = 1099511627776 = 1024 giga

(12)

Exemples :

1 kilobit = 1024 bits

128 mégaoctet = 128*1024*1024 octets

Attention : en informatique

1 kilo ≠ mille 1 méga ≠ 1 million 1 giga ≠ 1 milliard

Changement de base :

• Décimal vers binaire

47 2

1 23 2

1 11 2

1 5 2

1 2 2

0 1 2

1 0

4710 = 1011112

• Binaire vers décimal

1 x 25 + 0 x 24 + 1 x 23 + 1 x 22 + 1 x 21 + 1 x 20 = 4710

(13)

• Hexadécimal vers binaire

ab8516 = 1010 1011 1000 01012

• Binaire vers hexadécimal

1001 0000 1010 11112 = 90af16

Pour passer d’hexadécimal en décimal (et vice versa), vous pouvez passer par l’intermédiaire du binaire ou faire le calcul directement.

Exercice 1.1 :

1) Quel est le nombre décimal le plus grand que l’on peut coder avec 4 bits, 8 bits, 16 bits, 32 bits.

2) Convertissez 11011012 en décimal.

3) Convertissez 1910 et 4510 et 6310 en binaire.

4) Convertissez 11001010010101112 en hexadécimal.

5) Convertissez 10A416 et CF8E16 et 974216 en binaire et en décimal.

1.4 L’ordinateur

Un ordinateur :

• Traite l’information grâce à un programme qu’il mémorise,

• Communique et archive des informations.

Il est constitué de trois éléments :

(14)

1. La mémoire centrale (vive) qui permet de stocker les programmes pendant le temps nécessaire à leur exécution ainsi que les informations temporaires manipulées par ces programmes. La mise hors tension de l’ordinateur efface le contenu de la mémoire vive.

2. L’unité centrale qui exécute les instructions contenues dans le programme qui se trouve en mémoire vive.

3. Les périphériques qui échangent des informations avec l’unité centrale. On en trouve de deux sortes :

• Les périphériques de communication : clavier, écran, souris, imprimante, modem, carte son, carte réseau, …

• Les périphériques d’archivage : disque dur, disquette, CD-ROM, bande magnétique, ...

ils assurent le stockage permanent des données et des programmes.

Exemple : un PC.

Processeur Intel pentium IV, fréquence 3 GHz.

Mémoire vive 512 Mo.

Disque dur 200 Go.

Lecteur de DVD -ROM + graveur.

Lecture de disquette 3,5 pouces.

Ecran 17 pouces LCD.

Carte son.

Carte réseau.

Clavier, souris.

1.5 Le système d’exploitation

C’est un ensemble de programmes qui servent :

• à gérer les ressources de l’ordinateur et notamment à assurer leur partage harmonieux entre les différents programmes.

• à présenter à l’utilisateur et aux programmes une interface plus facile à utiliser que la machine physique. Cette interface est celle d’une machine virtuelle qui cache la complexité du matériel. Elle sert :

Ö d’interface entre l’ordinateur et les applications logicielles (API).

Ö d’interface entre l’ordinateur et l’utilisateur (IHM).

(15)

L’utilisateur d’un ordinateur effectue généralement les tâches suivantes : 1. il développe un programme,

2. ou bien il utilise un programme pour générer ou manipuler de l’information.

Pour faciliter ces opérations, le système d’exploitation peut utiliser deux sortes d’interface avec l’utilisateur :

1. L’interface graphique (mode graphique). Elle utilise la souris, les icônes et les menus déroulants. Très conviviale elle ne permet pas l’automatisation des traitements.

Exemples : MAC OS, Windows, …

2. L’interpréteur de commandes textuel (mode ligne de commande ou console ou terminal).

L’utilisateur manipule ici les données à l’aide de commandes tapées au clavier. On l’appelle un shell sous unix ou command.com sous MS-DOS. L’interpréteur de commande est peu intuitif car l’utilisateur doit connaître les commandes pour pouvoir l’utiliser mais il est en revanche plus puissant car programmable.

Le système d’exploitation comprend 4 parties essentielles : 1. La gestion des programmes.

2. Les entrées/sorties.

3. La gestion de la mémoire.

4. Le système de fichiers.

Caractéristiques :

⇒ La mémoire virtuelle. La taille des programmes et des données manipulées en mémoire vive dépasse généralement la quantité de mémoire physiquement disponible dans l’ordinateur. Pour augmenter la quantité de mémoire disponible, le système d’exploitation va garder en mémoire vive les parties actives du programme et des données et stocker le reste sur le disque dur. Un mécanisme de pagination permet de charger en mémoire quand il le faut les parties de programme à exécuter. Le nombre de bits codant l’adresse maximale de la mémoire utilisable par un programme caractérise le système d’exploitation (16, 32 ou 64 bits). La MMU est chargé de traduire les adresses virtuelles en adresses physiques.

(16)

⇒ La gestion des programmes. Le système monotâche ne peut exécuter qu’un seul programme à la fois même si plusieurs programmes peuvent être présents à la fois en mémoire (permutation). Un système multitâches préemptif fait tourner plusieurs programmes en même temps grâce à un planificateur (scheduler) qui attribue à chacun des programmes un petit laps de temps (slice time) pour s’exécuter. Tous les programmes se trouvent dans une file d’attente et attendent leur tour. Les programmes les plus prioritaires reviennent plus souvent dans la queue et donc s’exécutent plus rapidement.

Un système multitâches coopératif est un système monotâche (pas de scheduler) car ce sont les programmes qui sont conçus pour s’arrêter de temps en temps pour passer à un autre programme.

⇒ La gestion des utilisateurs. Un système multi-utilisateurs permet à plusieurs utilisateurs d’accéder simultanément à l’ordinateur pour exécuter des taches différentes. Le système doit distinguer les différents utilisateurs en les dotant d’un nom et d’un mot de passe ainsi que d’un espace disque (et d’un espace mémoire) réservé. C’est le compte utilisateur. Le système est forcément multitâches préemptif. Un système monotâche est forcément mono-utilisateur.

Caractéristiques des principaux systèmes :

MS-DOS Mono-tache Mono-utilisateur 16 (20) bits

MAC OS 9 Mono-tache Mono-utilisateur 32 bits

Unix multi-tâches Multi-Utilisateurs 32 bits ou 64 bits

VMS multi-tâches Multi-Utilisateurs 32 bits

Windows 95 et 98 multi-tâches Mono-utilisateur 32 bits + 16 bits

Windows NT multi-tâches Mono-utilisateur

Multi-Utilisateurs

32 bits

Windows 2000 Windows XP

Vista

multi-tâches Multi-Utilisateurs 32 bits ou 64 bits

(17)

1.6 Les applications logicielles

Ce sont des programmes. Exemples :

• Bureautique : traitement de texte, tableur, gestion de base de données, …

• Gestion et comptabilité : facturation, paye, stocks, …

• Jeux vidéo,

• Navigation Internet,

• Prévisions météorologiques,

• Conception assistée par ordinateur (CAO),

• Gestion d’une chaîne de fabrication,

• Simulateur de vol,

• …

Un ordinateur est capable de mettre en mémoire un programme (résidant généralement sur le disque dur), puis de l’exécuter.

Un programme est constitué d’instructions qui spécifient :

• Les opérations élémentaires que va exécuter l’ordinateur,

• La manière dont elles s’enchaînent.

programme

données résultats

Les données d’entrée du programme peuvent être fournies manuellement ou lues sur un disque dur (base de données) ou bien sur des capteurs.

Les résultats fournis par le programme peuvent être lus directement par l’utilisateur (sous forme de textes ou de graphiques) ou bien stockés sur disque.

Si le temps de réaction du programme entre un changement sur une entrée (capteur) et le résultat en sortie (actuateur) doit être garanti, alors on dit que le programme s’exécute en temps réel.

(18)

1.7 Le système de fichiers

On ne peut pas maintenir toutes les informations utiles d’un ordinateur en mémoire vive. Il faut les sauvegarder sur un support qui stocke l’information même lorsqu’il est hors tension (un disque dur par exemple). Le système de fichiers est l’ensemble des mécanismes destiné à manipuler de l’information sur ce support.

Un fichier est un objet qui peut contenir des programmes, des données ou tout autre type d’information. Le système d’exploitation fournit des opérations spéciales, les appels système, pour les créer, les détruire, les écrire ou les modifier.

Le système de fichiers est, avec le bureau, la partie la plus visible du système d’exploitation.

La plupart des programmes lisent ou écrivent au moins un fichier et les utilisateurs manipulent beaucoup de fichiers. L’utilisateur attache une grande importance à l’interface du système de fichiers, c’est-à-dire aux fichiers, à la manière de les nommer et de les protéger, aux opérations permises sur les fichiers, …

1.8 Les répertoires (syntaxe Unix)

Le système de fichiers range les fichiers dans des répertoires (directories) ou dossiers. Un répertoire contient un certain nombre d’entrées, une par fichier ou par répertoire. Etant donné la très grande quantité de fichiers à gérer sur un ordinateur (plusieurs centaines de milliers), il faut un système de classement performant. Une organisation hiérarchique constituée d’une arborescence de répertoires permet d’avoir autant de répertoires qu’il est nécessaire afin de regrouper les fichiers logiquement. Un répertoire peut contenir soit des fichiers, soit d’autres répertoires.

(19)

Le premier répertoire dans la hiérarchie (ici

/

) s’appelle le répertoire racine (root).

L’utilisateur peut définir le répertoire dans lequel il veut travailler, le répertoire de travail (working directory) ou répertoire courant (il y a une valeur par défaut spécifiée par le système d’exploitation). Il existe deux méthodes pour spécifier l’emplacement (chemin d’accès ou path) d’un fichier :

Le chemin d’accès absolu. C’est le chemin spécifié à partir du répertoire racine.

Ex : /usr/local/bin/nom_de_fichier.

Le

/

(slash) représente soit le répertoire racine s’il est au début du chemin d’accès, soit un séparateur qui indique un changement de niveau.

le chemin d’accès relatif. C’est le chemin spécifié à partir du répertoire courant.

Exemple : le répertoire courant est /usr/local/bin. On veut accéder à un fichier se trouvant dans /usr/bin

../../bin/ nom_de_fichier

.. désigne le répertoire père (répertoire juste au-dessus dans l’arborescence).

. désigne le répertoire dans lequel vous êtes.

Exercice 1.2 : le répertoire courant est /usr/local. Donnez le chemin d’accès absolu et relatif des répertoires man, Yves et etc.

1.9 Partitionnement et montage

Il est possible de diviser un disque en plusieurs morceaux (des partitions) en effectuant un partitionnement. Cela permet, par exemple, d’installer plusieurs systèmes d’exploitation (OS

= operating system) sur un disque.

Sur les OS Microsoft, on affecte aux partitions une lettre appelée lettre de lecteur. Chaque partition sera appelée C, D, E, … Les lettres A et B sont généralement affectées aux lecteurs amovibles.

(20)

Un chemin d’accès absolu sera nommé : C:\users\dut_info. Le répertoire racine est précédé de la lettre du lecteur suivie de :. Le slash (/) d’Unix est remplacé par un backslash (\). Le chemin d’accès relatif sous Windows est le même que sous Unix, mais avec un \ à la place d’un /.

Sous Unix, il n’y a pas de lettre de lecteur pour identifier un lecteur physique (disque dur ou disquette) ou bien une partition. Tout est monté sous le répertoire racine /.

Partition 1 Partition 0 /

usr etc tmp home

lib bin include

dut tpb

montage

(21)

L’opération de montage sert à indiquer au système à quel niveau de l’arborescence se placent les différents disques et partitions. Dans l’exemple précédent, la partition utilisateurs (partition 1) est rattachée (montée) au répertoire home de la partition racine (partition 0). Un lecteur de DVD-ROM sera par exemple monté sous le répertoire mount (/mnt/cdrom).

Sous Unix, il faut ajouter à la notion de répertoire de travail (working directory) celle de répertoire privé (home directory). Le répertoire privé est le répertoire dans lequel l’utilisateur se retrouvera lors de sa connexion au système. C’est l’emplacement où il enregistrera ses fichiers par défaut. Cette notion n’a pas de sens avec Windows 98 ni même avec Windows NT (NT ne créé pas automatiquement un répertoire par utilisateur), mais existe sous XP et Vista.

1.10 Informations associées aux fichiers

L’entrée du répertoire contient des informations associées au fichier telles que :

Le nom du fichier. La FAT-16 (MS-DOS) ne permet que des noms de 8 caractères suivis d’une extension de trois caractères (format 8+3).

Exemple : essai.txt

L’extension indique le type du fichier. Seuls les .bat, .exe et .com sont exécutables. La FAT-32 et NTFS (XP, Vista) autorisent les noms longs.

Unix permet des noms longs de 255 caractères avec différentiation des majuscules et des minuscules. Il n’y a pas d’extension, le . est un caractère comme un autre. Un attribut décide de la possibilité pour un programme de s’exécuter ou non.

• La date et l’heure de la dernière modification.

• La taille du fichier en octets.

• Les attributs de protection (sous Unix).

• Les numéros de bloc contenant les données du fichier. Ces informations ne sont pas visibles par l’utilisateur.

(22)

Exemple d’informations retournées par une commande dir sous Windows NT :

Le volume dans le lecteur D s'appelle MainNT Le numéro de série du volume est EB2A-9B11 Répertoire de D:\users\dut_info

09/10/00 16:36 <DIR> . 09/10/00 16:36 <DIR> ..

09/10/00 16:35 <DIR> essai

09/10/00 08:53 21 fichier_dos.txt 09/10/00 08:53 20 fichier_unix.txt 09/10/00 16:36 531 result.txt

6 fichier(s) 41 octets 8 242 147 328 octets libres

Nous sommes sur le disque D dans le répertoire \users\dut_info. <DIR> indique la présence d’un répertoire. Le . représente le répertoire courant. Le .. représente le répertoire père.

1.11 Protection des fichiers (Unix)

La protection des fichiers est inexistante sous Windows 98 (il n’y a en général qu’un utilisateur sur le PC), correcte sous Windows XP et Vista (avec NTFS mais pas avec la FAT- 32 utilisée par défaut) et bonne sous Unix.

Sous Unix. Chaque utilisateur fait partie d’un groupe de travail. Les protections d’un fichier concernent :

Le propriétaire du fichier Users (u) Le groupe d’utilisateurs Group (g)

Les autres utilisateurs Others (o) Les opérations concernées par les permissions rwx sont :

La lecture read (r)

L’écriture write (w)

L’exécution execute (x)

(23)

Ces permissions rwx ont une signification particulière lorsqu’il s’agit d’un répertoire :

• r : ce droit permet uniquement de lire les noms des fichiers du répertoire.

• w : cette permission autorise la création et la destruction de fichiers dans ce répertoire.

• x : cette permission indique que l’on pourra passer par ce répertoire (avec une commande cd).

Exemple du contenu d’un répertoire sous Unix :

drwxr-xr-x 4 dut dut 4096 jui 12 15:30 Desktop/

-rw-r--r-- 1 dut dut 18 oct 9 09:26 essai.txt drwx--- 2 dut dut 4096 oct 9 09:48 nsmail/

-rw-r--r-- 1 dut dut 0 oct 9 14:03 result.txt drwx--- 2 dut dut 4096 oct 9 09:48 tmp/

-rwxr--r-- 1 dut dut 0 oct 9 13:53 toto*

drwxr-xr-x 4 dut dut 4096 jui 12 15:30 Desktop/

-rw-r--r-- 1 dut dut 18 oct 9 09:26 essai.txt drwx--- 2 dut dut 4096 oct 9 09:48 nsmail/

-rw-r--r-- 1 dut dut 0 oct 9 14:03 result.txt drwx--- 2 dut dut 4096 oct 9 09:48 tmp/

-rwxr--r-- 1 dut dut 0 oct 9 13:53 toto*

drwxr-xr-x 4 dut dut 4096 jui 12 15:30 Desktop/

-rw-r--r-- 1 dut dut 18 oct 9 09:26 essai.txt drwx--- 2 dut dut 4096 oct 9 09:48 nsmail/

-rw-r--r-- 1 dut dut 0 oct 9 14:03 result.txt drwx--- 2 dut dut 4096 oct 9 09:48 tmp/

-rwxr--r-- 1 dut dut 0 oct 9 13:53 toto*

Permissions (rwx) user : group : others

d : directory

l : lien symbolique user group taille

Date et heure de la dernière modification

(pas d’année si année en cours) Nom

Exercice 1.3 : donnez tout les renseignements que vous pourrez sur essai.txt, toto et tmp.

Tout fichier dont le nom commence par un . est dit caché. Cela signifie simplement deux choses :

1. Le fichier ne sera pas vu lors d’une commande de listage de fichier classique de type ls.

2. Ce fichier ne sera pas détruit par une commande de destruction de type rm si vous utilisez un joker comme *.

(24)

1.12 Tableau comparatif des systèmes de fichiers

Système de fichiers

FAT 16 FAT 32 NTFS EXT2FS

OS MS-DOS, Windows 95

Windows 98, XP, Vista

Windows NT, 2000, XP, Vista

linux

Format des noms 8.3 (255 avec VFAT)

8.3 (255 avec VFAT)

255 255

protection non non oui oui

Sensible à la casse non non Non [1] oui

Mécanismes de correction

non non oui oui

Taille max cluster 32 ko 4 ko 4 ko 4 ko

Taille max partition

(216 – 10)*32 ko = 2 Go

(228 – 10)*8 ko = 2 To

(264 * 4ko) 2 To pour un disque « de base »

4 To

[1] NTFS affiche la différence entre majuscule et minuscule, mais vous ne pouvez avoir dans le même répertoire deux fichiers toto.txt et TOTO.txt.

1.13 Les fichiers textes

Le codage d’un caractère dans un fichier (on parle alors de fichier texte) doit utiliser un code pour faire correspondre un octet (en général) à un caractère. Le code le plus connu et le plus utilisé est le code ASCII (American Standard Code for Information Interchange). Mais il existe aussi le code EBCDIC (Extended Binary Coded Decimal Interchange Code), code propriétaire IBM utilisé pour ses gros ordinateurs (mainframes).

Le code ASCII est un jeu normalisé de 128 caractères codés sur 7 bits, devenu un standard quasi universel. Il comporte tous les caractères alphanumériques non accentués et est lisible par pratiquement n'importe quelle machine. Ce sont les 8 premières lignes du tableau suivant.

(25)

Les 32 premiers codes sont utilisés comme caractères de contrôle pour représenter, par exemple, une fin de ligne ou une tabulation.

(26)

Le code ASCII ne contient pas de caractères accentués et il a été complété par le code ISO- 8859-1 (ou Latin 1). Ce n’est hélas pas le seul. Les 128 premiers caractères correspondent au code ASCII, les 128 suivants aux caractères accentués et caractères spéciaux (voir les 8 dernières lignes du tableau).

Unicode est un jeu de caractères codé sur 16 bits (contre 7 ou 8 bits pour les standards anciens) qui permet le codage des caractères utilisés par toutes les langues du monde au sein d'une table unique. 16 bits permettent de coder 65 536 (2 puissance 16) caractères différents ce qui couvre largement les besoins en la matière. Unicode est supporté par tous les sytèmes d’exploitations « modernes ». Les 256 premiers caractères d'Unicode correspondent au jeu ISO Latin 1.

Un fichier texte comporte un caractère spécial EOL (End Of Line) pour signaler la fin d’une ligne. Ce caractère est différent suivant que le fichier est créé sous Unix ou bien sous Windows.

Fin de ligne Unix 0x0A (line feed)

Fin de ligne Windows 0x0D 0x0A (carriage return, line feed)

C’est une des principales sources d’incompatibilité aux transferts de fichiers entre les deux mondes.

Exercice 1.4 :

1) Sous Unix, donnez le fichier texte correspondant aux octets suivants : 43 0A 4F 0A 55 0A 43 0A 4F 0A 55 0A.

2) Sous Windows, donnez les octets correspondant au fichier précédent.

(27)

2. Langages de programmation 2.1 Définitions

Langage machine Langage assembleur

Langage évolué

ordinateur homme

compilateur

assembleur

• Langage machine. L’ordinateur ne sait exécuter qu’un nombre limité d’opérations élémentaires codées en binaire. C’est le langage machine. Les instructions sont généralement codées avec un ou plusieurs octets.

• Langage assembleur (ou d’assemblage). Quand le programmeur veut écrire en langage machine, au lieu d’écrire directement les instructions en binaire, il utilise un langage un peu plus parlant quoique strictement équivalent, le langage assembleur. Celui-ci traduit les codes binaires par des mnémoniques. Chaque microprocesseur a son propre langage assembleur. Les langages machine et assembleur possèdent pratiquement les mêmes instructions.

ADD A, B ≡ additionner (code 0101) les valeurs A (adresse mémoire 010010) et B (adresse mémoire 010011) ≡ 0101010010010011.

• Langage évolué. C’est un langage général utilisable sur n’importe quel ordinateur. Il y en a plusieurs : fortran, pascal, basic, C/C++, ADA, java, … Exemple :

Y = A*X + 2*B + C

à partir des variables A, B, C et X, cette instruction calcule l’expression mathématique et range le résultat dans Y. Pour calculer le même genre d’instruction en assembleur, il faudrait beaucoup d’instructions élémentaires (d’autant qu’il n’y généralement pas de multiplication native dans un microprocesseur).

(28)

Dans tous les langages évolués, on trouvera les notions suivantes :

Ö La variable : c’est un nom donné à un emplacement de la mémoire vive destiné à contenir une information. La nature de cette information (entier, caractère, adresse, …) est appelée son type.

Ö L’affectation : elle permet de calculer la valeur d’une expression et de la ranger dans une variable.

Ö Le test conditionnel : il permet de faire un choix du genre « si le cours m’intéresse alors j’écouterai le professeur, sinon je penserai à autre chose ».

Ö La répétition : elle permet d’exécuter une action jusqu’à satisfaire une condition du genre « tant que je ne serai pas suffisamment bon en C, je travaillerai le cours de programmation ».

2.2 Méthodologie pour l’écriture d’un programme

problème

analyse

programmation

Compilation/assemblage

Edition de liens

tests

programme exécutable algorithme

programme en langage évolué

programme en langage machine

(29)

L’analyse du problème commence en général par une réécriture du problème sous une forme textuelle précise ou bien mathématique. On passe ensuite à l’écriture de l’algorithme.

Définition : un algorithme est une suite finie de règles à appliquer dans un ordre déterminé à un nombre fini de données pour arriver, en un nombre fini d'étapes, à un certain résultat, et cela indépendamment des données. Un algorithme est donc une suite finie d'instructions qui sert à réaliser un travail, un peu à la manière d’une recette de cuisine.

En règle générale, un algorithme doit tenir sur une page. Si tel n’est pas le cas, il faut le diviser en plusieurs parties indépendantes à l’aide de fonctions de façon à ce que chaque partie tienne sur une page. On peut l’écrire de deux manières :

• A l’aide d’un langage algorithmique (ou un langage de programmation comme le C),

• A l’aide d’un ordinogramme.

Dans ce cours, nous commencerons l’écriture des algorithmes avec un langage algorithmique simplifié (voir sa définition au §3.16), puis nous passerons progressivement au langage C dès que nous aurons vu sa syntaxe. Nous n’utiliserons les ordinogrammes qu’à titre d’exemple dans les deux exercices suivants.

Exercice 2.1 : calcul de la somme des N premiers nombres entiers. On dispose d’une fonction LireEntier() qui permet de lire la valeur de N au clavier.

Exercice 2.2 : calcul de la moyenne de N notes. On dispose de la fonction LireEntier() qui permet de lire la valeur de N ainsi que la valeur d’une note au clavier.

2.3 Le langage C

Le langage C a été inventé vers 1972 pour réécrire Unix dans un langage évolué et le porter sur d’autres machines que le PDP 7 pour laquelle il avait été écrit à l’origine en assembleur.

Le langage C a été normalisé ANSI en 1988 (le C pré-ANSI est appelé le C Kernighan et Ritchie ou K&R ou encore compatible).

(30)

C’est un langage qui, par ses origines, est assez proche du matériel et donc bien adapté à l’électronique. C’est un langage :

Evolué : il dispose des structures de contrôle d’un langage évolué ainsi que de la récursivité.

Impératif : il faut déclarer les variables (et leur type) et les fonctions avant de pouvoir les utiliser.

Modulaire : le programme peut être découpé en modules indépendants qui seront compilés séparément. C’est l’édition de liens qui regroupe les morceaux et crée l’exécutable.

Compilé : par opposition avec un langage interprété qui n’est pas traduit en langage machine.

Lors de l’exécution d’un programme interprété, un programme spécialisé, l’interpréteur, se charge d’exécuter les instructions du langage sur une machine donné. Le langage compilé est beaucoup plus rapide que le langage interprété.

Efficace : comme il est assez proche de l’ordinateur, le compilateur peut assez facilement optimiser le code machine pour qu’il soit le plus rapide possible. Il est peu probable qu’un programmeur humain écrive en assembleur un programme plus rapide qu’en C (sauf pour un microprocesseur spécialisé de type DSP).

Très permissif : contrairement à Pascal ou à Fortran, le C permet d’écrire des absurdités que le compilateur ne verra pas, notamment dans les opérations arithmétiques. Tout est permis, le programmeur est supposé savoir ce qu’il fait ! ! !

Nous allons maintenant voir comment on définit en langage C : Ö les variables,

Ö les affectations,

Ö les entrées-sorties (clavier, écran), Ö les structures de choix,

Ö les structures de répétition conditionnelle.

Avec ces éléments, vous serez à même d’écrire des programmes élémentaires.

(31)

3. Bases du langage C

3.1 Les variables

Une variable est un nom qui sert à repérer un emplacement en mémoire, dont on peut faire évoluer la valeur au fil du déroulement du programme. Les noms de variables sont sensibles à la casse. Les caractères qui les composent doivent être choisis parmi les 26 lettres majuscules et minuscules de l’alphabet, les chiffres de 0 à 9 et l’underscore _. Le premier caractère du nom ne doit pas être un chiffre. Il ne doit pas y avoir d’espace ni de caractères accentués dans le nom. Le compilateur traite les noms de variable jusqu’à 32 caractères.

Noms corrects : A, A1, n_1, racine_carree

Noms incorrects : 1a, nombre 1, racine_carrée, nombre-1

Une variable peut contenir plusieurs types de données : nombre entier, nombre réel, caractère,

⇒ Il faut donc spécifier le type de la variable lors de sa déclaration.

A chaque type de variable correspond un nombre d’octets destinés à stocker un nombre limité de valeurs différentes. Exemple :

Un entier non signé (>0) est stocké à l’aide de 4 octets et donc sa valeur est comprise entre 0 et 232-1 (soit 4 294 967 295).

Exemple de types : 1) int = nombre entier, 2) float = nombre réel, 3) char = caractère.

Exemples de déclaration : int n, p;

float valeur, X1, X2;

char reponse;

(32)

Vous devez écrire vos instructions de déclaration avant les instructions d’exécution.

Le compilateur réserve un emplacement mémoire pour la variable, mais cet emplacement n’est pas initialisé. Vous ne pouvez prévoir quelle valeur sera stockée dans la variable si vous ne l’initialisez pas vous-même. Deux méthodes :

Ö Au moment de la déclaration.

int n = 0, p = 100;

Ö Dans le programme avant sa première utilisation.

int n;

n = 0;

3.2 L’instruction d’affectation

L’instruction d’affectation a pour rôle :

1) de calculer la valeur de l’expression figurant à droite du signe =, 2) de ranger le résultat dans la variable se trouvant à gauche du signe =.

Exemple : int n, p;

n = 10;

p = 2*n – 3;

instructions n p commentaire

déclaration - - les variables ne sont pas initialisées n = 10 ; 10 - affectation d’une constante p = 2*n – 3 ; 10 17 calcul de l’expression puis affectation

C’est après l’exécution de l’instruction que la variable à gauche du signe = change de valeur.

Attention à ne pas confondre l’affectation avec l’égalité mathématique.

(33)

Exemple 1 : a = b;

Mathématiquement, cette expression signifie que a est égal à b pendant toute la durée du problème.

En informatique, cette expression signifie que a prend la valeur de b au moment de l’exécution de l’instruction.

⇒ en informatique, a = b; n’est pas équivalent à b = a; (alors que c’est la même chose en mathématique)

Exemple 2 :

instructions a b commentaire

déclaration - - les variables ne sont pas initialisées

a = 5 ; 5 - affectation d’une constante

b = a + 1; 5 6 l’action de cette instruction est purement instantanée (au moment de son exécution)

a = 2; 2 6 le changement de la valeur de a n’affecte plus b (qui ne passe pas à 3)

Exemple 3 : a = a + 1;

Mathématiquement, cette expression n’a pas de sens.

En informatique, cette expression signifie que la nouvelle valeur de a (après exécution de l’instruction) est égale à l’ancienne valeur de a (avant exécution de l’instruction) + 1. C’est une incrémentation.

(34)

Exemple 4 : a + 5 = 3;

Mathématiquement, cette expression a un sens. C’est une banale équation.

En informatique, cette expression est fausse. On ne peut attribuer une valeur qu’à une variable et pas à une expression.

Exercice 3.1 : remplir les tableaux suivants.

instructions a b commentaire

déclaration a = 5 ;

b = a + 4;

a = a + 1;

b = a - 4;

instructions n1 n2 commentaire

déclaration n1 = 5 ;

n2 = 7 ; n1 = n2;

n2 = n1;

instructions n1 n2 commentaire

déclaration n1 = 5 ;

n2 = 7 ; n2 = n1;

n1 = n2;

(35)

Exercice 3.2 : soit trois variables entières. Compléter le programme suivant pour permuter leurs valeurs, de telle sorte que a → b, b → c et c → a.

main() {

int a = 1, b = 2, c = 3, tmp;

/* à compléter */

printf("a = %d, b = %d, c = %d\n ", a, b, c);

}

3.3 Les types entier

Les types entiers permettent de représenter une partie des nombres entiers naturels et relatifs :

type nombre de bits intervalle

unsigned short int 16 0 à (216-1 = 65535)

short int 16 (-215=-32768) à (215-1 = 32767)

unsigned long int 32 0 à (232-1= 4 294 967 295)

long int 32 (-231=-2 147 483 648) à (231-1 = 2 147 483 647) int 32* (-231=-2 147 483 648) à (231-1 = 2 147 483 647)

* : le type int dépend du compilateur utilisé qui est généralement lié au système d’exploitation (ou au compilateur). Sur un système 32 bits, il est généralement codé sur 32 bits. Il est préférable de spécifier short ou long sinon le comportement de vos programmes changera avec la machine cible (absence de portabilité).

Les nombres signés utilisent le codage en complément à 2. Les constantes de type int s’écrive comme en mathématique :

short int n, o, p;

n = 10;

o = +15;

p = -2542;

(36)

Les opérateurs mathématiques sont de deux types : les opérateurs unaires qui ne portent que sur un terme et les opérateurs binaires qui portent sur deux termes.

symbole opération

+, - addition, soustraction

* multiplication

/ division entière

% reste de la division entière (modulo) - opérateur unaire de négation (ex : -b;)

Lorsque plusieurs opérateurs apparaissent dans une même expression, le compilateur respecte des règles de priorités qui sont celles de l’algèbre traditionnelle.

priorité symbole commentaires

max - (négation)

moy *, /, % en cas d’égalité, le calcul s’effectue de gauche à droite min +, - en cas d’égalité, le calcul s’effectue de gauche à droite

En utilisant des parenthèses, vous pouvez outrepasser ces règles de priorité en forçant le calcul préalable de l’expression qu’elles contiennent.

Exercice 3.3 : quelles sont les valeurs des expressions suivantes ?

main() {

int n = 8, p = 13, q = 29, result;

result = n + p / q;

printf("resultat = %d\n ", result);

result = n + q / p;

printf("resultat = %d\n ", result);

(37)

result = (n + q) / p;

printf("resultat = %d\n ", result);

result = n + p % q;

printf("resultat = %d\n ", result);

result = n + q % p;

printf("resultat = %d\n ", result);

result = (n + q) % p;

printf("resultat = %d\n ", result);

result = n + p / n + p;

printf("resultat = %d\n ", result);

result = (n + p) / (n + p);

printf("resultat = %d\n ", result);

}

3.4 Les types flottants (réels)

Les types flottants permettent de représenter, de manière approchée, une partie des nombres réels. La valeur d’un réel ne peut être ni trop grande, ni trop petite, ni trop précise. Le codage en binaire est de la forme :

signe exposant (signé) mantisse (non signée)

type nombre de bits format valeur max (valeur min*)

précision max

float 32 1 + 8 + 23 2128 ≈ 10+38 2-23 ≈ 10-7 double 64 1 + 11 + 52 21024 ≈ 10+308 2-52 ≈ 10-15 long double 80 1 + 15 + 64 216384 ≈ 10+4932 2-64 ≈ 10-19

* : la valeur min se détermine à partir de la valeur max (ex : max = 10+38 ⇒ min = 10-38)

Les flottants s’écrivent en C sous la forme : mantisse + exposant (avec un point décimal et pas une virgule) tels que :

+4.25E+4 ou encore -58.0e-25

(38)

C’est la notation scientifique traditionnelle comme sur une calculatrice. Le E signifie 10 puissance. Les constantes de type flottant s’écrivent sous la forme :

float n, o, p;

n = 12.43;

o = -0.38e-33;

p = -4.0;

On retrouve les mêmes opérateurs binaires (portant sur 2 termes) que pour les entiers (sauf le

%) ainsi que l’opérateur unaire de négation. Les règles de priorité restent les mêmes.

Attention : l’expression 5/2 sera calculée en entier (résultat = 2) même si le résultat est rangé dans un flottant. Il faut utiliser 5./2. pour obtenir 2,5.

main() {

float p;

p = 5/2;

printf("resultat = %f\n",p);

p = 5.0/2.0;

printf("resultat = %f\n",p);

}

3.5 Les conversions de type

En C, vous pouvez mélanger dans une expression des variables de types différents sans effectuer aucune conversion contrairement au langage Pascal où la conversion est obligatoire (le langage est dit fortement typé). La conversion en C est implicite (elle est effectuée automatiquement par le compilateur) alors qu’elle est explicite en Pascal, en Fortran ou en Ada.

Le compilateur C réalise automatiquement la conversion de type en respectant : 1) la règle de priorité des opérateurs,

2) la règle « du type le plus petit (en nombre d’octets) vers le type le plus grand » (c’est la règle la moins dégradante pour les données). En général, tous les types plus petits qu’un int sont systématiquement convertis en int avant toute autre conversion.

(39)

Exemple : int n, p;

float x, y;

Dans l’expression y = n + x, n est d’abord converti en flottant puis l’addition est effectuée en flottant et le résultat est rangé dans le flottant y.

Dans l’expression y = n*p + x, n*p est calculé en entier, le résultat est converti en flottant puis additionné à x en flottant et le résultat est rangé dans y.

Exercice 3.4 : soient les instructions suivantes.

int n, p;

float x;

n = 10;

p = 7;

x = 2.5;

Donnez le type et la valeur des expressions suivantes : x + n % p;

x + n / p;

(x + n) / p;

5. * n;

(n + 1) / n;

(n + 1.0) / n;

Il est à noter que la conversion d’int vers float est non dégradante (on ne perd rien dans la conversion) alors que la conversion float → int est dégradante (on prend la partie entière du réel que l’on met dans l’entier, la partie fractionnaire est perdue).

Il est possible de convertir explicitement une expression grâce à un cast en mettant l’expression entre parenthèse et en la précédant de (type). Par exemple :

x + (float)n/p;

(40)

Exercice 3.5 : quels résultats donne le programme suivant ?

main() {

int n=15, p=4;

float x;

x = n/p;

printf("resultat = %f\n",x);

x = (float)n/p;

printf("resultat = %f\n",x);

x = (float)(n/p);

printf("resultat = %f\n",x);

}

Une règle élémentaire de prudence consiste à ne jamais mélanger des types signés avec des types non signés car les conversions n’ont généralement pas de sens. Si vous introduisez une variable non signée dans une expression signée, utilisez un cast (exemple typique, un indice de boucle).

main() {

long int n=-15, p; /* signé */

unsigned long int x; /* non signé */

...

p = n + (long int)x;

...

}

3.6 Les types char

Les types char permettent de coder des caractères en utilisant le code ASCII. Mais ils peuvent aussi être utilisés comme des petits entiers signés ou non signés ou bien directement en binaire si le programme travaille sur des octets.

type nombre de bits intervalle

unsigned char 8 0 à (28-1 = 255) char 8 (-27=-128) à (27-1 = 127)

(41)

Les constantes de type char s’écrivent sous la forme :

char n, o, p;

n = ‘s’; /* un caractère normal */

o = 100; /* un petit entier */

p = ‘\n’; /* le caractère spécial line feed */

p = 0x0A ; /* toujours un line feed */

Les caractères imprimables sont simplement écrits entre quotes et les caractères spéciaux utilisent l’antislash (backslash).

Tout ce qui s’applique aux types entiers s’applique aux types char (opérateurs, priorités, conversions). C’est une des grandes qualités du C (mais c’est aussi un défaut) de pouvoir effectuer des opérations arithmétiques avec des variables de type char. Les possibilités de confondre caractères et petits entiers sont nombreuses.

Exemple : main() {

char n;

n = 'A';

printf("Caractere = %c\n",n);

printf("Code ASCII en hexadecimal = %x\n",n);

printf("Code ASCII en decimal = %d\n",n);

}

Exercice 3.6 : soient trois variables c1, c2 et c3 de type char. Ecrivez un programme permettant de permuter le contenu de ces variables.

3.7 Communiquer avec le programme : les entrées-sorties standard

La manière la plus simple de lire un caractère à la fois sur l’entrée standard (qui est normalement le clavier) est d’utiliser la fonction getchar :

(42)

int getchar(void)

type de la variable d’entrée type de la variable de sortie

Cette fonction n’accepte en entrée aucune variable (entrée de type void qui veut dire vide) et retourne un entier (type int) dont la valeur est égale au code ASCII du caractère tapé au clavier suivi d’un « retour chariot ».

Pour la sortie d’un caractère, on utilise la fonction putchar :

int putchar(int)

Cette fonction accepte un entier en entrée (celui retourné par getchar() par exemple) et retourne un entier (type int). putchar(c) envoie le caractère c sur la sortie standard (l’écran par défaut) et retourne le caractère écrit ou -1 en cas d’erreur.

Exemple 1 : ce programme accepte un caractère en entrée puis le restitue en sortie.

#include <stdio.h> /* déclaration de fonctions getchar et putchar */

main() {

int c;

c=getchar();

putchar(c);

}

Exemple 2 : ce programme accepte un caractère en entrée puis le restitue en sortie et recommence tant que vous ne tapez pas Ctrl-d pour sortir de la boucle (Ctrl-z sous Windows).

#include <stdio.h>

main() {

(43)

int c;

c=getchar();

while (c != EOF) {

putchar(c);

c=getchar();

} }

Sous Unix, on peut rediriger la sortie standard (StdOut) d’un programme (l’écran par défaut) vers un fichier grâce à la commande :

prog > sortie.txt

Mais il est aussi possible de remplacer le clavier comme entrée standard (StdIn) par un fichier en utilisant la commande :

prog < entree.txt

De plus, il existe encore une autre sortie, la sortie des erreurs (StdErr, par exemple les messages d’erreurs du compilateur), qui peut être redirigée vers un fichier grâce à :

prog 2> error.txt

ou bien vers le même endroit que la sortie standard en tapant :

prog 2>&1

C’est grâce aux entrées-sorties standards que le pipe fonctionne. Quand on tape :

prog1 | prog2

on redirige la sortie standard de prog1 vers l’entrée standard de prog2 (le pipe « branche » StdOut1 sur StdIn2).

(44)

Reprenons l’exemple 2. Si vous créez avec un éditeur un petit fichier texte (entree.txt) comportant des lettres majuscules et minuscules ainsi que des chiffres puis que vous tapez la commande suivante :

exemple2 < entree.txt > sortie.txt

Vous obtenez un fichier sortie.txt identique à entree.txt. Ainsi, la fonction getchar() peut accepter un flot de texte issu d’un fichier plutôt qu’un seul caractère au clavier et la fonction putchar peut renvoyer un caractère dans un fichier.

Exemple 3 : le programme suivant accepte un caractère en entrée puis le restitue en sortie mais converti en minuscule et recommence tant que vous ne tapez pas Ctrl-d pour sortir de la boucle (en manuel au clavier) ou tant que le programme n’a pas atteint la fin du fichier EOF (pour une entrée via un fichier). La fonction tolower est définie dans ctype.h. Elle convertit les lettres majuscules en minuscules et retourne les autres caractères tels quels.

#include <stdio.h>

#include <ctype.h>

main() {

int c, cm;

c=getchar();

while (c != EOF) {

cm = tolower(c) ; putchar(cm);

c=getchar();

} }

Cet exemple fonctionne aussi bien au clavier qu’avec le fichier entree.txt.

Il existe en C des instructions plus sophistiquées pour afficher du texte à l’écran ou bien pour lire du texte à partir du clavier : printf et scanf.

(45)

3.8 L’instruction printf

Nous avons déjà vu à plusieurs reprises des exemples simples de cette instruction : int n=10, p=25;

printf("nombre : %d, valeur %d ", n, p);

On a entre double quotes ("") soit du texte, soit un ou plusieurs codes de format (%d) qui seront remplacés par la valeur d’une ou de plusieurs variables lors de l’affichage. On trouve ensuite les variables à afficher séparées par une virgule. Il doit y avoir autant de codes de format que de variables à afficher. Il existe de nombreux codes de formats (%d correspond à un entier) pour tous les types de variables. Ils commencent tous par un %. Tout ce qui n’est pas un code de format mais qui se trouve entre doubles quotes est affiché tel quel.

On peut omettre les codes de format pour afficher seulement du texte : printf("bonjour");

Il est possible, quoique non recommandé, de remplacer une variable par une expression : printf("la somme de %d et de %d est %d", n, p, n+p);

Le code de format %c permet d’afficher un caractère : int n=10;

char c=’c’;

printf("nombre : %d, caractère %c ", n, c);

Le code de format %e permet d’afficher un nombre flottant en notation exponentielle et le code %f permet d’afficher un nombre flottant en notation décimale.

float x=1.23456e4;

printf("notation exp : %e, notation déc %f ", x, x);

Le formatage des données permet de contrôler le nombre de chiffres affichés à l’écran. Dans ce texte, le caractère ^ sert à matérialiser un espace lors de l’affichage. En insérant un nombre dans le code de format après le %, on précise le gabarit d’affichage, c’est-à-dire le nombre minimal de caractères à utiliser pour afficher la valeur du nombre. Si le nombre peut s’afficher avec moins de caractères, printf le fera précéder d’un nombre suffisant d’espaces. Par contre, si le nombre nécessite plus de caractères pour s’afficher que vous en avez spécifiés, printf utilisera le nombre de caractères nécessaire. Exemples :

(46)

printf("%3d", n);

valeur affichage

n = 20 ^20

n = 3 ^^3

n = -5 ^-5

n = 2358 2358

n = -5200 -5200

printf("%10f", x);

valeur affichage

x = 1.2345 ^^1.234500

x = 12.345 ^12.345000

x = 1.2345E5 123450.00000

Par défaut, les flottants sont affichés avec 6 chiffres à droite du point décimal. Dans l’exemple précédent, %10f signifie « en utilisant 10 caractères (y compris le .) avec au moins 6 chiffres après le point ». Il est possible de modifier ce nombre est écrivant %A.Bf qui signifie « au minimum A caractères dont au moins B après le point décimal ». Exemples :

printf("%10.3f ", x);

valeur affichage

x = 1.2345 ^^^^^1.234

x = 1.2345E3 ^^1234.500

x = 1.2345E7 12345000.000

(47)

printf("%12.4e", x);

valeur affichage

x = 1.2345 ^^1.2345e+00

x = 123.456789E8 ^^1.2345e+10

Chaque instruction printf affiche ses informations à la suite de celles qui ont déjà été affichées par un printf précédent, ce qui revient à dire qu’il n’y a pas de passage à la ligne entre deux printf. Exemple :

int n=10;

char c=’c’;

printf("nombre : %d, ", n);

printf("caractère %c", c);

Les deux printf précédent affichent exactement la même chose que le printf suivant : printf("nombre : %d, caractère %c", n, c);

Le changement de ligne est réalisé avec le caractère non imprimable \n placé au milieu ou à la fin d’un printf :

printf("nombre : %d\ncaractère %c", n, c);

Il est aussi possible d’afficher une tabulation avec \t comme dans : printf("\n\tTerminé\n\n");

Exercice 3.7 : soient les déclarations : int qte=50;

char cat=’B’;

char art=’S’;

Ecrivez le programme permettant d’afficher les variables de la manière suivante : 50 articles S, de la catégorie B

Quel sera le résultat si art est déclarée de la manière suivante : char art=’\n’;

(48)

Exercice 3.8 : écrivez le programme qui calcule le prix TTC d’un nombre donné d’articles d’un prix unitaire égal à 10.51 euros, compte tenu d’un taux de TVA de 19,6 %. Les résultats seront affichés de la manière suivante :

nombre d'articles : 15 prix unitaire HT : 10.51 prix total TTC : 188.55

3.9 L’instruction scanf

La lecture au clavier d’un entier que l’on range dans la variable n s’écrit en langage C : scanf("%d", &n);

Lorsque le programme exécute cette instruction, il attend que vous tapiez une valeur au clavier suivie d’un retour chariot (↵). Le format (entre " ") est similaire à celui de l’instruction printf, mais on voit que la variable est spécifiée par &n (et pas seulement n). Le & qui précède n signifie « adresse de n ». Par contre, le gabarit, comme %3d, est interdit. Exemples d’entrées entières :

12 ↵ 0 ↵ -1 ↵ +1234 ↵

La lecture d’un nombre flottant s’effectue avec l’instruction suivante : scanf("%f", &x);

scanf("%e", &x);

Les codes %e et %f jouent strictement le même rôle. Exemples d’entrées flottantes : -12 ↵

0.5 ↵ -1. ↵

+1.2e-4 ↵ 32e45 ↵

Attention : il ne faut pas placer de texte avant ou après le code de format ni même d’espace.

L’instruction suivante n’est pas légale :

scanf("Entrez une valeur : %f", &x);

(49)

Il faut écrire :

printf("Entrez une valeur : ");

scanf("%f", &x);

Si vous souhaitez lire deux valeurs numériques sur la même ligne, vous pouvez utiliser l’instruction (sans aucun espace entre les ") :

scanf("%d%d", &n, &p);

Les deux valeurs doivent être saisies au clavier séparées par au moins un espace.

12^-15 ↵

L’entrée suivante est identique à la précédente car les codes de format %d ou %f sautent tous les blancs qui précèdent une valeur.

^^^12^^^-15 ↵

Exercice 3.9 : modifiez le programme de l’exercice 3.8 afin de pouvoir saisir le nombre d’articles et le prix unitaire.

Attention : lorsque l’utilisateur fournit trop peu de données, scanf continue d’attendre les données suivantes. Exemple :

scanf("%d%d", &n, &p);

L’entrée 12^-15 ↵ donnera le même résultat que 12 ↵ suivi de -15 ↵. Supposons qu’à cette même instruction, vous fournissiez :

12^-15^1254 ↵

Il y a maintenant trop de données. scanf va mettre bien 12 dans n, -15 dans p mais il va garder 1254 en mémoire dans le buffer clavier pour la prochaine lecture avec scanf. En cas de besoin, vous pouvez purger le buffer clavier à l’aide de l’instruction :

fflush(stdin);

Le code de format %c permet de lire un caractère. Ainsi, l’instruction suivante :

(50)

char c1 ; ...

scanf("%c", &c1);

lit un caractère au clavier et le range dans c1. Si vous souhaitez lire plusieurs caractères à la suite, il suffit de les taper successivement et de les faire suivre d’un retour chariot. Exemple : scanf("%c%c%c", &c1, &c2, &c3) ;

Avec l’entrée : abc↵

a est rangé dans c1, b dans c2 et c dans c3. L’espace n’est en aucun cas un séparateur comme pour les nombres. C’est un caractère comme un autre. Si vous tapez :

a^bc↵

a va dans c1, un espace va dans c2, b va dans c3 et c est disponible pour la lecture suivante.

En règle générale, évitez de lire plusieurs valeurs (numériques ou caractères) avec une même instruction scanf.

Exercice 3.10 : modifiez le programme de l’exercice 3.7 afin de pouvoir saisir le nom de l’article, sa catégorie ainsi que la quantité.

3.10 Structure de choix : l’instruction if

L’instruction if permet de réaliser des choix dans un programme comme le montre l’exemple suivant :

main() {

int n, p;

printf("Donnez deux nombres entiers : ");

scanf("%d%d", &n, &p);

(51)

if (n < p)

printf("croissant\n");

else

printf("non croissant\n");

printf("au revoir\n");

}

Sa compréhension est assez intuitive. Si n < p, alors on exécute l’instruction : printf("croissant\n");

sinon on exécute l’instruction :

printf("non croissant\n");

Dans tous les cas, on exécute la dernière instruction du programme : printf("au revoir\n");

Le compilateur se moque de la présentation des instructions. Ainsi, la forme : if (n < p)

printf("croissant\n");

else

printf("non croissant\n");

est strictement équivalente à :

if (n < p) printf("croissant\n"); else printf("non croissant\n");

Mais il est fortement conseillé d’utiliser la première forme pour une meilleure lisibilité du programme et donc une maintenance plus facile.

Dans l’exemple précédent, chacune des deux parties du choix se limite à une instruction (printf). Il est possible d’en placer plusieurs à condition de les placer dans un bloc entre {}. Voyons une nouvelle version de notre exemple :

main() {

int n, p, maxi;

printf("Donnez deux nombres entiers : ");

scanf("%d%d", &n, &p);

(52)

if (n < p) {

maxi = p;

printf("croissant\n");

}

else {

maxi = n;

printf("non croissant\n");

}

printf("Le plus grand des deux nombres est : %d\n", maxi);

}

L’instruction if correspond maintenant à : if (n < p) bloc_instructions_1 else bloc_instructions_2

ce qui équivaut dans notre exemple à : si n < p alors maxi prend la valeur de p et printf sinon maxi prend la valeur de n et printf.

Les blocs d’instructions peuvent contenir n’importe quelles instructions du C y compris d’autres instructions if. Un bloc peut ne contenir qu’une seule instruction :

if (n < p) {

printf("croissant\n");

}

ou bien une instruction vide (parfaitement légale en C) : if (n < p) {

; }

ou bien aucune instruction : if (n < p) {

}

Il est possible d’avoir un bloc dans le if et une instruction dans le else : if (n < p) {

maxi = p;

printf("croissant\n");

} else

printf("non croissant\n");

ou le contraire.

(53)

if (n < p)

printf("croissant\n");

else {

maxi = n;

printf("non croissant\n");

}

La branche else de l’instruction if n’est pas obligatoire. Ainsi, l’enchaînement : if (n < p)

printf("croissant\n");

printf("au revoir\n");

est tout à fait acceptable. Si n < p, le programme exécute le printf. Dans tous les cas, le dernier printf est exécuté. Cette remarque est aussi valable avec un bloc d’instructions : if (n < p) {

maxi = p;

printf("croissant\n");

}

printf("au revoir\n");

D’une manière générale, l’instruction if se présente de la manière suivante (La branche else est optionnelle) :

if (condition)

instruction_1 [else

instruction_2]

où instruction_1 et instruction_2 sont :

• une instruction simple (terminée par un ;),

• une instruction structurée (comme un autre if),

• un bloc d’instructions entre {}.

Voyons maintenant la condition plus en détail.

3.11 Structure de choix : les conditions en C

Les opérateurs de comparaisons ont deux significations suivant qu’ils s’appliquent à deux types numériques (float ou int) ou à deux types caractères (char) :

Références

Documents relatifs

Dans les précédentes versions de ce tutoriel, je présentais une fonction Trace, mais après réflexion, il me semble plus propre de vous montrer la solution objet, même si elle

Il ne nous reste plus qu’à savoir comment appeler cet appel système en langage d’assemblage.. i

• Nous ´ etudierons la coexistence d’un syst` eme large bande de type FBMC-OQAM avec des syst` emes bande ´ etroite en pr´ esence d’AP non lin´ eaires,.. • Nous proposerons

RÉPUBLIQUE DE DJIBOUTI Abdourahman Houssein DJAMA Centre de formation continue Université de Djibouti. Campus de Balbala, Croisement RN2-RN5,

Un fichier objet (extension .o sous Linux, .obj sous Windows) contient les instructions en langage machine correspondant au source et des données destinées à l’éditeur

— Sont abrogées toutes les dispositions de loi ou de règlement contraires à la présente loi... Disposition générale de

Si, dans les portées courantes de 40 à 50 mètres, on peut admettre pour les deux métaux des poteaux de m ê m e hauteur, la variation totale de la flèche étant relativement

ïïff 3.. Court-circuit provenant du contact de branches d'arbres, de chutes d'arbres, de chutes de pierres, du contact d'ani- maux, ou du contact direct des fils entre eux.