Vous êtes sur la page 1sur 300

Machine Translated by Google

Machine Translated by Google

S'autoformer

C
24
heures
Tony Zhang

DEUXIÈME ÉDITION

201 West 103rd St., Indianapolis, Indiana, 46290 États­Unis


Machine Translated by Google

Sams enseignez­vous C en 24 heures, ÉDITEUR ASSOCIÉ

Michel Stephens
Deuxième édition
RÉDACTEUR DES ACQUISITIONS

Copyright ©2000 par Sams Publishing Carol Ackermann

Tous les droits sont réservés. Aucune partie de ce livre ne doit être reproduite, stockée ÉDITEUR DE DÉVELOPPEMENT

dans un système de récupération ou transmise par quelque moyen que ce soit, électronique, Gus A Miklos
mécanique, photocopie, enregistrement ou autre, sans l'autorisation écrite de l'éditeur.
DIRECTEUR DE LA RÉDACTION
Aucune responsabilité de brevet n'est assumée en ce qui concerne l'utilisation des informations
Charlotte Clapp
contenues dans ce document. Bien que toutes les précautions aient été prises lors de la
préparation de ce livre, l'éditeur et l'auteur déclinent toute responsabilité en cas d'erreur ou ÉDITEUR DE PROJET

d'omission. De même, aucune responsabilité n'est assumée pour les dommages résultant de Andy Beaster
l'utilisation des informations contenues dans ce document.
ÉDITEUR DE COPIE
Numéro international normalisé du livre : 0­672­31861­x Kate Givens

Numéro de carte de catalogue de la Bibliothèque du Congrès : 99­067311 INDEXEURS

Christine Nelsen
Imprimé aux États­Unis d'Amérique
Déborah Hittel
Première impression : février 2000
RELECTEUR

05 04 03 6543 Candice High Tower

RÉDACTEUR TECHNIQUE
Marques de commerce Bill Mitchell

Tous les termes mentionnés dans ce livre qui sont connus pour être des marques commerciales ou COORDONNATEUR D' ÉQUIPE
des marques de service ont été correctement mis en majuscules. Sams Publishing ne peut attester de Pamalée Nelson
l'exactitude de ces informations. L'utilisation d'un terme dans ce livre ne doit pas être considérée comme
DESIGNER D' INTÉRIEUR
affectant la validité d'une marque commerciale ou d'une marque de service.
Gary Adair

Avertissement et clause de non­responsabilité CONCEPTEUR DE COUVERTURE

Aren Howell
Tous les efforts ont été faits pour rendre ce livre aussi complet et aussi précis que
possible, mais aucune garantie ou adéquation n'est implicite. Les informations fournies COPYWRITER

sont sur une base "telle quelle". L'auteur et l'éditeur déclinent toute responsabilité vis­à­vis Eric Borgert
de toute personne ou entité en cas de perte ou de dommage résultant des informations
ASSISTANTE ÉDITORIALE
contenues dans ce livre.
Angela Boley

PRODUCTION

Stacey De Rome
Marc Walchle
Machine Translated by Google

Sommaire en un coup d'œil


Introduction 1

Partie I Les bases du C 9


Heure 1 Faire le premier pas 11

2 Écrire votre premier programme C 27

3 Apprentissage de la structure d'un programme C 41

4 Comprendre les types de données et les mots­clés 55

5 Gestion des entrées et sorties standard 71

Opérateurs de la partie II et instructions de flux de contrôle 89


Heure 6 Manipulation des données 91

7 Travailler avec des boucles 105

8 Utilisation des opérateurs conditionnels 121

9 Utilisation des modificateurs de données et des fonctions mathématiques 141

10 Contrôle du déroulement du programme 155

Partie III Pointeurs et tableaux 173


Heure 11 Comprendre les pointeurs 175

12 Comprendre les tableaux 189

13 Manipulation des chaînes 207

14 Présentation de la portée et des classes de stockage 223

Partie IV Fonctions et allocation de mémoire dynamique 241

Heure 15 Travailler avec des fonctions 243

16 Application de pointeurs 259

17 Allocation de mémoire 279

18 Utilisation de types de données et de fonctions spéciales 295


Machine Translated by Google

Partie V Structure, Union, E/S de fichiers, etc. 311


Heure 19 Comprendre les structures 313

20 Comprendre les syndicats 333

21 Lire et écrire avec des fichiers 355

22 Utilisation des fonctions de fichiers spéciaux 373

23 Compiler des programmes : le préprocesseur C 391


24 Où allez­vous d'ici? 409

Annexes de la partie VI 437


Annexe A Fichiers d'en­tête standard ANSI 439

B Réponses aux questions et exercices du quiz 441


Indice 503
Machine Translated by Google

Table des matières


Introduction 1

Qui devrait lire ce livre ? .................................................. ...............................1 Particularités


de ce livre ............... .................................................. ................1 Exemples de
programmation .................................. .................................................. .........2 Questions­
réponses et atelier ...................................... .................................................. .........4
Conventions utilisées dans ce manuel .................................. ..................................................4
Ce que vous apprendrez dans 24 heures................................................ ................................4

Partie I Les bases du C 9


Heure 1 Faire le premier pas 11

Qu'est­ce que C? .................................................. .................................................. ........12


La norme ANSI C ...................................... .................................................. ...15 Hypothèses
à votre sujet .................................................. .............................................16 Configuration
de votre système .................................................. .......................................16
Matériel ....... .................................................. ..................................................16
Logiciel.. .................................................. .................................................. ......16 A
Exemple de configuration de programmation C ...................................... ..................................17
Utilisation du compilateur de Microsoft ................ .................................................. ..........18
Utilisation du compilateur de Borland.................................. ..................................................21
Résumé................................................. .................................................. .............24
Questions­réponses .................................... .................................................. ..................................25
Atelier ............... .................................................. ..................................................25
Questionnaire ... .................................................. .................................................. ...........25

Heure 2 Écrire votre premier programme en C 27

Un programme simple en C.................................................. ..................................................28


Commentaires .................................................. .................................................. ..........29
La directive #include .................................................. .................................................. ...31
Fichiers d'en­tête.............................................. .................................................. ........32
Crochets angulaires (< >) et guillemets (" ") .................................. ..................32 La
fonction main() .................................. .................................................. ................33 Le
caractère de saut de ligne (\n) .................................. .................................................. ..33
La déclaration de retour .................................................. ..........................................34
La fonction exit() .. .................................................. .................................. ..34
Compilation et liaison.................................................. ...............................................34
Qu'est­ce qui ne va pas avec Mon Programme ? .................................................. ................36
Débogage de votre programme ....................... .................................................. ............37
Machine Translated by Google

nous Sams, apprenez­vous C en 24 heures

Résumé................................................. .................................................. .............37 Questions­


réponses .................................... .................................................. ..................................38
Atelier ............... .................................................. ..................................................38
Questionnaire ... .................................................. .................................................. ...........38
Des exercices ................................................. .................................................. .......39

Heure 3 Apprentissage de la structure d'un programme en C 41

Les bases d'un programme en C.................................................. .......................................42


Constantes et Variables ...... .................................................. ................................42
Expressions ................................................. .................................................. ...42
Énoncés .................................................. .................................................. .........45
Blocs d'instructions .................................................. ...............................................45
Anatomie d'une fonction C .................................................. ..................................................46
Détermination du type d'une fonction .... .................................................. ..................46
Donner un nom valide à une fonction .................................. .............................................47
Passer des arguments à C Les fonctions ................................................. ..................47
Début et fin d'une fonction .................................. ..................................48 Le corps de la
fonction ........... .................................................. .................................48 Effectuer des
appels de fonction .................. .................................................. .......................49
Résumé.................................. .................................................. .....................................51
Q&R ........... .................................................. .................................................. .......52 Travail
magasin ................................................. .................................................. ...........52
Questionnaire ..................................... .................................................. .......................52
Des exercices ................................................. .................................................. .......53

Heure 4 Comprendre les types de données et les mots­clés 55

Mots­clés C .................................................. .................................................. ........56 Le type


de données char .................................. .................................................. .......57 Variables de
caractères ................................................. .................................................. 58
Constantes de caractères .................................................. .......................................58
Le caractère d'échappement (\) ....................................................... ..................................59
Caractères d'impression ......... .................................................. ...............................60 Le
type de données int .............. .................................................. ................................62
Déclarer des variables entières ............... .................................................. ..............62
Affichage des valeurs numériques des caractères ...................... .......................63 Le
type de données flottant ................................ .................................................. ...................64
Déclarer des variables à virgule flottante ...................... ..........................................64 Le
spécificateur de format à virgule flottante ( %f) ....................................................... .........65
Le double type de données .................................. .................................................. ....67
Utilisation de la notation scientifique ions .................................................. .....................................67
Nommer une variable ......... .................................................. .......................................68
Résumé.......... .................................................. .................................................. ...68
Questions­réponses ............................................. .................................................. .......................68
Machine Translated by Google

Contenu vii

Atelier ................................................. .................................................. ...........69


Questionnaire ....................................... .................................................. ................................69
Des exercices ................................................. .................................................. .......70

Heure 5 Manipulation des entrées et sorties standard 71

Présentation des E/S standard .................................................. ..................................72


Obtenir l'entrée de l'utilisateur ......... .................................................. .......................72
Utilisation de la fonction getc() .................. .................................................. ........72
Utilisation de la fonction getchar() .................................. .....................................74
Impression de la sortie à l'écran ....... .................................................. .....................75
Utilisation de la fonction putc() ...................... .................................................. ......75
Une autre fonction d'écriture : putchar() ...................................... ....................77 Revisiter
la fonction printf() ................................ .................................................. 78 Conversion en
nombres hexadécimaux ................................................. ..................................79
Spécification de la largeur de champ minimale... .................................................. .........81
Alignement de la sortie .................................. .................................................. ........83
Utilisation du spécificateur de précision ...................................... .....................................84
Résumé ........... .................................................. .................................................. .85
Questions­réponses ............................................... .................................................. .....................86
Atelier ................................ .................................................. ..................................86
Questionnaire ............... .................................................. ..................................................87
Des exercices ................................................. .................................................. .......87

Opérateurs de la partie II et instructions de flux de contrôle 89

Heure 6 Manipulation des données 91

Opérateurs d'affectation arithmétique .................................................. ..................................92


L'opérateur d'affectation (=) .................. .................................................. ......92
Combinaison d'opérateurs arithmétiques avec =......................................... ....................92
Obtention de négations de valeurs numériques ...................... ..................................................95
Incrémentation ou décrémentation d'un .. .................................................. ............96
Supérieur ou Inférieur à ? .................................................. ..................................98
Utilisation de l'opérateur Cast .................................................. .......................................101
Résumé........ .................................................. .................................................. ..102
Questions­réponses ............................................... .................................................. ....................102
Atelier ................................ .................................................. ..................................103
Questionnaire .................. .................................................. ..................................................103
Des exercices ................................................. .................................................. .....103

Heure 7 Travailler avec des boucles 105

La boucle while ....................................................... .................................................. .106 La


boucle do­while .................................................. .................................................. .107
Bouclage sous l' instruction for .................................................. ..................................109
Machine Translated by Google

viii Sams, apprenez­vous C en 24 heures

La déclaration nulle .................................................................. ...............................................112

Utilisation d'expressions complexes dans une instruction for .......................................... .113


Utilisation de boucles imbriquées .................................................. ...............................................116
Résumé. .................................................. .................................................. .........118 Questions et
réponses ....................................... .................................................. ..................................118
Atelier ..................... .................................................. .....................................119
Questionnaire ........... .................................................. .................................................. .119
Des exercices ................................................. .................................................. .....120

Heure 8 Utilisation des opérateurs conditionnels 121

Tailles des données de mesure .................................................. .......................................122 Tout est


logique ... .................................................. .....................................124 L'opérateur ET logique
(&&) ..... .................................................. .............124 L'opérateur logique OU
(||) ................................ ..........................................126 L'opérateur de NÉGATION logique
(!) .................................................. ........128 Manipulation de
bits ....................................... .................................................. .......129 Conversion de décimal en
hexadécimal ou binaire .................................. ..................129 Utilisation d'opérateurs au niveau du
bit .................. .................................................. ......130 Utilisation des opérateurs de
décalage .................................. .......................................133 Que signifie x?y :z C'est à
dire ? .................................................. ..................................135
Résumé.............. .................................................. ..................................................137 Questions et
réponses .. .................................................. .................................................. ..............137
Atelier .................................. .................................................. .......................138
Questionnaire ................................ .................................................. .......................................138
Des exercices ................................................. .................................................. .....138

Heure 9 Travailler avec des modificateurs de données et des fonctions mathématiques 141

Activation ou désactivation du bit de signe......................................................... ................................142


Le modificateur signé .................................. .................................................. ................142 Le
modificateur non signé .................................. .................................................. ..143 Modification de
la taille des données.............................. ..................................................145 Le modificateur
court .................................................. .......................................145

Le modificateur long .................................................. .......................................145 Ajout de h, l ou L


vers les spécificateurs de format printf et fprintf .................147 Fonctions mathématiques en
C ................ .................................................. ................148

Appel de sin(), cos() et tan() ...................................... ...............................149 Appeler pow() et


sqrt() .......... .................................................. ..................150
Résumé.................................. .................................................. ..................................152 Questions­
réponses .................. .................................................. ..................................................153
Atelier .................................................. .................................................. ........154
Questionnaire .................................................. .................................................. .......................154
Des exercices ................................................. .................................................. .....154
Machine Translated by Google

Contenu ix

Heure 10 Contrôle du déroulement du programme 155

Toujours dire « si… » .................................................................. ...............................................156


Le si­ déclaration d'autre .................................................. ..................................158
Instructions if imbriquées .................................................................. .......................................160
La déclaration de commutateur .................................................. ..................................................161
La déclaration de rupture .................................................. .............................................164

Briser une boucle infinie .................................................................. ..................................166 La


déclaration continue ........ .................................................. ................................167
La déclaration goto .................................................. ...............................................168
Résumé. .................................................. .................................................. .........170 Questions­
réponses ....................................... .................................................. ..................................170
Atelier .................................. .................................................. .....................................171
Questionnaire ........... .................................................. .................................................. .171
Exercices .................................................. .................................................. .......172

Partie III Pointeurs et tableaux 173


Heure 11 Comprendre les pointeurs 175

Qu'est­ce qu'un pointeur ? .................................................. .................................................. .176

Adresse (valeur de gauche) versus contenu (valeur de droite) ...................................... .....176


L'adresse de l'opérateur (&) ..................................... ..................................177 Déclaration de
pointeurs......... .................................................. .....................................179 L'opérateur de
déréférencement (*) ...... .................................................. ................182 Pointeurs
nuls .................................. .................................................. ..................183

Mise à jour des variables via des pointeurs ....................................... ..................................183


Pointer vers le même emplacement de mémoire ...... ...............................................184
Résumé. .................................................. .................................................. .........186 Questions­
réponses ....................................... .................................................. ..................................187
Atelier .................................. .................................................. .....................................188
Questionnaire ........... .................................................. .................................................. .188
Exercices ....................................................... .................................................. .......188

Heure 12 Comprendre les tableaux 189

Qu'est­ce qu'un tableau ? .................................................. .................................................. .190


Déclarer des tableaux .................................................. ...............................................190
Tableaux d'indexation . .................................................. ..................................................190
Initialisation des tableaux .... .................................................. .....................................191 La
taille d'un tableau........ .................................................. ..................................192 Tableaux et
pointeurs............ .................................................. ..................................194 Affichage de tableaux
de caractères ....... .................................................. .....196 Le caractère nul
('\0').......................................... ..................................................198 Tableaux
multidimensionnels .... .................................................. ..................... ..........199
Machine Translated by Google

X Sams, apprenez­vous C en 24 heures

Tableaux non dimensionnés .................................................. .................................................. ..201


Résumé.................................................. .................................................. ..............203
Questions­réponses .................................. .................................................. ................................203
Atelier ................ .................................................. .......................................204
Questionnaire ...... .................................................. .................................................. ......204
Des exercices ................................................. .................................................. .....205

Heure 13 Manipuler des chaînes 207

Déclarer des chaînes .................................................. ..................................................208


Quoi est­ce qu'une chaîne de
caractères ?.................................................. ...............................................208 Initialisation
des chaînes . .................................................. .......................................208 Constantes
de chaîne et constantes de caractère ..... ..................................209 Quelle est la longueur
d'une chaîne ? .................................................. ......................................212 La fonction
strlen() ...... .................................................. ..........................212 Copier des chaînes
avec strcpy() .................. .................................................. ...213 Lecture et écriture de
chaînes .................................................. .....................................215 Les fonctions gets()
et puts() .... .................................................. ............215 Utilisation de %s avec la fonction
printf() ......................... ..................................217 La fonction
scanf() ............ .................................................. .......................217
Résumé.................................. .................................................. ..................................219
Q&R .............. .................................................. .................................................. ..220
Atelier ....................... .................................................. ....................................221 Questionnaire ............. ...............
Des exercices ................................................. .................................................. .....221

Heure 14 Comprendre la portée et les classes de stockage 223

Masquer des données.................................................. .................................................. ........224


Portée du bloc ................................................ .................................................. ...........224
Étendue des blocs imbriqués.............................. .................................................. ...225
Étendue des fonctions .................................................. ..................................................
226 Portée du programme .................................................. ..................................................227
Les spécificateurs de classe de stockage ............................................... ..................................229
Le spécificateur automatique .............. .................................................. ................................229
Le spécificateur statique .................. .................................................. ................230
Étendue du fichier et hiérarchie des étendues .................. ............................. .232 Le
spécificateur de registre .................................................. .....................................233 Le
Prescripteur externe ......... .................................................. ................................233 Les
modificateurs de classe de stockage .................. .................................................. ..........234
Le modificateur const ....................................... .................................................. ..234
Le modificateur volatil .................................................. .......................................235
Résumé................................................. .................................................. ...........236 Questions­
réponses ..................................... .................................................. .............................237
Machine Translated by Google

Contenu xii

Atelier ................................................. .................................................. .........238


Questionnaire ....................................... .................................................. .......................238
Des exercices ................................................. .................................................. .....239

Partie IV Fonctions et allocation de mémoire dynamique 241

Heure 15 Travailler avec des fonctions 243

Déclarer des fonctions .................................................. ..................................................244


Déclaration versus définition .. .................................................. .......................244
Spécification des types de retour .................................................. ..................................244
Utilisation de prototypes ............... .................................................. ................................245
Effectuer des appels de fonction .................. .................................................. ..............245
Fonctions de prototypage .................................. .................................................. .......247
Fonctions sans arguments ...................................................... ..................................248
Utilisation de time(), localtime() et asctime().. ..................................................249
Fonctions avec un nombre fixe d'arguments ................................................ ..251
Prototypage d'un nombre variable d'arguments .................................................. .....251
Traitement d'arguments variables .................................................. ..................................252
Apprentissage de la programmation structurée .................. ..................... ..................................255
Résumé................ .................................................. ..................................................255
Q&R .... .................................................. .................................................. ............256
Atelier .................................. .................................................. ..................257
Questionnaire .................................. .................................................. .......................................257
Des exercices ................................................. .................................................. .....257

Heure 16 Appliquer des pointeurs 259

Arithmétique du pointeur .................................................. ..................................................259


La taille scalaire des pointeurs .................................................. ...............................260
Soustraction de pointeur .................................................. .......................................263

Pointeurs et tableaux .................................................................. ...............................................264


Accès aux baies via des pointeurs .................................................. .......................264
Pointeurs et fonctions .................................. .................................................. ................266
Passage de tableaux à des fonctions .................................................. ................................266
Passage de pointeurs vers des fonctions .................. .................................................. .....268
Passage de tableaux multidimensionnels en tant qu'arguments.............................. .....270
Tableaux de pointeurs.................................................. .................................................. .....272
Pointer vers des fonctions ................................................. ..................................................274
Résumé................................................. .................................................. ...........276 Questions­
réponses ..................................... .................................................. ................................276
Atelier .................... .................................................. .......................................277
Questionnaire ......... .................................................. ................................ .......................277
Des exercices ................................................. .................................................. .....278
Machine Translated by Google

xii Sams, apprenez­vous C en 24 heures

Heure 17 Allocation de mémoire 279

Allocation de mémoire à l'exécution ................................................ ................................280 La


fonction malloc() ................ .................................................. ..................280 Libération de la
mémoire allouée avec free() ...................... ......................................283 La fonction
calloc() ...... .................................................. ................................286 La fonction
realloc() ............ .................................................. .......................288
Résumé................................. .................................................. ..................................291
Q&R ............ .................................................. .................................................. ....292
Atelier .................................................. .................................................. ..............293
Questionnaire .................................. .................................................. ................................293
Exercices .................... .................................................. .......................................294

Heure 18 Utilisation de types de données et de fonctions spéciales 295

Le type de données enum ............................................... ...............................................296


Déclarer l' énumération Type de données ................................................ ..................296
Attribuer des valeurs aux noms d' énumération .................... ...............................................296
Création de définitions de typedef .................................................. ..............................300
Pourquoi utiliser typedef ? .................................................. ................................................300
Fonctions récursives ... .................................................. .......................................303 Revisiter
la fonction main() .... .................................................. ......................305 Arguments de la ligne
de commande ....................... .................................................. ...305 Recevoir des arguments
de ligne de commande .................................. ..................306
Résumé.................................. .................................................. ................................308 Questions­
réponses .................... .................................................. ..................................................308
Atelier . .................................................. .................................................. .......309
Questionnaire .................................................. .................................................. ................ .....309
Exercices .................................................. .................................................. ...........310

Partie V Structure, Union, E/S de fichiers, etc. 311


Heure 19 Comprendre les structures 313

Qu'est­ce qu'une Structure ? .................................................. ..........................................314


Déclarer des structures ..... .................................................. ...............................314 Définition
des variables de structure ............... .................................................. .........315 Référencement
des membres de la structure avec l'opérateur point .................. ...315 Initialisation des
structures ....................................... ...............................................317 Structures et fonctions
Appels................................................. ................................319 Référencement de structures
avec des pointeurs ................. ................................................322 Référencement d'un
élément de structure avec ­> .................................................. ......324 Tableaux de
structures ...................................... .................................................. ..324 Structures
imbriquées.................................. .................................................. .........327
Résumé.................................................. .................................................. .......................330
Machine Translated by Google

Contenu xiii

Questions­réponses .................................................. .................................................. ..................330


Atelier .................................. .................................................. ..................................331
Quizz .................................. .................................................. .......................................331
Des exercices ................................................. .................................................. .....332

Heure 20 Comprendre les syndicats 333

Qu'est­ce qu'un syndicat ? .................................................. ...............................................334

Déclarer des syndicats .................................................. ..................................................334


Définition des variables d'union .. .................................................. ..................334 Référencer une
Union avec . ou ­> ....................................................... ....................335 Syndicats contre
Structures .................................. .................................................. .......337

Initialisation d'une union .................................................. .......................................337 La taille


d'un syndicat... .................................................. .......................................339

Utilisation des syndicats .................................................. .................................................. ..341


Référencement différent du même emplacement de mémoire ..................................341 Création
de structures Souple ................................................. ................................343 Définir des champs
de bits avec struct .................. .................................................. .347
Résumé............................................................. .................................................. .............350 Questions­
réponses .................................... .................................................. ..................................351
Atelier .................. .................................................. .......................................352
Questionnaire ....... .................................................. .................................................. .....352
Des exercices ................................................. .................................................. .....353

Heure 21 Lire et écrire avec des fichiers 355

Fichiers contre flux ................................................................. .............................................356


Qu'est­ce qu'un fichier ? .................................................. .................................................. .356
Qu'est­ce qu'un flux ? .................................................. .......................................356
E/S tamponnées .................................................. .................................................. ....356
Les bases de l'E/S de fichiers sur disque .................................. .......................................357
Pointeurs de FICHIER ....................................................... .............................................357

Ouverture d'un fichier ....................................................... ..................................................357


Fermeture d'un fichier .................................................. .................................................. .358
Lecture et écriture de fichiers sur disque .................................. ...............................360 Un caractère à
la fois ............. .................................................. ................360
Une ligne à la fois .................................................. ..................................................363
Un bloc à la fois .................................................. .......................................366

Résumé................................................. .................................................. ...........370 Questions­


réponses ....................................... .................................................. ................................370
Atelier .................... .................................................. .......................................371
Questionnaire ......... .................................................. .................................................. ...371
Des exercices ................................................. .................................................. .....372
Machine Translated by Google

xiv Sams, apprenez­vous C en 24 heures

Heure 22 Utilisation des fonctions de fichiers spéciaux 373

Accès aléatoire aux fichiers du disque.............................................. ..................................374


Les fonctions fseek() et ftell() ......................................................... .....................374 La
fonction rewind() ....................... .................................................. .........378 Plus
d'exemples d'E/S de fichiers sur disque .................. .......................................378 Lecture et
écriture de données binaires.... .................................................. ............378 Les
fonctions fscanf() et fprintf() ................................. ................................381 Redirection
des flux standard avec freopen() ............. ..................................384
Résumé.............................. .................................................. .......................................387
Q&R ......... .................................................. .................................................. .......387
Atelier .................................................. .................................................. ..................388
Questionnaire .................................. .................................................. .....................................388
Exercices ........... .................................................. .......................................389

Programmes de compilation de l'heure 23 : le préprocesseur C 391

Qu'est­ce que le préprocesseur C ?............................................ ....................................392


Le préprocesseur C contre le compilateur ....... .................................................. ...392 Les
directives #define et #undef ....................................... .............................393
Définir des macros de type fonction avec #define ...................................... ....394
Définitions de macros imbriquées ......................................... .......................................396
Compiler votre code sous conditions .................................................. ...............397 Les
directives #ifdef et #endif ...................................... .....................................397
La Directive #ifndef .................................................. .......................................397
Les directives #if, #elif et #else ....................................... .....................399 Compilation
conditionnelle imbriquée .................................. .......................................402
Résumé..... .................................................. .................................................. .....405
Questions­réponses ................................................. .................................................. .......................405
Atelier ................................ .................................................. ..................................406
Questionnaire ............... .................................................. ..................................................406
Exercices . .................................................. .................................................. ...407

Heure 24 Où allez­vous d'ici ? 409

Création d'une liste chaînée .................................................. ..................................................410


Style de programmation ..... .................................................. .......................................418
Programmation modulaire ........ .................................................. ...............................419
Débogage.................................. .................................................. ..................................420
Ce que vous avez appris ..... .................................................. ...............................420
Mots­clés C .................................................. .................................................. ..420
Opérateurs .................................................. .................................................. ........421
Constantes ....................................... .................................................. ..............422
Types de données ................................................ .................................................. ....423
Expressions et affirmations .................................................. ................................426
Instructions de flux de contrôle .................. .................................................. ................426
Machine Translated by Google

Contenu xv

Pointeurs .................................................. .................................................. .......430


Les fonctions ................................................. .................................................. .....432

Entrée et sortie (E/S).................................................. ..........................................433 Le


préprocesseur C .. .................................................. ..................................434 Le chemin à
parcourir… ........... .................................................. ..................................434

Résumé................................................. .................................................. ...........435

Annexes de la partie VI 437

Annexe A Fichiers d'en­tête standard ANSI 439

Annexe B Réponses aux questions et exercices du quiz 441

Heure 1, "Faire le premier pas" ...................................................... ..................................441


Questionnaire ............... .................................................. ...............................................441 Heure
2 , "Ecrire votre premier programme en C" ......................................... ..................442
Questionnaire .................................. .................................................. ................................442
Des exercices ................................................. .................................................. .....442

Heure 3, "Apprentissage de la structure d'un programme en C" ...................................... ........443


Questionnaire .................................................. .................................................. .......................443
Des exercices ................................................. .................................................. .....444

Heure 4, « Comprendre les types de données et les mots­clés » ...................................... ..445


Questionnaire .................................................. .................................................. ................445
Des exercices ................................................. .................................................. .....445

Heure 5, « Gestion des entrées et des sorties standard » ......................................... ..........447


Questionnaire ...................................... .................................................. .......................447
Des exercices ................................................. .................................................. .....447

Heure 6, « Manipulation des données » ......................................... ....................................449


Questionnaire ............. .................................................. ..................................................449
Des exercices ................................................. .................................................. .....449

Heure 7, « Travailler avec des boucles » ......................................... ..................................451


Questionnaire .................. .................................................. ...............................................451
Des exercices ................................................. .................................................. .....451

Heure 8, "Utilisation des opérateurs conditionnels" ......................................... ....................453


Quizz ................................ .................................................. ..................................453
Des exercices ................................................. .................................................. .....453

Heure 9, « Travailler avec des modificateurs de données et des fonctions mathématiques » ......455
Quiz ........ .................................................. .................................................. ....455
Des exercices ................................................. .................................................. .....456

Heure 10, "Contrôle du déroulement du programme".................................................. ..................458


Questionnaire .................................. .................................................. .......................................458
Des exercices ................................................. .................................................. .....458
Machine Translated by Google

xvi Sams, apprenez­vous C en 24 heures

Heure 11, « Comprendre les pointeurs » ......................................... ..................................460


Questionnaire ....................... .................................................. .......................................460
Des exercices ................................................. .................................................. .....461

Heure 12, « Comprendre les tableaux » ......................................... ..................................462


Quizz .................................. .................................................. .......................................462
Des exercices ................................................. .................................................. .....463

Heure 13, « Manipulation des chaînes » ......................................... ..................................465


Questionnaire .................... .................................................. ..................................................465
Des exercices ................................................. .................................................. .....466

Heure 14, « Comprendre la portée et les classes de stockage » ......................467


Quiz .................................................. .................................................. ............467
Des exercices ................................................. .................................................. .....468

Heure 15, "Travailler avec les fonctions".................................................. ..................................470


Questionnaire ...................... .................................................. ........................................470
Des exercices ................................................. .................................................. .....470

Heure 16, « Appliquer des pointeurs » ......................................... ....................................473


Questionnaire ............. .................................................. ..................................................473
Des exercices ................................................. .................................................. .....474

Heure 17, "Allocation de mémoire" .................................................. ..................................476


Questionnaire .................. .................................................. .............................................476
Des exercices ................................................. .................................................. .....476

Heure 18, "Utilisation de types de données et de fonctions spéciales" ....................................... .480


Questionnaire .................................................. .................................................. ...............480
Des exercices ................................................. .................................................. .....480

Heure 19, « Comprendre les structures » ......................................... .......................482


Questionnaire .................................. .................................................. .....................................482
Des exercices ................................................. .................................................. .....482

Heure 20, « Comprendre les syndicats » ......................................................... ..................................486


Questionnaire ................................. .................................................. .......................................486
Des exercices ................................................. .................................................. .....486

Heure 21, « Lire et écrire avec des fichiers »......................................... ................490


Questionnaire ................................ .................................................. ..............................490
Des exercices ................................................. .................................................. .....490

Heure 22, « Utilisation des fonctions de fichiers spéciaux » ...................................... ....................494


Questionnaire ............................. .................................................. ..................................494
Des exercices ................................................. .................................................. .....494

Heure 23, « Compiler des programmes : le préprocesseur C » .........................................499


Questionnaire ................................................. .................................................. .............499
Des exercices ................................................. .................................................. .....500

Indice 503
Machine Translated by Google

A propos de l'auteur
TONY ZHANG a plus de 15 ans d'expérience dans la programmation informatique et la conception de
systèmes d'information à l'échelle de l'entreprise. Il travaille actuellement pour l'une des « 5 grandes »
sociétés de conseil spécialisées dans la conception, le développement et la mise en œuvre d'infrastructures
liées aux affaires électroniques.

Titulaire d'une maîtrise en physique, il a publié des dizaines d'articles de recherche sur les lasers et
la programmation informatique. Parmi ses grands intérêts figurent la peinture à l'huile et la
photographie, les deux choses que Tony aime le plus.

Vous pouvez contacter Tony via Sams Publishing ou en lui envoyant un e­mail
à tyc24h@hotmail.com.

À propos de l'auteur collaborateur


JOHN SOUTHMAYD est un ingénieur en conception de logiciels avec une expérience dans des domaines
allant de la programmation au niveau des systèmes et des pilotes de périphériques au développement
Windows et aux technologies Internet. Il travaille actuellement comme consultant chez Excell Data Corporation
et vit avec sa femme à Kirkland, Washington.
Machine Translated by Google

Dévouement
À ma femme, Ellen, et à mes parents, Zhi­ying et Bing­rong, pour leur amour et leurs inspirations.

—Tony Zhang

Remerciements
Tout d'abord, je voudrais remercier les lecteurs de la première édition du livre pour leurs encouragements,
leur patience, leurs commentaires et surtout leurs critiques, qui ont rendu la deuxième édition plus
adaptée aux personnes qui souhaitent se lancer dans la programmation en C monde.

C'est pour moi un grand plaisir de travailler avec l'éditrice Sharon Cox pour la deuxième fois. Je
tiens à remercier les éditeurs Carol Ackerman et Gus Miklos, ainsi que l'auteur contributeur John
Southmayd pour leur excellent travail qui a rendu la deuxième édition du livre plus accessible et en
grande partie, sinon complètement, sans erreur. De plus, j'aimerais exprimer mon appréciation pour
l'excellent travail des autres membres de l'équipe de rédaction. Ensemble, ils ont rendu possible la deuxième édition.

J'apprécie grandement l'amour et le soutien de ma femme, Ellen, qui m'inspire à regarder le monde
de la technologie sous différents angles. C'est toujours une grande joie de discuter avec elle de
questions de philosophie et de littérature. Mes parents, que je ne remercierai jamais assez, m'ont donné
non seulement de l'amour et de l'affection, mais aussi l'opportunité de recevoir la meilleure éducation
que j'aie jamais pu avoir quand j'étais en Chine.
Machine Translated by Google

Dites­nous ce que vous pensez!


En tant que lecteur de ce livre, vous êtes notre critique et commentateur le plus important. Nous apprécions
votre opinion et voulons savoir ce que nous faisons bien, ce que nous pourrions faire mieux, dans quels
domaines vous aimeriez nous voir publier et tout autre mot de sagesse que vous êtes prêt à
passer notre chemin.

En tant qu'éditeur associé pour Sams, j'apprécie vos commentaires. Vous pouvez me faxer, m'envoyer un e­
mail ou m'écrire directement pour me faire savoir ce que vous avez aimé ou non dans ce livre, ainsi que ce
que nous pouvons faire pour rendre nos livres plus solides.

Veuillez noter que je ne peux pas vous aider avec des problèmes techniques liés au sujet de ce livre, et
qu'en raison du volume élevé de courrier que je reçois, je ne pourrai peut­être pas répondre à
chaque message.

Lorsque vous écrivez, assurez­vous d'inclure le titre et l'auteur de ce livre ainsi que votre nom et votre
numéro de téléphone ou de télécopieur. Je vais examiner attentivement vos commentaires et les partager
avec l'auteur et les éditeurs qui ont travaillé sur le livre.

Fax: 317­581­4770
Courriel : michael.stephens@macmillanusa.com Courriel :
Michael Stephens Éditeur associé

Éditions Sams
201 103e rue Ouest

Indianapolis, IN 46290 États­Unis


Machine Translated by Google
Machine Translated by Google

Introduction
Si l'on apprend des autres mais ne pense pas, on sera désorienté ; Si l'on pense mais

n'apprend pas des autres, on sera en danger.

—Confucius

Bienvenue à la deuxième édition d' Apprends­toi C en 24 heures !

Sur la base du succès de la première édition du livre et des commentaires des lecteurs, nous avons réécrit ou modifié

chaque chapitre du livre pour rendre la deuxième édition plus adaptée aux débutants comme vous qui veulent
commencer avec le langage de programmation C le plus rapidement possible.

Bien sûr, il est tout à fait normal de passer plus de 24 heures pour vraiment comprendre les concepts et les
compétences de programmation introduits dans le livre. Cependant, la bonne nouvelle est que ce livre propose de
nombreux exemples de programmes et d'exercices avec des explications et des réponses claires, ce qui facilite la
compréhension des concepts du langage C.

En fait, Teach Yourself C in 24 Hours vous fournit un bon point de départ pour la programmation en C. Il couvre
des sujets importants en programmation C et établit une base solide pour un débutant sérieux comme vous. Après
avoir lu ce livre, vous serez capable d'écrire des bases en C pro
grammes par vous­même.

Vous tirerez profit de la lecture de ce livre lorsque vous commencerez à appliquer des programmes C à des
problèmes réels ou que vous passerez à l'apprentissage d'autres langages de programmation, tels que Perl, C++ et Java.

Qui devrait lire ce livre ?


Si c'est la première fois que vous apprenez le C, ce livre est écrit pour vous. En fait, en écrivant ce livre, je suppose
que les lecteurs n'ont aucune expérience préalable en programmation. Bien sûr, c'est toujours un gros plus si vous
avez des connaissances en informatique.

Particularités de ce livre
Ce livre contient les éléments spéciaux suivants qui vous permettent d'assimiler plus simplement et plus clairement
les fonctionnalités et concepts rudimentaires du C au fur et à mesure qu'ils sont introduits :

• Boîtes de syntaxe

• Remarques

• Précautions

• Conseils
Machine Translated by Google

2 Sams, apprenez­vous C en 24 heures

Les encadrés de syntaxe expliquent certaines des fonctionnalités les plus compliquées du C, telles que les
structures de contrôle. Chaque boîte de syntaxe consiste en une définition formelle de la caractéristique suivie
d'une explication. Voici un exemple de boîte de syntaxe :

La syntaxe de la fonction malloc() est


#include <stdlib.h> void
,SYNTAXE
*malloc(size_t size);

Ici, la taille spécifie le nombre d'octets de stockage à allouer. Le fichier d'en­tête, stdlib.h, doit être
inclus avant que la fonction malloc() puisse être appelée. Étant donné que la fonction malloc() renvoie un
pointeur vide , son type est automatiquement converti en type de pointeur sur le côté gauche d'un opérateur
, d'affectation.

(Vous en apprendrez plus sur la fonction malloc() plus loin dans le livre.)

Les notes sont des explications des propriétés intéressantes d'une fonctionnalité particulière du programme
C. Examinons l'exemple de note suivant :

Dans une sortie justifiée à gauche, la valeur affichée apparaît à l'extrémité gauche du champ de valeur.
Dans une sortie justifiée à droite, la valeur affichée apparaît à l'extrémité droite du champ de valeur.

Les avertissements vous avertissent des pièges de programmation que vous devez éviter. Voici un avertissement typique :

N'utilisez jamais les mots clés réservés en C, ni les noms des fonctions de la bibliothèque C comme
noms de variables dans votre programme.

Les astuces sont des conseils pour mieux écrire vos programmes C. Voici un exemple de conseil :

Si vous avez un projet de programmation complexe, divisez­le en plus petits morceaux.


Et essayez de faire en sorte qu'une fonction fasse une chose et qu'elle le fasse très bien.

Exemples de programmation
Comme mentionné précédemment, ce livre contient de nombreux exemples de programmation utiles avec des
explications. Ces exemples sont destinés à vous montrer comment utiliser différents types de données et
fonctions fournis en C.
Machine Translated by Google

Introduction 3

Chaque exemple a une liste du programme C; la sortie générée à partir de cette liste suivra. L'exemple
propose également une analyse du fonctionnement du programme. Des icônes spéciales sont utilisées
pour souligner chaque partie de l'exemple : Type, Entrée/Sortie et Analyse.

Dans l'exemple présenté dans le Listing IN.1, il existe des conventions typographiques spéciales.
L'entrée que vous entrez est affichée en caractères gras à espacement fixe, et la sortie générée par le
programme exécutable du Listing IN.1 est affichée en caractères à espacement fixe.

TAPER LISTING IN.1 Lire un caractère saisi par l'utilisateur

1 : /* INL01.c : lit l'entrée en appelant getc() */ 2 : #include


<stdio.h> 3 : 4 : main() 5 : { 6 : 7 :

int ch ;

printf("Veuillez saisir un caractère :\n"); ch = getc(stdin);


printf("Le caractère que vous venez d'entrer est :
%c\n", ch); renvoie 0 ;
8 : 9 : 10 : 11 :

12 : }

La sortie suivante s'affiche après la création et l'exécution du fichier exécutable, INL01.exe .


L'utilisateur saisit le caractère H et le programme affiche ce que l'utilisateur a saisi.

Veuillez saisir un caractère :


H
Le caractère que vous venez d'entrer est : H

À la ligne 2 du Listing IN.1, le fichier d'en­tête stdio.h est inclus pour les fonctions getc() et
UNE ANALYSE
printf() utilisées dans le programme. Les lignes 4 à 12 donnent le nom et le corps
de la fonction main() .

À la ligne 6, une variable entière ch est déclarée, qui est affectée à la valeur de retour de la fonction
getc() plus loin à la ligne 9. La ligne 8 imprime un message demandant à l'utilisateur d'entrer un caractère
au clavier. La fonction printf() de la ligne 8 utilise la sortie standard par défaut stdout pour afficher les
messages à l'écran.

À la ligne 9, l'entrée standard stdin est transmise à la fonction getc() , qui indique que le flux de fichiers
provient du clavier. Une fois que l'utilisateur a saisi un caractère, la fonction getc() renvoie la valeur
numérique (c'est­à­dire un entier) du caractère. Notez qu'à la ligne 9, la valeur numérique est affectée à la
variable entière ch.
Machine Translated by Google

4 Sams, apprenez­vous C en 24 heures

A la ligne 10, le caractère saisi est affiché à l'écran à l'aide de printf().


Notez que le spécificateur de format de caractère %c est utilisé dans la fonction printf() à la ligne 10.

Questions­réponses et atelier
Chaque heure (c'est­à­dire chaque chapitre) se termine par une section Q&A qui contient des réponses aux questions
courantes relatives à la leçon du chapitre. Après la section Q&A, il y a un atelier qui consiste en des questions de quiz et
des exercices de programmation. Les réponses à ces questions de quiz et des exemples de solutions pour les exercices
sont présentés à l'annexe D, « Réponses au quiz et aux exercices ».

Pour vous aider à consolider votre compréhension de chaque leçon, nous vous encourageons à essayer de
répondre aux questions du quiz et à terminer les exercices fournis dans l'atelier.

Conventions utilisées dans ce livre


Ce livre utilise des polices de caractères spéciales pour vous aider à différencier le code C de l'anglais normal et à
identifier les concepts importants.

• Le code C réel est composé dans une police spéciale à espacement fixe . Vous verrez cette police utilisée dans
des listes, des exemples d'entrée/sortie et des extraits de code. Dans l'explication des fonctionnalités C, les
commandes, les noms de fichiers, les instructions, les variables et tout texte que vous voyez à l'écran sont
également composés dans cette police. • L'entrée de commande et tout ce que vous êtes censé entrer apparaît

en gras
police monospace . Vous le verrez principalement dans les sections Entrée/Sortie des exemples. • Les

espaces réservés dans les descriptions de syntaxe apparaissent dans une police italique à espacement fixe .
Remplacez l'espace réservé par le nom de fichier réel, le paramètre ou tout autre élément qu'il représente
envoie.

• Les italiques mettent en évidence les termes techniques lorsqu'ils apparaissent pour la première fois dans le texte et
sont parfois utilisés pour souligner des points importants.

Ce que vous apprendrez en 24 heures


Teach Yourself C en 24 heures se compose de cinq parties. Dans la partie I, "Les bases du C", vous apprendrez les
bases du langage C. Voici un résumé de ce que vous allez apprendre :

L'heure 1, "Faire le premier pas", vous présente le langage C, la norme ANSI et les exigences logicielles et
matérielles de base pour la programmation en C.

L' heure 2, "Votre premier programme C", montre toute la procédure d'écriture, de compilation, de liaison et
d'exécution d'un programme C.
Machine Translated by Google

Introduction 5

L'heure 3, "Apprendre la structure d'un programme C", vous apprend plusieurs concepts importants, tels que les
constantes, les variables, les expressions et les instructions. L'anatomie d'une fonction est également introduite
dans cette heure.

L'heure 4, « Comprendre les types de données et les mots clés », répertorie tous les mots clés C réservés.
Quatre types de données, char, int, float et double, sont présentés en détail. De plus, les règles pour
nommer une variable sont expliquées.

L'heure 5, "Gestion des entrées et sorties standard", vous apprend à recevoir des entrées du clavier et
à imprimer des sorties à l'écran à l'aide d'un ensemble de fonctions C, telles que getc(), getchar(),
putc(), putchar() et printf().

La partie II, « Opérateurs et instructions de flux de contrôle », met l'accent sur les opérateurs et les instructions de flux
de contrôle en C. Voici un résumé de ce que vous apprendrez :

L'heure 6, « Manipulation des données », vous apprend à utiliser les opérateurs d'affectation arithmétique,
l'opérateur moins unaire, les opérateurs d'incrémentation/décrémentation, les opérateurs relationnels et l'opérateur
de transtypage.

L'heure 7, "Travailler avec des boucles", présente la boucle (c'est­à­dire l'itération) avec les instructions for, while
ou do­while .

L'heure 8, "Utilisation des opérateurs conditionnels", vous en dit plus sur les opérateurs, tels que les opérateurs
logiques, les opérateurs au niveau du bit, l' opérateur sizeof et l'opérateur ? , qui sont fréquemment utilisés en C.

L'heure 9, "Travailler avec les modificateurs de données et les fonctions mathématiques", décrit comment utiliser
les modificateurs de données pour activer ou désactiver le bit de signe ou modifier la taille d'un type de données.
En outre, plusieurs fonctions mathématiques fournies par C sont introduites.

L'heure 10, "Contrôle du flux de programme", présente toutes les instructions de flux de contrôle
utilisées en C. Il s'agit des instructions if, if­else, switch, break, continue et goto .

Les pointeurs et les tableaux sont abordés dans la partie III, « Pointeurs et tableaux ». Voici un résumé de ce que
vous apprendrez :

L'heure 11, "Comprendre les pointeurs", vous apprend à référencer des variables avec des pointeurs. Des
concepts tels que la valeur de gauche et la valeur de droite sont également introduits.

L'heure 12, « Comprendre les tableaux », explique comment déclarer et initialiser des tableaux.
La relation entre le tableau et le pointeur en C est également discutée.

L'heure 13, "Manipulation de chaînes" se concentre sur la lecture et l'écriture de chaînes. Plusieurs
fonctions de la bibliothèque C, telles que strlen(), strcpy(), gets(), puts() et scanf(), sont introduites
pour manipuler les chaînes.

L'heure 14, « Comprendre la portée et les classes de stockage », présente la portée du bloc, la portée
de la fonction, la portée du programme et la portée du fichier. En outre, les spécificateurs ou
modificateurs de classe de stockage, tels que auto, static, register, extern, const et volatile sont expliqués.
Machine Translated by Google

6 Sams, apprenez­vous C en 24 heures

La partie IV, « Fonctions et allocation dynamique de mémoire », se concentre sur les fonctions et les
allocations dynamiques de mémoire en C. Voici un résumé de ce que vous apprendrez :

L'heure 15, « Travailler avec les fonctions », décrit la déclaration et la définition de la fonction en C. Le
prototypage de la fonction est expliqué, ainsi que la spécification du type de retour de la fonction.

L'heure 16, « Appliquer des pointeurs » , vous apprend à effectuer des opérations arithmétiques sur les
pointeurs, à accéder aux éléments de tableaux avec des pointeurs et à passer des pointeurs à des fonctions.

L'heure 17, « Allocation de mémoire », explique le concept d'allocation dynamique de mémoire. Les
fonctions C, telles que malloc(), calloc(), realloc() et free(), sont introduites en ce qui concerne l'allocation
de mémoire dynamique.

L'heure 18, "Utilisation de types de données et de fonctions spéciales", présente le type de données enum
et l'utilisation de typedef. La récursivité des fonctions et les arguments de ligne de commande de la fonction
main() sont également enseignés dans l'heure 18.

La partie V, « Structure, union, E/S de fichiers, etc. », traite des structures, des unions et des E/S de fichiers de
disque en C. Voici un résumé de ce que vous apprendrez :

L'heure 19, « Comprendre les structures », présente le type de données de structure . Vous apprenez
à accéder aux membres de la structure et à passer des structures aux fonctions à l'aide de pointeurs. Les
structures imbriquées et de référencement vers l'avant sont également abordées au cours de cette heure.

L' heure 20, « Comprendre les syndicats », décrit le type de données du syndicat et la différence entre le
syndicat et la structure. Les applications des unions sont démontrées dans plusieurs exemples.

L'heure 21, "Lecture et écriture avec des fichiers", explique les concepts de fichier et de
flux en C. Les bases de l'entrée et de la sortie de fichiers sur disque sont introduites dans
cette première partie. Les fonctions C suivantes, ainsi que plusieurs exemples, sont
introduites dans cette heure : fopen(), fclose(), fgetc(), fputc(), fgets(), fputs(), fread(),
fwrite() et feof ().
L'heure 22, "Utilisation des fonctions de fichiers spéciales", est la deuxième partie des E/S de fichiers
sur disque, dans laquelle fseek(), ftell() et rewind() sont introduits pour montrer comment ils peuvent
vous aider à obtenir un accès aléatoire au disque des dossiers. De plus, les fonctions fscanf(), fprintf()
et freopen() sont enseignées et appelées dans des exemples de programmes.

L'heure 23, « Compilation de programmes : le préprocesseur C », décrit le rôle joué par le


préprocesseur C. Vous pouvez apprendre les directives du préprocesseur, telles que
#define, #undef, #ifdef, #endif, #ifndef, #if, #elis et #else à travers les exemples donnés dans
cette heure.
Machine Translated by Google

Introduction 7

L'heure 24, "Où allez­vous à partir d'ici ?", résume les concepts et fonctionnalités importants introduits
dans ce livre. De plus, le style de programmation, la programmation modulaire et le débogage sont
expliqués brièvement. Une liste de livres C recommandés est fournie pour vos lectures ultérieures.

Maintenant, vous êtes prêt à commencer le voyage d'apprentissage du langage C, alors que le monde
est entré dans un nouveau millénaire. Amusez­vous à lire ce livre et amusez­vous à programmer en C !

Tony Zhang

Centre­ville, Pennsylvanie

janvier 2000
Machine Translated by Google
Machine Translated by Google

PARTIE I

Les bases du C
Heure
1 Faire le premier pas

2 Votre premier programme C

3 Apprentissage de la structure d'un programme C

4 Comprendre les types de données et les mots­clés

5 Gestion des entrées et sorties standard


Machine Translated by Google
Machine Translated by Google

HEURE 1
Faire le premier pas
Un voyage de mille miles commence par le premier pas.

­Proverbe chinois

Les pensées élevées doivent avoir un langage élevé.

—Aristophane

Bienvenue à Teach Yourself C en 24 heures. Dans cette première leçon, vous apprendrez ce qui
suit :

• Qu'est­ce que C ?

• Pourquoi devez­vous apprendre le C ?

• La norme ANSI

• Matériel et logiciel requis pour écrire et exécuter des programmes C


Machine Translated by Google

12 Heure 1

Qu'est­ce que C?
C est un langage de programmation. Le langage C a été développé pour la première fois en 1972 par
Dennis Ritchie chez AT&T Bell Labs. Ritchie a appelé son nouveau langage C simplement parce qu'il
existait déjà un langage de programmation B. (En fait, la langue B a conduit au développement de C.)

C est un langage de programmation de haut niveau. En fait, C est l'un des langages de programmation
à usage général les plus populaires.

Dans le monde informatique, plus un langage de programmation est éloigné de l'architecture informatique,
plus le niveau du langage est élevé. Vous pouvez imaginer que les langages de plus bas niveau sont des
langages machine que les ordinateurs comprennent et exécutent directement. Les langages de
programmation de haut niveau, en revanche, sont plus proches de nos langages humains (voir Figure 1.1).

FIGURE 1.1
Haute
La spécification de langue Si la ligne n'est

trum. pas occupée, connectez­


Le langage humain (par vous à Internet ; sinon
exemple, l'anglais) attends...

Si (ligne ! = occupé)
connexion (Internet) ;
Le langage de programmation de haut sinon attendez (5)...
niveau (par exemple, C)

Le langage machine (c'est­à­ 10001111101100

dire le code binaire) 01100111011000

Bas

Les langages de programmation de haut niveau, dont le C, présentent les avantages suivants :

• Lisibilité : Les programmes sont faciles à lire. •

Maintenabilité : les programmes sont faciles à entretenir. •

Portabilité : les programmes sont faciles à transférer sur différentes plates­formes informatiques.
Machine Translated by Google

Faire le premier pas 13

La lisibilité et la maintenabilité du langage C bénéficient directement de sa relative proximité avec les langages
humains, en particulier l'anglais.
1
Chaque langage de haut niveau a besoin d'un compilateur ou d'un interpréteur pour traduire les instructions
écrites dans le langage de programmation de haut niveau en un langage machine qu'un ordinateur peut
comprendre et exécuter. Différentes machines peuvent nécessiter différents compilateurs ou interpréteurs pour
le même langage de programmation. Par exemple, j'utilise le compilateur C de Microsoft pour compiler les
programmes C de ce livre pour mon ordinateur personnel (PC). Si j'ai besoin d'exécuter les programmes C sur un
poste de travail basé sur UNIX, je dois utiliser un autre type de compilateur C pour compiler ces programmes. Par
conséquent, la portabilité des programmes écrits en C est réalisée en recompilant les programmes avec différents
compilateurs pour différentes machines (voir Figure 1.2).

FIGURE 1.2
Le C
Portage de programmes Programme

écrits en C sur différents


types d'ordinateurs.

Compilateur Compilateur Compilateur


UN B C

Le cerveau de l'ordinateur Vous


savez peut­être que le cerveau d'un ordinateur est l'unité centrale de traitement (CPU). Certains
ordinateurs peuvent avoir plus d'un processeur à l'intérieur. Un CPU a des millions de transistors qui
utilisent des commutateurs électroniques. Les interrupteurs électroniques n'ont que deux états : éteint et allumé.
(Symboliquement, 0 et 1 sont utilisés pour représenter les deux états.) Par conséquent, un ordinateur
ne peut comprendre que des instructions composées de séries de 0 et de 1. En d'autres termes, les
instructions lisibles par machine doivent être au format binaire.
Machine Translated by Google

14 Heure 1

Cependant, un programme informatique écrit dans un langage de haut niveau, tel que C, Java ou Perl,
n'est qu'un fichier texte, composé de caractères et de mots de type anglais. Vous devez utiliser des
programmes spéciaux, appelés compilateurs ou interpréteurs, pour traduire un tel programme en un code
lisible par machine. C'est­à­dire que le format texte de toutes les instructions écrites dans un langage de
haut niveau doit être converti en format binaire. Le code obtenu après la traduction est appelé code binaire.
Avant la traduction, un programme au format texte est appelé code source.
La plus petite unité de code binaire est appelée un bit (de chiffre binaire), qui peut avoir une valeur de 0 ou
1. Généralement, huit bits constituent un octet et un demi­octet (quatre bits) est un quartet.

De plus, le langage C présente d'autres avantages. Les programmes écrits en C peuvent être réutilisés.
Vous pouvez enregistrer des parties de vos programmes C dans un fichier de bibliothèque et les invoquer dans
votre prochain projet de programmation simplement en incluant le fichier de bibliothèque. De nombreuses tâches
de programmation courantes et utiles sont déjà implémentées dans les bibliothèques fournies avec les compilateurs.
De plus, les bibliothèques vous permettent de libérer facilement la puissance et les fonctionnalités du système
d'exploitation que vous utilisez. Plus de détails sur l'utilisation des fonctions de la bibliothèque C sont couverts
dans le reste de ce livre.

C est un langage de programmation relativement petit, ce qui vous facilite la vie. Vous n'avez pas besoin de vous
rappeler de nombreux mots­clés ou commandes C avant de commencer à écrire des programmes en C pour
résoudre des problèmes dans le monde réel.

Pour ceux qui recherchent la rapidité tout en gardant la commodité et l'élégance d'un langage de haut niveau,
le langage C est probablement le meilleur choix. En fait, C vous permet de prendre le contrôle du matériel
informatique et des périphériques. C'est pourquoi le langage C est parfois appelé le langage de programmation
de haut niveau le plus bas.

De nombreux autres langages de haut niveau ont été développés sur la base de C. Par exemple, Perl est un
langage de programmation populaire dans la conception du World Wide Web (WWW) sur Internet.
Perl emprunte en fait beaucoup de fonctionnalités au C. Si vous comprenez le C, apprendre Perl est un jeu
d'enfant. Un autre exemple est le langage C++, qui est simplement une version étendue de C, bien que C++
facilite la programmation orientée objet. De plus, apprendre Java devient beaucoup plus facile si vous connaissez
déjà C.

Il existe généralement deux types de langages de programmation : les langages


compilés et les langages interprétés .
Un compilateur est nécessaire pour traduire un programme écrit dans un langage compilé
en code compréhensible par une machine (c'est­à­dire un code binaire) avant de pouvoir
exécuter le programme sur votre machine. Lorsque la traduction est terminée, le binaire
Machine Translated by Google

Faire le premier pas 15

1
le code peut être enregistré dans un fichier d'application. Vous pouvez continuer à exécuter le
fichier d'application sans le compilateur, sauf si le programme (code source) est mis à jour et que vous
devez le recompiler. Le code binaire ou fichier d'application est également appelé code exécutable (ou
fichier exécutable).

D'un autre côté, un programme écrit dans un langage interprété peut être exécuté immédiatement
après que vous ayez fini de l'écrire — ou d'ailleurs, pendant que vous l'écrivez ! Mais un tel
programme a toujours besoin d'un interpréteur pour traduire les instructions de haut niveau en
instructions compréhensibles par la machine (code binaire) au moment de l'exécution. Vous ne
pouvez pas exécuter le programme sur une machine à moins que le bon interprète ne soit disponible.

Vous pouvez considérer le langage C comme un langage compilé car la plupart des fournisseurs
de langage C ne fabriquent que des compilateurs C, par opposition aux interpréteurs, pour prendre
en charge les programmes écrits en C.

Cependant, rien d'inhérent à un langage compilé n'empêche quelqu'un de fournir un interpréteur


pour le langage ; de même, les gens peuvent écrire, et le font souvent, des compilateurs pour les
langages interprétés. En fait, il n'est pas rare de mélanger les deux saveurs de langages, où un
programmeur compile le code source dans un petit fichier binaire qui est ensuite exécuté par un
interpréteur d'exécution.

La norme ANSI C
Pendant de nombreuses années, la norme de facto pour le langage de programmation C était le livre
The C Programming Language, écrit par Brian Kernighan et Dennis Ritchie en 1978. Ce livre est
communément connu dans la communauté de la programmation sous le simple nom de K&R (faisant
référence aux initiales du auteurs) et trouve une place sur les étagères de nombreux programmeurs à
ce jour. Cependant, le livre a été écrit comme un didacticiel d'introduction au C, et non comme une
norme complète ou officielle pour le langage. Au fur et à mesure que différents fournisseurs proposaient
diverses implémentations du langage C, des différences entre ces implémentations ont commencé à apparaître.

Craignant que C ne perde sa portabilité, un groupe de fournisseurs de compilateurs et de développeurs


de logiciels a demandé à l'American National Standards Institute (ANSI) de créer une norme pour le
langage C en 1983. L'ANSI a approuvé l'application et a formé le comité technique X3J11 pour travailler
sur la norme C. À la fin de 1989, le comité a approuvé la norme ANSI pour le langage de programmation
C.

La norme ANSI pour C améliore la norme K&R d'origine et définit un groupe de fonctions C
couramment utilisées connues sous le nom de bibliothèque standard ANSI C. Dans la plupart des cas,
les compilateurs C incluent la bibliothèque standard, ainsi que d'autres bibliothèques pour fournir
d'autres fonctions spécifiques au compilateur.
Machine Translated by Google

16 Heure 1

Ce livre se concentre sur les fonctions C définies dans la norme ANSI, qui est prise en charge par tous les
fournisseurs de compilateurs. Tous les programmes de ce livre peuvent être compilés par n'importe quel
compilateur conforme à la norme ANSI. Si vous êtes intéressé par un compilateur spécifique, vous pouvez
apprendre les fonctions spécifiques au compilateur à partir du manuel de référence du compilateur.

Hypothèses sur vous


Aucune expérience préalable en programmation n'est requise pour apprendre le langage C à partir de ce livre,
bien qu'une certaine connaissance de l'informatique soit utile. De plus, c'est à vous de déterminer à quelle
vitesse parcourir les 24 heures de ce livre : vous pouvez vous asseoir avec une grande tasse de café et
parcourir le livre en une séance ou vous pouvez prendre une heure par jour pendant 24 jours.

Après avoir terminé ce livre, après avoir fait tous les exercices en cours de route, vous devriez être compétent
et à l'aise avec la syntaxe et les fonctionnalités du langage C. De plus, vous aurez déjà une certaine expérience
de la plupart des tâches rencontrées en programmation C. Lorsque vous serez prêt à entreprendre vos propres
projets de programmation, vous pourrez utiliser le C comme outil pour écrire les programmes puissants et utiles
que vous souhaitez créer. Au fur et à mesure de votre progression, vous constaterez qu'il y a toujours plus à
apprendre, non seulement sur le C et sur la manière d'exploiter sa puissance, mais aussi sur les nouvelles
technologies et les idées de programmation en général. Avec un travail acharné et beaucoup de pratique, vous
pouvez rapidement développer les compétences et les technologies que vous apprenez.

Configuration de votre système


Fondamentalement, tout ce dont vous avez besoin est un ordinateur et un compilateur C pour compiler et
exécuter vos propres programmes C ou les programmes C de ce livre. Le matériel et les logiciels
recommandés sont répertoriés dans les sections suivantes.

Matériel
Tout type d'ordinateur qui a ou peut accéder à un compilateur C convient. Le compilateur C doit être conforme
à la norme ANSI C. Très probablement, vous avez un PC sur votre bureau. Un PC 286 avec un disque dur de
50 Mo et 1 Mo de mémoire (RAM) est probablement le minimum requis pour exécuter un compilateur C basé
sur DOS. Pour un compilateur C basé sur Windows, votre ordinateur doit avoir un disque dur plus gros et plus
de mémoire. Vérifiez votre fournisseur de compilateur pour plus de détails sur les exigences matérielles.

Logiciel
Si vous utilisez un poste de travail basé sur UNIX, vous avez peut­être déjà un compilateur C chargé sur
votre machine, ou du moins vous pouvez accéder à un compilateur C sur une machine serveur. Consultez
votre administrateur système pour savoir comment accéder à un ANSI C
Machine Translated by Google

Faire le premier pas 17

compilateur conforme. Sur une machine basée sur UNIX, vous devez savoir comment utiliser un éditeur de texte
tel que vi ou emacs pour écrire des programmes en C.
1
Si vous avez un PC exécutant un système d'exploitation Microsoft Windows (tel que Windows 95), vous devez
installer un compilateur C et un éditeur de texte sur votre PC. Cependant, la plupart des compilateurs C sont
livrés avec un éditeur intégré. Vous pouvez également utiliser n'importe quel éditeur de texte déjà installé sur
votre machine.

Turbo C de Borland International et Quick C de Microsoft étaient autrefois très populaires sur le marché des
compilateurs C. De nos jours, un compilateur C conforme à ANSI fait généralement partie de tout package de
développement C++ disponible dans le commerce, tel que Microsoft Visual C++. De plus, les packages de
développement sont livrés avec un environnement de développement intégré (IDE), que vous pouvez utiliser
pour éditer, compiler, exécuter et déboguer vos programmes C à partir de la même fenêtre.

Vous pouvez choisir n'importe quel compilateur C de votre choix pour compiler l'exemple de code donné dans le
livre, tant que le compilateur est conforme à la norme ANSI C. Vous ne devriez pas rencontrer de problèmes pour
installer un compilateur C sur votre ordinateur si vous lisez les manuels fournis avec le compilateur et suivez
correctement les instructions d'installation. La plupart des compilateurs C et/ou C++ fournissent un didacticiel
rapide qui vous montre comment installer le compilateur et configurer un environnement de développement
fonctionnel sur votre ordinateur.

De nos jours, le système d'exploitation Linux devient de plus en plus populaire parmi les utilisateurs de PC. Dans
la plupart des cas, le package Linux que vous obtenez contient un compilateur C. Le compilateur C peut être
installé sur votre PC lorsque vous installez le système d'exploitation Linux, ou peut être ajouté ultérieurement
après avoir terminé l'installation de Linux.

Un exemple de configuration de programmation en C


J'ai un PC Pentium 100 MHz avec 32 Mo de mémoire et un disque dur de 2,5 Go. (Le disque dur avait environ
1,5 Go d'espace libre avant que j'installe une copie de Microsoft Visual C++ 5.0.) De plus, j'ai Windows 95 comme
système d'exploitation sur la machine.

Dans ce livre, tous les programmes C sont développés avec Microsoft Visual C++ version 5.0. Les raisons pour
lesquelles j'ai choisi Visual C++ sont simples : tous les programmes C de ce livre sont écrits en ANSI C et
peuvent être compilés dans des applications en mode console (c'est­à­dire des programmes textuels exécutés
dans une fenêtre DOS) ; le package Visual C++ 5.0 inclut un bon compilateur C conforme à la norme ANSI C.

J'ai configuré mon environnement de développement de manière à ce que tous les programmes C de ce livre
puissent être compilés et transformés en applications console. De plus, je teste et exécute les applications créées
à partir des programmes C à une invite DOS fournie par Windows 95.

Dans les deux sections suivantes, je vais vous montrer brièvement comment utiliser les compilateurs C de
Microsoft et de Boralnd.
Machine Translated by Google

18 Heure 1

Utilisation du compilateur de Microsoft


Je vais vous montrer comment utiliser le compilateur C fourni avec le package Visual C++ de Microsoft
dans cette section. Si vous avez besoin d'en savoir plus sur l'installation de Visual C++, veuillez suivre
les instructions fournies avec le compilateur.

Maintenant, je suppose que vous avez installé une copie de Visual C++ 5.0 sur votre ordinateur. Pour
démarrer le compilateur, vous pouvez cliquer sur le bouton Démarrer de votre Windows 95 (ou 98 ou
NT), et choisir : Programmes, Microsoft Visual C++ 5.0, Microsoft Visual C++ 5.0. Ou, vous pouvez
simplement exécuter le fichier d'application MSDEV.EXE directement à partir du répertoire (dossier) où
vous avez installé le package Visual C++. La figure 1.3 montre un exemple de l'environnement de
développement intégré (IDE) de Visual C++ 5.0.

FIGURE 1.3
Un exemple de l'IDE de
Visual C++ version 5.0.

Ensuite, vous pouvez ouvrir un nouveau fichier dans l'IDE en cliquant sur le bouton Nouveau fichier à
l'extrême gauche de la barre d'outils et saisir le texte suivant dans l'espace du nouveau fichier :
#include <stdio.h>

principale()

{
printf ("Bonjour, voisin ! C'est mon premier programme C.\n" ); renvoie 0 ;

}
Machine Translated by Google

Faire le premier pas 19

La figure 1.4 montre l'EDI avec le texte que vous venez de saisir. Ne vous souciez pas de la signification du texte.
Dans le chapitre suivant, "Votre premier programme C", vous l'expliquera.
1
FIGURE 1.4
Écriture de code dans
l'IDE Visual C++ 5.0.

Ensuite, vous devez enregistrer le texte dans un fichier. Appelons le fichier MyFirstProgram.c. C'est aussi une bonne
idée de créer un nouveau répertoire sur votre disque dur pour stocker vos projets de programmation et d'y enregistrer
le nouveau fichier. Tout d'abord, cliquez sur le bouton Enregistrer dans la barre d'outils. Dans la boîte de dialogue
Enregistrer sous, cliquez sur le bouton Nouveau dossier et saisissez un nom pour votre dossier de programmation.
Double­cliquez ensuite sur ce dossier pour l'ouvrir, saisissez MyFirstProgram.c dans la zone Nom de fichier, puis
cliquez sur Enregistrer. Notez que l'extension .c est utilisée pour indiquer que le fichier que vous venez d'enregistrer
est un fichier de programme C.

Maintenant, vous devez cliquer sur le menu Construire et choisir l'option Compiler MyFirstProgram.c. Ce
faisant, vous demandez au compilateur de compiler le texte que vous venez de saisir et d'enregistrer (voir Figure 1.5).
À ce stade, Visual C++ peut vous inviter à créer un nouvel espace de travail ; cliquez simplement sur Oui et cela se
fera automatiquement. Il ne devrait pas y avoir d'erreurs ou d'avertissements dans la fenêtre de sortie après l'exécution
du compilateur.

Ensuite, cliquez à nouveau sur le menu Construire, et cette fois, choisissez l'option Construire MyFirstProgram.exe
qui finira par produire un fichier exécutable appelé MyFirstProgram.exe.
La figure 1.6 montre qu'il n'y a pas d'erreurs ou d'avertissements après la génération de MyFirstProgram.exe .
Machine Translated by Google

20 Heure 1

FIGURE 1.5

Compilation d'un
programme C à l'aide de l'IDE.

FIGURE 1.6

Création d'un fichier


exécutable de programme.

Vous êtes maintenant prêt à exécuter le fichier exécutable, MyFirstProgram.exe, que vous venez de
compiler. Vous pouvez l'exécuter à partir du chemin du menu : Build, Execute MyFirstProgram.exe. Étant
donné que le fichier exécutable est une application en mode console, une fenêtre d'invite DOS s'affiche
lorsque le fichier exécutable est en cours d'exécution (voir Figure 1.7).
Machine Translated by Google

Faire le premier pas 21

FIGURE 1.7

Exécution d'un programme C.


1

Vous pouvez voir que la première ligne de la fenêtre d'invite DOS illustrée à la figure 1.7 est la ligne
exacte que vous venez de taper : « Howdy neighbor ! C'est mon premier programme en C. C'est en
effet votre première sortie de programme C ! (Notez que la deuxième ligne affichée dans l'invite DOS
n'est qu'un rappel intégré de la fenêtre d'invite DOS.)

D'accord. Je viens de montrer comment utiliser le compilateur Visual C++ pour écrire et compiler un
programme C, et comment rendre le programme exécutable. Pour plus de détails, vous devez lire des
livres tels que Teach Yourself Visual C++ 5 in 21 Days qui se concentrent sur l'apprentissage de l'utilisation
du compilateur Visual C++.

Utilisation du compilateur de Borland Dans cette


section, je vais vous montrer comment utiliser le compilateur C fourni avec le package C++ de
Borland. La procédure de la section est assez similaire à celle de la section précédente. Si vous avez
besoin d'en savoir plus sur l'installation de Borland C++, veuillez suivre les instructions fournies avec le
compilateur.

Je suppose que vous avez installé une copie de Borland C++ 5.02 sur votre ordinateur. Pour démarrer le
compilateur, vous pouvez cliquer sur le bouton Démarrer de la barre des tâches de Windows 95 (ou
Windows 98 ou NT) et choisir Programmes, Borland C++ 5.02, Borland C++. Ou, vous pouvez simplement
exécuter le fichier d'application bcw.exe directement à partir du répertoire (dossier) où vous avez installé
le package Borland C++. La figure 1.8 montre un exemple de l'environnement de développement intégré
(IDE) de Borland C++ 5.02.

Ensuite, vous pouvez ouvrir un nouveau fichier dans l'IDE et saisir le texte suivant dans l'espace du fichier
nouvellement ouvert :
#include <stdio.h>

principale()

{
printf ("Bonjour, voisin ! C'est mon premier programme C.\n" ); renvoie 0 ;

}
Machine Translated by Google

22 Heure 1

FIGURE 1.8

Créer un programme avec


Borland C++

SE REND.

La figure 1.9 montre l'IDE avec le texte que vous venez de taper. Ne vous souciez pas du sens
du texte. La prochaine heure vous l'expliquera.

FIGURE 1.9

Enregistrement du texte du
programme C avec l'IDE de Borland.
Machine Translated by Google

Faire le premier pas 23

Vous devez maintenant enregistrer le texte dans un fichier. Appelons le fichier MyFirstProgram.c. Notez que
l'extension .c est utilisée pour indiquer que le fichier que vous venez d'enregistrer est un fichier de programme C.
1
Maintenant, vous devez cliquer sur le menu Projet et choisir l'option Compiler. Ce faisant, vous demandez au
compilateur de commencer à compiler le texte que vous venez de taper et d'enregistrer. La figure 1.10 montre
qu'il n'y a pas d'erreurs ou d'avertissements après la compilation de MyFirstProgram.c et la création de
MyFirstProgram.exe .

FIGURE 1.10

Compilation d'un
programme C à l'aide de
l'IDE de Borland.

Vous êtes maintenant prêt à exécuter le fichier exécutable, MyFirstProgram.exe, que vous venez de compiler.
Vous pouvez l'exécuter en cliquant sur le bouton Exécuter de la barre d'outils. Ou, vous pouvez exécuter
MyFirstProgram.exe directement à partir du répertoire dans lequel vous l'avez créé. Parce que le fichier exécutable
est en fait une application DOS, une fenêtre d'invite DOS apparaîtra lorsque le fichier exécutable est en cours
d'exécution (voir Figure 1.11).

FIGURE 1.11

Exécution d'un programme


C à l'aide de l'IDE de Borland.
Machine Translated by Google

24 Heure 1

La figure 1.11 affiche la sortie exactement telle que vous venez de la saisir : « Howdy neighbor ! C'est mon
premier programme en C. C'est en effet votre première sortie de programme C !

Si vous souhaitez en savoir plus sur l'utilisation de Borland C++, lisez un livre tel que Teach Yourself Borland
C++ 5 in 21 Days.

Voici une brève note sur le code binaire et les fichiers exécutables. Vous apprendrez
plus de détails plus tard dans ce livre. Fondamentalement, avant de pouvoir exécuter un
programme C sur votre ordinateur, vous devez utiliser un compilateur C pour traduire le
programme C en code compréhensible par la machine (c'est­à­dire en code binaire). Une
fois la traduction terminée, le code binaire peut être enregistré dans un fichier d'application.
Le code binaire ou fichier d'application est appelé code exécutable, ou fichier exécutable,
car il peut être exécuté directement sur votre ordinateur.

Résumé
Dans cette première leçon, vous avez appris les éléments de base suivants sur le langage C :

• C est un langage de programmation généraliste. • C est un

langage de haut niveau qui a les avantages de la lisibilité, de la maintenabilité,


et portabilité.

• C est un langage très efficace qui permet de contrôler le matériel informatique et


périphériques.

• C est un petit langage que vous pouvez facilement apprendre en relativement peu de

temps. • Les programmes écrits en C peuvent être réutilisés. • Les programmes écrits en C

doivent être compilés et traduits en code lisible par machine avant que l'ordinateur puisse les exécuter. •
De nombreux autres langages de programmation, tels que Perl, C++ et Java, ont adopté

concepts de base et fonctionnalités utiles du langage C. Une fois que vous avez appris le C, apprendre
ces autres langages est beaucoup plus facile. • La norme ANSI pour C est la norme prise en charge par

les fournisseurs de compilateurs C pour


tain la portabilité des programmes C.

• Vous pouvez utiliser n'importe quel compilateur compatible ANSI C pour compiler tous les programmes C dans
ce livre.

Dans la prochaine leçon, vous apprendrez à écrire votre premier programme en C.


Machine Translated by Google

Faire le premier pas 25

Questions et réponses

Q Quel est le langage de plus bas niveau dans le monde informatique ? 1


R Le langage machine de l'ordinateur est le plus bas car le langage machine, composé de 0 et de 1, est le
seul langage que l'ordinateur peut comprendre directement.

Q Quels sont les avantages des langages de programmation de haut niveau ?

R La lisibilité, la maintenabilité et la portabilité sont les principaux avantages des langages de programmation
de haut niveau.

Q Qu'est­ce que C, de toute façon ?

A C est un langage de programmation à usage général. C'est un langage de haut niveau qui présente des
avantages tels que la lisibilité, la maintenabilité et la portabilité. De plus, C vous permet de descendre au
niveau matériel pour augmenter la vitesse de performance si nécessaire. Le compilateur AC est nécessaire
pour traduire les programmes écrits en C en code compréhensible par la machine. La portabilité de C est
réalisée en recompilant les programmes C avec différents compilateurs C destinés à différents types
d'ordinateurs.

Q Puis­je apprendre le C en peu de temps ?

R Oui. C est un petit langage de programmation. Il n'y a pas beaucoup de mots­clés C ou com
mandes à retenir. De plus, il est très facile de lire et d'écrire des programmes C car C est un langage de
programmation de haut niveau proche des langages humains, en particulier l'anglais. Vous pouvez apprendre
le C en relativement peu de temps.

Atelier
Pour aider à consolider votre compréhension de la leçon de cette heure, nous vous encourageons à répondre aux
questions du quiz fournies dans l'atelier avant de passer à la leçon suivante. Les réponses et les conseils aux
questions sont donnés dans l'annexe D, « Réponses aux questions et exercices du quiz ».

Questionnaire

1. Quels sont les langages de niveau le plus bas et de niveau le plus élevé mentionnés dans ce livre ?

2. Un ordinateur peut­il comprendre directement un programme écrit en C ? De quoi avez­vous besoin pour
traduire un programme écrit en C en code compréhensible par la machine (c'est­à­dire en code binaire) ?

3. Si nécessaire, un programme C peut­il être réutilisé dans un autre programme C ?

4. Pourquoi avons­nous besoin de la norme ANSI pour le langage C ?


Machine Translated by Google
Machine Translated by Google

HEURE 2
Écrire votre premier C
Programme
Coupez votre propre bois et il vous réchauffera deux fois.

­Proverbe chinois

Au cours de la première heure, "Faire le premier pas", vous avez appris que le C est un
langage de programmation de haut niveau et que vous avez besoin d'un compilateur C pour
traduire vos programmes C en code binaire que votre ordinateur peut comprendre et exécuter.
Dans cette leçon, vous allez écrire votre premier programme C et apprendre les bases d'un
programme C, telles que

• La directive #include

• Fichiers d'en­tête

• Commentaires

• La fonction main()

• La déclaration de retour

• La fonction exit()
Machine Translated by Google

28 Heure 2

• Le caractère de nouvelle ligne (\n)

• Traduction d'un programme C en un fichier exécutable •

Débogage

Un programme en C simple
Jetons un coup d'œil à votre premier programme C, illustré dans le Listing 2.1. Plus tard dans cette leçon,
vous allez écrire votre propre programme C pour la première fois.

LISTE 2.1 Un programme en C simple

1 : /* 02L01.c : c'est mon premier programme C */


2 : #include <stdio.h> 3 : 4 : main() 5 : { 6 : 7 :

printf ("Bonjour, voisin ! C'est mon premier programme C.\n" ); renvoie 0 ;

8:}

Il s'agit d'un programme C très simple, qui est enregistré dans un fichier appelé 02L01.c. Notez que le nom
d'un fichier de programme C doit avoir une extension .c. Si vous avez installé un compilateur C et configuré
l'environnement de développement approprié, vous devriez pouvoir compiler ce programme C et en faire un
fichier exécutable. J'expliquerai comment créer un fichier exécutable plus loin dans ce chapitre.

Au cours de l'heure précédente, vous avez appris à entrer un programme dans votre éditeur de texte et à
l'enregistrer en tant que fichier de programme C. Ici, vous remarquerez peut­être que contrairement à
l'exemple du dernier chapitre, chaque ligne est numérotée. Ceci n'est fait ici qu'à titre de référence lorsque je
discute de ce que fait chaque ligne d'un programme. Contrairement à d'autres langages tels que BASIC, le
langage C n'a pas du tout de numéros de ligne. En fait, si vous entrez les numéros de ligne dans la liste, votre
programme ne fonctionnera pas ! Ainsi, lorsque vous entrez dans ces programmes, n'oubliez pas de ne pas
entrer les numéros de ligne indiqués dans le livre.

Deux choses que vous remarquerez peut­être en jetant un coup d'œil au Listing 2.1 sont les
points­virgules et l'indentation sur les lignes 6 et 7. Contrairement à d'autres langages, comme le
BASIC, la fin d'une ligne n'a pas de signification particulière en C. C'est parfaitement légal (et dans
de nombreux cas , conseillé) pour diviser une déclaration en plusieurs lignes pour plus de clarté.
En règle générale, une instruction C individuelle se termine par un point­virgule, mais nous en
dirons plus à ce sujet plus loin dans le livre. L'indentation sert à identifier les différents niveaux
Machine Translated by Google

Écrire votre premier programme en C 29

els d'un programme dans une sorte de format de plan. La fonction main() est, eh bien, le
niveau principal du programme, donc elle va à l'extrême gauche. Les lignes 6 et 7 font
partie de main() donc elles sont en retrait d'un niveau vers la droite. Habituellement, vous
utilisez votre touche Tab pour indenter un niveau avant de commencer à taper. Il convient
de noter que l'indentation, comme les numéros de ligne, n'est pas appliquée ­ ni même
remarquée ! — par le compilateur. Le programmeur est libre d'utiliser des sauts de ligne et
des indentations, communément appelés espaces, pour rendre le programme lisible. C'est
généralement une question de style, mais c'est une bonne idée de suivre les conventions 2
généralement acceptées afin que les autres programmeurs puissent comprendre vos
programmes et vice­versa. Jetez un coup d'œil à l'utilisation des espaces blancs dans les
programmes de ce livre et n'hésitez pas à développer votre propre style au fur et à mesure.

J'ai configuré mon environnement de développement de manière à ce que tous les programmes C de ce livre
puissent être compilés et transformés en applications console. Par exemple, 02L01.exe est le nom de l'application
console créée à partir de 02L01.c. Notez que .exe est inclus comme extension du nom d'un programme d'application
DOS ou Windows (c'est­à­dire un fichier exécutable).

De plus, sur ma machine, j'enregistre tous les fichiers exécutables créés à partir des programmes C de ce livre
dans un répertoire dédié appelé C:\app. Par conséquent, si je tape 02L01 à partir d'une invite DOS et que j'appuie
sur la touche Entrée, je peux exécuter le fichier exécutable 02L01.exe et afficher le message Salut, voisin ! C'est
mon premier programme en C. sur l'écran. La sortie suivante est une copie de l'écran :

Salut voisin! C'est mon premier programme en C.


SORTIR

commentaires
Examinons maintenant de près le programme C du Listing 2.1.

La première ligne contient un commentaire :

/* 02L01.C : Ceci est mon premier programme C */

Vous remarquez que cette ligne commence par une combinaison de barre oblique et d'astérisque, /*, et se termine
par */. En C, /* est appelé la marque de commentaire d'ouverture et */ est la marque de commentaire de fermeture.
Le compilateur C ignore tout ce qui se trouve entre la marque de commentaire d'ouverture et la marque de
commentaire de fermeture. Cela signifie que le commentaire dans la première ligne du Listing 2.1, 02L01.C : Ceci
est mon premier programme C, est complètement ignoré par le compilateur.

Le seul but d'inclure des commentaires dans votre programme C est de vous aider à documenter ce que font
le programme ou certaines sections spécifiques des programmes. N'oubliez pas que les commentaires sont écrits
pour vous­même et pour les autres programmeurs. Par exemple, lorsque vous lisez quelqu'un d'autre
Machine Translated by Google

30 Heure 2

code, les commentaires dans le code vous aident à comprendre ce que fait le code, ou du moins ce que le code
a l'intention de faire. Au fur et à mesure que vos programmes deviennent plus volumineux et plus compliqués, vous
pouvez utiliser des commentaires pour vous écrire des notes sur ce que vous essayez de faire et pourquoi.

Vous n'avez pas à vous soucier de la taille ou de la vitesse de performance de votre programme C si
vous y ajoutez de nombreux commentaires. L'ajout de commentaires dans un programme C
n'augmente pas la taille du code binaire du programme (c'est­à­dire le fichier exécutable), bien que la
taille du programme lui­même (c'est­à­dire le code source) puisse augmenter. La vitesse de
performance du fichier exécutable créé à partir de votre programme C n'est en aucun cas affectée par
les commentaires à l'intérieur de votre programme C.

Le langage C vous permet d'écrire un commentaire qui traverse plus d'une ligne. Par exemple,
vous pouvez écrire un commentaire en C comme ceci :
/*
Ce commentaire n'augmente pas la taille du fichier
exécutable (code binaire), ni n'affecte la vitesse de
performance.
*/

ce qui équivaut à ceci :


/* Ce commentaire n'augmente pas la taille */ /* du fichier
exécutable (code binaire), et */ /* n'affecte pas non plus la
vitesse de performance. */

De nos jours, il existe une autre façon de mettre des commentaires dans un programme C. C+
+ a commencé à utiliser deux barres obliques (//) pour marquer le début d'une ligne de
commentaire ; de nombreux compilateurs C utilisent désormais également cette convention. Le
commentaire se termine à la fin de la ligne. Par exemple, si j'écris un programme C en Borland C+
+ ou Visual C++, les deux commentaires suivants sont identiques :
/*
Ce commentaire n'augmente pas la taille de
le fichier exécutable (code binaire), ni n'affecte la
vitesse de performance.

*/ // Ce commentaire n'augmente pas // la taille du fichier


exécutable (code binaire), ni // n'affecte la vitesse de
performance.

Notez que ce nouveau style d'utilisation de // comme marque de début d'un commentaire n'a
pas été approuvé par l'ANSI. Assurez­vous que votre compilateur C prend en charge // avant
de l'utiliser.
Machine Translated by Google

Écrire votre premier programme en C 31

Une chose qui doit être soulignée est que la norme ANSI ne prend pas en charge les commentaires
imbriqués, c'est­à­dire les commentaires dans les commentaires. Par exemple, ce qui suit n'est pas
autorisé par la norme ANSI :

/* Ceci est la première partie du premier commentaire


/* Ceci est le deuxième commentaire */
Ceci est la deuxième partie du premier commentaire */

2
Vous pouvez utiliser la marque de commentaire d'ouverture, /*, et la marque de commentaire de fermeture,
*/, pour vous aider à tester et à corriger les erreurs trouvées dans votre programme C. Ceci est
communément appelé commenter un bloc de code. Vous pouvez commenter une ou plusieurs instructions
C dans votre programme C avec /* et */ lorsque vous devez vous concentrer sur d'autres instructions et
surveiller de près leurs comportements. Le compilateur C ignorera les instructions que vous commentez.

Plus tard, vous pouvez toujours restaurer les instructions précédemment commentées simplement en
supprimant les marques de commentaire d'ouverture et de fermeture. De cette façon, vous n'avez pas
besoin d'effacer ou de réécrire les instructions pendant les tests et le débogage.

Cependant, comme vous ne pouvez pas imbriquer les commentaires faits avec /* et */, si vous
essayez de commenter du code qui contient déjà ces commentaires, votre programme ne se compilera
pas. L'une des raisons pour lesquelles les commentaires de type // sont si utiles est que vous pouvez les
imbriquer, et donc les commenter légalement avec /* et */.

Si votre éditeur de texte prend en charge la coloration syntaxique des couleurs, vous pouvez l'utiliser pour
savoir en un coup d'œil si des sections de code sont réellement commentées comme vous le souhaitiez.

La directive #include
Passons maintenant à la ligne 2 du programme C du Listing 2.1 :

#include <stdio.h>

Vous voyez que cette ligne commence par un signe dièse, #, suivi de include. En C, #include forme
une directive de préprocesseur qui indique au préprocesseur C de rechercher un fichier et de placer
le contenu de ce fichier à l'emplacement indiqué par la directive #include .

Le préprocesseur est un programme qui effectue certaines préparations pour le compilateur C avant
que votre code ne soit compilé. Plus de détails sur le préprocesseur C sont abordés dans l'Heure 23, «
Compilation de programmes : le préprocesseur C ».

Toujours dans cette ligne, vous voyez que <stdio.h> suit #include. Vous pouvez deviner que le fichier
demandé par la directive #include s'appelle stdio.h. Vous avez tout à fait raison ! Ici, la directive #include
demande au préprocesseur C de rechercher et de placer stdio.h à l'emplacement de la directive dans le
programme C.
Machine Translated by Google

32 Heure 2

Le nom du fichier stdio.h signifie fichier d'en­tête d'entrée­sortie standard . Le fichier stdio.h contient de nombreux
prototypes et macros pour effectuer des entrées ou des sorties (E/S) pour les programmes C. Vous verrez plus d'E/S de
programme dans l'heure 5, « Gestion des entrées et sorties standard ».

Certains systèmes d'exploitation font la distinction entre les majuscules et les minuscules,
tandis que d'autres ne le font pas. Par exemple, stdio.h et STDIO.H sont des noms de fichiers
identiques sur un PC, alors qu'ils sont différents sous UNIX.

Fichiers d'en­tête
Les fichiers inclus par la directive #include , comme stdio.h, sont appelés fichiers d'en­tête car les directives #include
sont presque toujours placées au début ou à la tête des programmes C. En fait, le nom d'extension de .h signifie "en­
tête" et ceux­ci sont parfois appelés dans la conversation des fichiers point­h.

Outre stdio.h, il existe d'autres fichiers d'en­tête, tels que stdlib.h, string.h, math.h, etc. L'annexe A, "Fichiers d'en­tête
standard ANSI", donne une liste de tous les fichiers d'en­tête standard ANSI. Les fichiers d'en­tête spécifiques que
vous devez inclure dépendent des fonctions de bibliothèque spécifiques que vous avez l'intention d'appeler. La
documentation des fonctions de la bibliothèque vous indiquera quel fichier d'en­tête est requis.

Crochets angulaires (< >) et guillemets (" ")


Dans la deuxième ligne du Listing 2.1, il y a deux crochets angulaires, < et >, qui sont utilisés pour entourer stdio.h.
Vous vous demandez peut­être à quoi servent les équerres. En C, les chevrons demandent au préprocesseur C de
rechercher un fichier d'en­tête dans un répertoire autre que le cur
en louer un.

Par exemple, le répertoire courant contenant le fichier 02L01.C s'appelle C:\code sur mon ordinateur. Par conséquent,
les crochets angulaires autour de <stdio.h> indiquent au préprocesseur C de rechercher stdio.h dans un répertoire autre
que C:\code.

Si vous voulez laisser le préprocesseur C chercher d'abord dans le répertoire courant un fichier d'en­tête avant qu'il ne
commence à chercher ailleurs, vous pouvez utiliser des guillemets doubles pour entourer le nom du fichier d'en­tête. Par
exemple, lorsque le préprocesseur C voit "stdio.h", il regarde dans le répertoire courant, qui est C:\code sur ma machine,
avant de chercher ailleurs le fichier d'en­tête stdio.h .

Normalement, les fichiers d'en­tête sont enregistrés dans un sous­répertoire appelé include. Par exemple, j'installe
un compilateur Microsoft C dans le répertoire MSVC sur mon disque dur, qui est étiqueté comme le lecteur C. Ensuite,
le chemin d'accès aux fichiers d'en­tête devient C:\MSVC\include.
Machine Translated by Google

Écrire votre premier programme en C 33

Le chemin où sont conservés les fichiers d'en­tête est généralement déterminé par votre compilateur
lorsque vous l'installez. Ceci est communément appelé le répertoire d'inclusion ou le chemin d'inclusion de
votre environnement. Normalement, vous n'avez jamais à vous soucier du répertoire d'inclusion tant que
vous n'avez pas créé vos propres fichiers d'en­tête. Pour l'instant, il vous suffit de spécifier le nom du fichier
d'en­tête que vous souhaitez inclure.

La fonction principale() 2
À la ligne 4 du Listing 2.1, vous voyez cette fonction :

principale ()

C'est une fonction très spéciale en C. Chaque programme C doit avoir une fonction main() , et chaque
programme C ne peut avoir qu'une seule fonction main() . Des discussions plus génériques sur les fonctions
sont données dans l'heure 3, "Apprentissage de la structure d'un programme C".

Vous pouvez mettre la fonction main() où vous voulez dans votre programme C. Cependant, l'exécution
de votre programme commence toujours par la fonction main() . Si vous créez d'autres fonctions dans
votre programme, main() s'exécutera toujours en premier, même si elle se trouve en bas de votre fichier
programme.

Dans le Listing 2.1, le corps de la fonction main() commence à la ligne 4 et se termine à la ligne 8. Comme il
s'agit d'un programme très simple, la fonction main() est la seule fonction définie dans le programme.
Dans le corps de la fonction main() , une fonction de la bibliothèque C, printf(), est appelée afin d'imprimer un
message d'accueil (voir ligne 6). Plus de détails sur printf() sont couverts dans l'heure 5.

Une autre chose importante à propos de main() est que l'exécution de chaque programme C se termine
par main(). Un programme se termine lorsque toutes les instructions de la fonction main() ont été exécutées.

Le caractère de saut de ligne (\n)


Dans la fonction printf() , une chose qui mérite d'être mentionnée à ce stade est le caractère de retour à la
ligne , \n. Habituellement suffixé à la fin d'un message, le caractère de nouvelle ligne indique à l'ordinateur de
déplacer le curseur au début de la ligne suivante afin que tout ce qui est imprimé après le message commence
sur la ligne suivante à l'écran.

Dans un environnement UNIX, \n va de lui­même à une nouvelle ligne mais laisse le curseur à la position où il
se trouvait sur la ligne précédente. Dans ce cas, il est nécessaire d'imprimer \r\n plutôt que \n uniquement. Le
caractère \r est le caractère de retour chariot . Lorsque vous exécutez les exemples de programmes de ce
livre, vous serez en mesure de dire immédiatement si le curseur revient au début de la nouvelle ligne ; si ce
n'est pas le cas, utilisez simplement \r\n partout où vous voyez \n dans les listes de programmes.

L'exercice 3 de cette leçon vous permet d'utiliser le caractère de saut de ligne pour diviser un message
d'une ligne en deux lignes.
Machine Translated by Google

34 Heure 2

La déclaration de retour
Toutes les fonctions en C peuvent renvoyer des valeurs. Par exemple, lorsque vous créez une fonction pour
additionner deux nombres, vous pouvez créer une telle fonction qui vous renvoie la valeur de l'addition.

La fonction main() renvoie elle­même une valeur entière. En C, les nombres entiers sont des nombres
décimaux sans fractions.

Par conséquent, à la ligne 7 du Listing 2.1, il y a une instruction, return 0;, qui indique que 0 est renvoyé par
la fonction main() et que le programme se termine normalement. Dans certains cas, vous devez terminer
votre programme en raison d'une condition d'erreur. Lorsque cela se produit, vous pouvez renvoyer des
valeurs autres que 0 pour indiquer au système d'exploitation (ou au programme qui a exécuté votre
programme) qu'il y a eu une erreur.

La fonction exit() Il existe également

une fonction de la bibliothèque C, exit(), qui peut être utilisée pour terminer un programme. Étant donné
que la fonction exit() est définie dans un fichier d'en­tête, stdlib.h, vous devez inclure le fichier d'en­tête au
début de votre programme afin d'utiliser la fonction. La fonction exit() elle­même ne renvoie pas de valeur à
votre programme.

Notez que return et exit() peuvent également être utilisés dans d'autres fonctions. Vous verrez d'autres
exemples du mot­clé return dans le reste du livre.

Compilation et liaison
Vous êtes peut­être déjà anxieux de savoir comment un fichier exécutable est créé. Voyons comment
un programme C est compilé et traduit en un fichier exécutable. Comme le montre la figure 2.1, il y a au
moins trois étapes nécessaires pour créer un fichier exécutable.

Tout d'abord, un fichier de programme écrit en C, appelé code source, est créé. Le nom du fichier de
code source se termine par l'extension .c.

Ensuite, le fichier de code source est compilé par un compilateur C, qui crée un nouveau fichier. Le
nouveau fichier est un fichier objet. Dans le système d'exploitation UNIX, le nom d'un fichier objet se termine
par l'extension .o ; Dans les systèmes d'exploitation DOS et Windows, l'extension est .obj.

Vous ne pouvez pas exécuter le fichier objet car il manque du code de fonction. Vous devez terminer l'étape
suivante : la liaison. La liaison est effectuée en appelant un programme spécial appelé éditeur de liens, qui
est normalement fourni avec le package du compilateur.

Un éditeur de liens est utilisé pour lier ensemble le fichier objet, la bibliothèque C standard ANSI et d'autres
bibliothèques générées par l'utilisateur pour produire un fichier exécutable, le code binaire. Dans cette
étape, le code binaire des fonctions de la bibliothèque qui sont appelées dans le code source est combiné
Machine Translated by Google

Écrire votre premier programme en C 35

avec le fichier objet ; le résultat est enregistré dans un nouveau fichier, un fichier exécutable.
Comme vous l'avez appris dans le premier chapitre du livre, le nom d'un fichier exécutable se termine
généralement par l'extension .exe sous DOS et Windows. (.com est une autre extension utilisée pour un
nom de fichier exécutable DOS.) Sous UNIX, il n'est pas nécessaire d'inclure une telle extension à un
nom de fichier exécutable.

FIGURE 2.1 Les fichiers d'en­tête Le programme C

Faire un exécutable
stdio.h 2
fichier par le compilateur et stdlib.h /* 02L01.C */
l'éditeur de liens. .....

Fichiers de bibliothèque
Le compilateur C et

Autres fichiers objets

L'éditeur de liens

Le fichier exécutable

10011111001
0111000011
110001100

Plus tard, vous apprendrez que dans de nombreux cas, il peut y avoir plusieurs fichiers objets qui
doivent être liés ensemble afin de créer un programme exécutable.

Notez que le fichier objet et le fichier exécutable dépendent tous deux de la machine. Vous ne pouvez
pas simplement déplacer un fichier exécutable de la plate­forme informatique actuelle vers une autre
qui est exploitée par un système d'exploitation différent, bien que le code source du fichier exécutable,
vraisemblablement écrit en ANSI C, puisse être indépendant de la machine (c'est­à­dire portable) .
Machine Translated by Google

36 Heure 2

La portabilité est un concept important en C, car c'était l'un des objectifs de conception
originaux du langage. La portabilité du code C est ce qui a alimenté sa large utilisation et
sa popularité. À l'époque où les applications et les systèmes d'exploitation étaient adaptés à
un système informatique spécifique, les logiciels devaient être écrits à partir de zéro chaque
fois qu'un nouvel ordinateur arrivait. L'avènement du langage C a séparé le logiciel du
matériel et, dans un sens très réel, a contribué à donner naissance à l'industrie du logiciel
telle que nous la connaissons aujourd'hui.
La portabilité, par essence, fait référence au processus de portage d'un programme sur un
autre ordinateur et/ou système d'exploitation. Le développement de logiciels est un
processus long et coûteux, et la réécriture d'un programme existant pour qu'il fonctionne sur
un nouvel ordinateur est souvent une tâche ardue qu'il vaut mieux éviter. En supposant que
chaque combinaison de système d'exploitation et de compilateur est adaptée à l'ordinateur
spécifique sur lequel il est destiné à s'exécuter, un programme C devrait être facilement
portable avec seulement des modifications minimes du code. La portabilité est mentionnée
tout au long de ce livre, car il est important que les programmes C ne fassent pas
d'hypothèses sur le système informatique spécifique sur lequel ils s'exécutent.
Heureusement, la norme ANSI C fournit de nombreuses caractéristiques et fonctions qui
permettent à votre programme de s'adapter essentiellement à son environnement, au lieu
d'agir sur des hypothèses faites par vous, le programmeur. Si vous prenez l'habitude de
maintenir la portabilité dès le début, alors que vous progressez avec C, l'idée deviendra
une seconde nature.

Qu'est­ce qui ne va pas avec mon programme ?


Lorsque vous avez fini d'écrire un programme C et commencé à le compiler, vous pouvez recevoir des messages
d'erreur ou d'avertissement. Ne paniquez pas lorsque vous voyez des messages d'erreur. Nous sommes des êtres humains.
Tout le monde fait des erreurs. En fait, vous devriez comprendre que votre compilateur détecte certaines erreurs pour
vous avant d'aller plus loin.

Habituellement, votre compilateur peut vous aider à vérifier la grammaire ­ c'est­à­dire la syntaxe ­ de votre programme
C et à vous assurer que vous avez correctement suivi les règles de programmation C. Par exemple, si vous oubliez de
mettre l'accolade de fin sur la fonction main() à la ligne 8 du Listing 2.1, vous obtiendrez un message d'erreur du genre :
erreur de syntaxe : fin de fichier trouvée.

En outre, l'éditeur de liens émettra un message d'erreur s'il ne trouve pas le code manquant pour une fonction
nécessaire dans les bibliothèques. Par exemple, si vous orthographiez mal printf() comme pprintf() dans le programme
du Listing 2.1, vous verrez un message d'erreur : '_pprintf' : unresolved external (ou quelque chose de similaire).

Toutes les erreurs trouvées par le compilateur et l'éditeur de liens doivent être corrigées avant qu'un fichier
exécutable (code binaire) puisse être créé.
Machine Translated by Google

Écrire votre premier programme en C 37

Débogage de votre programme


Dans le monde informatique, les erreurs de programme sont également appelées bogues. Dans de nombreux cas, votre

compilateur C et votre éditeur de liens ne trouvent aucune erreur dans votre programme, mais le résultat obtenu en

exécutant le fichier exécutable du programme n'est pas celui que vous attendiez. Afin de trouver ces erreurs "cachées" dans

votre programme, vous devrez peut­être utiliser un débogueur.

Normalement, votre compilateur C inclut déjà un logiciel de débogage. Le débogueur peut exécuter votre programme une

ligne à la fois afin que vous puissiez surveiller de près ce qui se passe avec le code dans chaque ligne, ou pour que vous 2
puissiez demander au débogueur d'arrêter l'exécution de votre programme sur n'importe quelle ligne. Pour plus de détails sur

votre débogueur, reportez­vous aux instructions fournies avec votre compilateur C.

Plus loin dans ce livre, vous apprendrez que le débogage est une étape très nécessaire et importante dans l'écriture de

programmes logiciels. (Ce sujet est traité dans l'heure 24, "Où allez­vous à partir d'ici".)

Résumé
Dans cette leçon, vous avez appris les concepts et énoncés suivants concernant le langage C :

• Certains fichiers d'en­tête doivent être inclus au début de votre programme C.

• Les fichiers d'en­tête, tels que stdio.h et stdlib.h, contiennent les déclarations des fonctions utilisées dans votre

programme C ; par exemple, les fonctions printf() et exit() .

• Les commentaires dans vos programmes C sont nécessaires pour vous aider à documenter vos programmes.

Vous pouvez mettre des commentaires n'importe où dans vos programmes.

• En ANSI C, un commentaire commence par la marque de commentaire d'ouverture, /*, et se termine par

la marque de commentaire de fermeture, */.

• Chaque programme C doit avoir une mais une seule fonction main() . Le programme exe
cution commence et se termine avec la fonction main() .

• L' instruction return peut être utilisée pour renvoyer une valeur pour indiquer au système d'exploitation si une erreur

s'est produite. La fonction exit() termine un programme ; l'argument de la fonction indique également l'état de l'erreur.

• La compilation et la liaison sont des étapes consécutives qui doivent être terminées avant qu'un fichier exécutable ne

soit produit.

• Tout le monde, y compris vous et moi, fait des erreurs de programmation. Le débogage est

une étape très importante dans la conception et le codage de votre programme.

Dans la prochaine leçon, vous en apprendrez plus sur les bases des programmes C.
Machine Translated by Google

38 Heure 2

Questions et réponses

Q Pourquoi avez­vous besoin de mettre des commentaires dans vos programmes ?

A Les commentaires vous aident à documenter ce que fait un programme. Surtout quand un programme devient
très complexe, vous devez écrire des commentaires pour expliquer les différentes parties du programme.

Q Pourquoi la fonction main() est­ elle nécessaire dans un programme ?

A L'exécution d'un programme C commence et se termine par la fonction main() . Sans pour autant
la fonction main() , l'ordinateur ne sait pas par où commencer pour exécuter un programme.

Q Que fait la directive #include ?

A La directive #include est utilisée pour inclure les fichiers d'en­tête contenant les déclarations

aux fonctions utilisées dans votre programme C. En d'autres termes, la directive #include indique au
préprocesseur C d'examiner le chemin d'inclusion pour trouver le fichier d'en­tête spécifié.

Q Pourquoi avez­vous besoin d'un éditeur de liens ?

A Après la compilation, il se peut qu'il manque encore du code de fonction dans le fichier objet d'un
programme. Un éditeur de liens doit ensuite être utilisé pour lier le fichier objet à la bibliothèque standard C ou
à d'autres bibliothèques générées par l'utilisateur et inclure le code de fonction manquant afin qu'un fichier
exécutable puisse être créé.

Atelier
Pour aider à consolider votre compréhension de la leçon de cette heure, nous vous encourageons à répondre aux
questions du quiz et à terminer les exercices fournis dans l'atelier avant de passer à la leçon suivante. Les réponses
et les conseils aux questions et exercices sont donnés dans l'annexe D, « Réponses aux questions et exercices du
quiz ».

Questionnaire

1. Un compilateur C peut­il voir les commentaires dans votre programme C ?

2. Quel type de fichiers un compilateur C produit­il réellement ?

3. La fonction exit() renvoie­t­elle une valeur ? Qu'en est­il de la déclaration de retour ?

4. Qu'est­ce qu'un fichier d'en­tête ?


Machine Translated by Google

Écrire votre premier programme en C 39

Des exercices
1. #include <stdio.h> est ­il identique à #include "stdio.h" ?

2. Il est temps pour vous d'écrire un programme par vous­même. Se référant au programme de
Listing 2.1, écrivez un programme C capable d'afficher un message : C'est amusant d'écrire mon
propre programme en C.

3. Mettez à jour le programme du Listing 2.1 en ajoutant un caractère de retour à la ligne supplémentaire
dans le message imprimé par la fonction printf() . Vous devriez voir deux lignes du message à l'écran 2
après avoir exécuté le fichier exécutable mis à jour : Howdy, neighbor !

C'est mon premier programme en C.

4. Quels messages d'avertissement ou d'erreur, le cas échéant, obtiendrez­vous lors de la compilation du


programme suivant ?
#include <stdlib.h>
#include <stdio.h> main()
{

printf ("Bonjour, voisin ! C'est mon premier programme C.\n" ); sortie(0);

5. Quels messages d'erreur obtiendrez­vous pour le programme suivant lorsque vous essayez de
le compiler ?
void main() {

printf ("Bonjour, voisin ! C'est mon premier programme C.\n" ); renvoie 0 ;

}
Machine Translated by Google
Machine Translated by Google

HEURE 3

Apprendre la structure d'un


programme en C
Le tout est égal à la somme de ses parties.

­Euclide

Au cours de l'heure 2, "Écrire votre premier programme C", vous avez vu et écrit quelques
programmes C simples. Vous avez également appris la structure de base d'un programme C.
Vous savez qu'un programme écrit en C doit être compilé avant de pouvoir être exécuté. Dans
cette leçon, vous apprendrez plus d'éléments essentiels dans un programme C, tels que

• Constantes et variables

• Expressions
• Déclarations

• Blocs d'instructions

• Types et noms de fonctions C •

Arguments des fonctions • Le corps

d'une fonction
• Appels de fonction
Machine Translated by Google

42 Heure 3

Les bases d'un programme C


Comme un bâtiment est constitué de briques, un programme C est constitué d'éléments de base, tels que des
expressions, des instructions, des blocs d'instructions et des blocs fonctionnels. Ces éléments sont abordés dans
les sections suivantes. Mais d'abord, vous devez apprendre deux éléments plus petits mais importants, constant
et variable, qui composent les expressions.

Constantes et variables
Comme son nom l'indique, une constante est une valeur qui ne change jamais. Une variable, en revanche,
peut être utilisée pour présenter différentes valeurs.

Vous pouvez considérer une constante comme un CD­ROM musical ; la musique enregistrée sur le CD­ROM
n'est jamais modifiée. Une variable ressemble plus à une cassette audio : vous pouvez toujours mettre à jour le
contenu de la cassette en écrasant simplement les anciennes chansons avec les nouvelles.

Vous pouvez voir de nombreux exemples dans lesquels des constantes et des variables sont dans la même instruction.
Par exemple, considérez ce qui suit :

je = 1 ;

où le symbole 1 est une constante car il a toujours la même valeur (1), et le symbole i est affecté de la constante
1. En d'autres termes, i contient la valeur de 1 après l'exécution de l'instruction. Plus tard, s'il y a une autre
déclaration,

je = 10 ;

après son exécution, i reçoit la valeur 10. Comme i peut contenir différentes valeurs, on l'appelle une variable en
langage C.

Expressions Une

expression est une combinaison de constantes, de variables et d'opérateurs utilisés pour dénoter des calculs.

Par exemple, les éléments suivants :

(2 + 3) * 10

est une expression qui additionne d'abord 2 et 3, puis multiplie le résultat de l'addition par 10. (Le résultat final
de l'expression est 50.)

De même, l'expression 10 * (4 + 5) donne 90. L' expression 80/4 donne 20.

Voici d'autres exemples d'expressions :


Machine Translated by Google

Apprendre la structure d'un programme en C 43

Expression Description
6 Expression d'une constante.

je
Expression d'une variable.

6 + je Expression d'une constante plus une variable.

sortie(0) Expression d'un appel de fonction.

Opérateurs
Comme vous l'avez vu, une expression peut contenir des symboles tels que +, * et /. En langage
C, ces symboles sont appelés opérateurs arithmétiques. Le tableau 3.1 liste tous les opérateurs
arithmétiques et leurs significations.

TABLEAU 3.1 C Symbole des opérateurs


3
arithmétiques Sens
+ Une addition

­ Soustraction
* Multiplication
/ Division
% Reste (ou module)

Vous connaissez peut­être déjà tous les opérateurs arithmétiques, à l'exception de l'opérateur reste
(%) . % est utilisé pour obtenir le reste du premier opérande divisé par le deuxième opérande. Par
exemple, l'expression

6%4

donne une valeur de 2 car 4 va dans 6 une fois avec un reste de 2.

L'opérateur de reste, %, est également appelé opérateur de module.

Parmi les opérateurs arithmétiques, les opérateurs de multiplication, de division et de reste ont une
priorité plus élevée que les opérateurs d'addition et de soustraction. Par exemple, l'expression

2 + 3 * 10

donne 32, et non 50, en raison de la priorité plus élevée de l'opérateur de multiplication. 3 * 10
est calculé en premier, puis 2 est ajouté au résultat de la multiplication.
Machine Translated by Google

44 Heure 3

Comme vous le savez peut­être, vous pouvez mettre des parenthèses autour d'une addition (ou d'une
soustraction) pour forcer l'addition (ou la soustraction) à être effectuée avant une multiplication, une
division ou un calcul de module. Par exemple, l'expression

(2 + 3) * 10

effectue d'abord l'addition de 2 et 3 avant de multiplier le résultat par 10.

D'autres opérateurs, qui sont utilisés pour la syntaxe, incluent la virgule et le point­virgule. Le point­
virgule est généralement utilisé pour indiquer la fin d'une instruction, comme vous le verrez plus tard. La
virgule est utilisée dans certains cas où une instruction est composée d'une liste d'expressions ou de
déclarations.

Vous en apprendrez plus sur les opérateurs du langage C dans les heures 6, "Manipulation des données" et 8, "Utilisation
des opérateurs conditionnels".

Identifiants
Outre les nombres (tels que la constante 7) et les opérateurs (tels que le symbole +), les expressions
peuvent également contenir des mots appelés identificateurs. Les noms de fonctions (comme exit) et
les noms de variables (comme i), ainsi que les mots clés réservés, sont tous des identifiants en C.

Voici le jeu de caractères que vous pouvez utiliser pour créer un identifiant valide. Tous les caractères
ou symboles qui ne suivent pas ces règles sont illégaux à utiliser dans un identifiant.

• Caractères A à Z et a à z. • Caractères

numériques de 0 à 9 (mais ceux­ci ne peuvent pas être utilisés comme premier caractère d'un
identifiant).

• Le caractère de soulignement (_).

Par exemple, stop_sign, Loop3 et _pause sont tous des identifiants valides.

Les caractères suivants sont illégaux ; c'est­à­dire qu'ils ne respectent pas l'ensemble de règles ci­dessus pour
les identifiants :

• Signes arithmétiques C (+, ­, *, /).

• Point ou point (.).

• Apostrophes (') ou guillemets (“). •

Tout autre symbole spécial tel que *, @, #, ?, etc.

Certains identifiants non valides, par exemple, sont 4flags, sum­result, method*4
et what_size?.
Machine Translated by Google

Apprendre la structure d'un programme en C 45

N'utilisez jamais les mots­clés réservés ou les noms des fonctions de la bibliothèque C
standard pour les noms de variables ou les noms de fonctions que vous créez dans vos
propres programmes C.

Vous avez déjà vu le mot­clé return dans l'heure précédente. L'heure 4, « Comprendre les types de données et les
mots clés », répertorie tous les mots clés réservés.

Déclarations
En langage C, une instruction est une instruction complète, se terminant par un point­virgule. Dans de nombreux
cas, vous pouvez transformer une expression en instruction en ajoutant simplement un point­virgule à la fin de
l'expression.

Par exemple, les éléments suivants :


3
je = 1 ;

est une déclaration. Vous avez peut­être déjà compris que l'instruction se compose d'une expression de i = 1
et d'un point­virgule (;).

Voici d'autres exemples d'énoncés :

je = (2 + 3) * 10 ; je =
2 + 3 * 10 ; j = 6 % 4;
k = je + j ;

De plus, dans la première leçon de ce livre, vous avez appris des déclarations telles que

renvoie 0 ;
sortie(0);
printf ("Bonjour, voisin ! C'est mon premier programme C.\n" );

Blocs d'instructions
Un groupe d'instructions peut former un bloc d'instructions commençant par une accolade ouvrante ({) et se
terminant par une accolade fermante (}). Un bloc d'instructions est traité comme une seule instruction par le
compilateur C.

Par exemple, les éléments suivants :

pour(. . .) { s3
= s1 + s2; mul =
s3 * c; reste =
somme % c;
}
Machine Translated by Google

46 Heure 3

est un bloc d'instructions qui commence par { et se termine par }. Ici, for est un mot­clé en C qui détermine le bloc
d'instructions. Le mot­clé for est abordé dans l'heure 7, "Travailler avec des boucles".

Un bloc d'instructions permet de regrouper une ou plusieurs instructions en une seule instruction. De nombreux mots­
clés C ne peuvent contrôler qu'une seule instruction. Si vous souhaitez placer plusieurs instructions sous le contrôle
d'un mot­clé C, vous pouvez ajouter ces instructions dans un bloc d'instructions afin que le bloc soit considéré comme une
seule instruction par le mot­clé C.

Anatomie d'une fonction C


Les fonctions sont les blocs de construction des programmes C. Outre les fonctions standard de la bibliothèque C,
vous pouvez également utiliser d'autres fonctions créées par vous ou un autre programmeur dans votre programme C.
Dans l'heure 2, vous avez vu la fonction main() , ainsi que deux fonctions de la bibliothèque C, printf() et exit(). Maintenant,
regardons de plus près les fonctions.

Comme le montre la figure 3.1, une fonction se compose de six parties : le type de fonction, le nom de la fonction, les
arguments de la fonction, l'accolade ouvrante, le corps de la fonction et l'accolade fermante.

FIGURE Une fonction Une fonction Liste d'arguments


3.1 Anatomie d'une Taper Nom à la fonction

fonction en langage C.

entier entier_add (int x, int y)

{ Début de fonction

résultat entier ;
résultat = x + y ; Fonction Corps

retourner le résultat ;
Corps et fonction de fin de
} fonction

Les six parties d'une fonction sont expliquées dans les sections suivantes.

Déterminer le type d'une fonction


Le type de fonction est utilisé pour indiquer quel type de valeur une fonction va retourner après son exécution. Dans
l'Heure 2 par exemple, vous avez appris que le type de fonction par défaut de main() est int.

En C, int est utilisé comme mot clé pour le type de données entier. Au cours de la prochaine heure, vous en apprendrez
plus sur les types de données.
Machine Translated by Google

Apprendre la structure d'un programme en C 47

Outre le type int , un type de fonction peut être l'un des autres types, tels que le type caractère (mot­clé : char),
le type flottant (float), etc. Vous en apprendrez plus sur ces types plus tard dans ce livre.

Lorsque vous appelez une fonction C qui renvoie un type de données, la valeur qu'elle renvoie (valeur de retour)
peut alors être utilisée dans une expression. Vous pouvez l'affecter à une variable, telle que

int a = fonction();

ou l'utiliser dans une expression, comme celle­ci

a = fonction() + 7 ;

Attribution d'un nom valide à une fonction


Un nom de fonction est normalement donné de telle manière qu'il reflète ce que la fonction peut faire. Par
exemple, le nom de la fonction printf() signifie "imprimer des données formatées".
3
Puisqu'un nom de fonction est un identificateur, lors de la création de vos propres fonctions, vous devez
suivre les règles de création d'identificateurs valides lorsque vous nommez votre fonction.

De plus, vous ne pouvez pas utiliser les noms des fonctions C standard telles que printf() ou exit() pour
nommer vos propres fonctions. Ils sont déjà définis et il est illégal d'utiliser le même nom de fonction pour définir
plusieurs fonctions.

Passer des arguments aux fonctions C


Les fonctions sont utiles car vous pouvez les appeler encore et encore à partir de différents points de votre
programme. Cependant, il est probable que vous appeliez une certaine fonction pour une raison légèrement
différente à chaque fois.

Par exemple, dans le Listing 2.1 de l'Heure 2, une chaîne de caractères, « Bonjour, voisin ! C'est mon premier
programme C.\n", est passé à la fonction printf() , puis printf() imprime la chaîne à l'écran. Le but de printf() est
d'imprimer une chaîne à l'écran, mais chaque fois que vous l'appelez, vous transmettez la chaîne spécifique que
vous souhaitez qu'elle imprime cette fois­ci.

Les informations transmises aux fonctions sont appelées arguments. Comme vous l'avez vu, l'argument d'une
fonction est placé entre les parenthèses qui suivent immédiatement le nom de la fonction.

Le nombre d'arguments d'une fonction est déterminé par la déclaration de la fonction, qui à son tour est
déterminée par la tâche que la fonction va effectuer. Si une fonction a besoin de plus d'un argument, les
arguments passés à la fonction doivent être séparés par des virgules ; ces arguments sont considérés comme
une liste d'arguments.
Machine Translated by Google

48 Heure 3

Si aucune information ne doit être transmise à une fonction, il vous suffit de laisser vide le
champ argument entre parenthèses. Par exemple, la fonction main() du Listing 2.1 de l'Heure 2 n'a
pas d'argument, donc le champ entre parenthèses après le nom de la fonction est vide. Voir la copie
de la liste 3.1 ci­dessous :

LISTE 3.1. Un programme en C simple.

1 : /* 02L01.c : c'est mon premier programme C */


2 : #include <stdio.h> 3 : 4 : main() 5 : { 6 : 7 :

printf ("Bonjour, voisin ! C'est mon premier programme C.\n" ); renvoie 0 ;

8:}

Le début et la fin d'une fonction


Comme vous l'avez peut­être déjà compris, les accolades sont utilisées pour marquer le début et la
fin d'une fonction. L' accolade ouvrante ({) signifie le début d'un corps de fonction, tandis que l'
accolade fermante (}) marque la fin du corps de la fonction.

Comme mentionné précédemment, les accolades sont également utilisées pour marquer le début et la fin d'un bloc
d'instructions. Vous pouvez le considérer comme une extension naturelle pour utiliser des accolades avec des fonctions
car une fonction se compose d'une ou plusieurs instructions.

Le corps de la fonction
Le corps de la fonction dans une fonction est l'endroit qui contient les déclarations de variables et
d'autres instructions C. La tâche d'une fonction est accomplie en exécutant les instructions à
l'intérieur du corps de la fonction une par une.

Il est important de se rappeler que toute déclaration de variable doit être placée au début du
corps de la fonction. Il est illégal de placer des déclarations de variables ailleurs qu'au tout début
d'un bloc d'instructions.

Si le corps de votre fonction contient des déclarations de variables, elles doivent toutes être
placées en premier, avant toute autre instruction.

Le Listing 3.2 illustre une fonction qui additionne deux entiers spécifiés par ses arguments et renvoie
le résultat de l'addition.
Machine Translated by Google

Apprendre la structure d'un programme en C 49

LISTE 3.2 Une fonction qui additionne deux entiers

1 : /* 03L01.c : cette fonction additionne deux entiers et renvoie le résultat */ 2 : int integer_add( int x, int y )
3:{

4: résultat entier ;
résultat = x + y ;
retourner le résultat ;
5:6:7:}

Comme vous l'avez appris à l'heure 2, la ligne 1 du Listing 3.1 est un commentaire qui décrit ce que la
UNE ANALYSE
fonction peut faire.

À la ligne 2, vous voyez que le type de données int est préfixé avant le nom de la fonction. Ici, int est utilisé
comme type de fonction, ce qui signifie qu'un entier est renvoyé par la fonction.
Le nom de la fonction affiché à la ligne 2 est integer_add. La liste d'arguments contient deux arguments, int x et
3
int y, à la ligne 2, où le type de données int spécifie que les deux arguments sont tous deux des entiers.

La ligne 3 contient l'accolade ouvrante ({) qui marque le début de la fonction.

Le corps de la fonction se trouve aux lignes 4 à 6 du Listing 3.1. La ligne 4 donne la déclaration de variable du
résultat et est spécifiée par le type de données int sous la forme d'un entier. L'instruction de la ligne 5 additionne
les deux nombres entiers représentés par x et y et affecte le résultat du calcul à la variable de résultat . L'
instruction return de la ligne 6 renvoie ensuite le résultat du calcul représenté par result.

Enfin, mais non des moindres, l'accolade fermante (}) à la ligne 7 est utilisée pour fermer la fonction.

Lorsque vous créez une fonction dans votre programme C, n'attribuez pas trop de
travail à la fonction. Si une fonction a trop à faire, elle sera très difficile à écrire et à
déboguer. Si vous avez un projet de programmation complexe, divisez­le en plus petits
morceaux. Faites de votre mieux pour vous assurer que chaque fonction n'a qu'une
seule tâche à accomplir.

Faire des appels de fonction


Sur la base de ce que vous avez appris jusqu'à présent, vous pouvez écrire un programme C qui
appelle la fonction integer_add() pour calculer une addition, puis afficher le résultat à l'écran. Un exemple
d'un tel programme est présenté dans le Listing 3.3.
Machine Translated by Google

50 Heure 3

LISTE 3.3 Programme AC qui calcule une addition et imprime le résultat à l' écran

1 : /* 03L02.c : Calcule une addition et affiche le résultat */ 2 : #include <stdio.h> 3 : /*


Cette fonction additionne deux entiers et renvoie le résultat */ 4 : int integer_add( int x, int
y)5:{6:

résultat entier ;
résultat = x + y ;
retourner le résultat ;
7:8:
9:}
10 : 11 : int main()
12 : { 13 : 14 : 15 :
16 : 17 : 18
int :somme
} ;

somme = entier_add(5, 12);


printf("L'addition de 5 et 12 est %d.\n", somme); renvoie 0 ;

Le programme du Listing 3.2 est enregistré en tant que fichier source appelé 03L02.c. Une fois ce
programme compilé et lié, un fichier exécutable pour 03L02.c est créé. Sur ma machine, le fichier exe
cutable s'appelle 03L02.exe. Voici la sortie imprimée à l'écran après avoir lancé l'exécutable sur ma
machine :

L'addition de 5 et 12 donne 17.


SORTIR

La ligne 1 du Listing 3.2 est un commentaire sur le programme. Comme vous l'avez appris à
UNE ANALYSE
l'heure 2, la directive include de la ligne 2 inclut le fichier d'en­tête stdio.h en raison de la
fonction printf() dans le programme.

Les lignes 3 à 9 représentent la fonction integer_add() qui additionne deux entiers, comme indiqué
dans la section précédente.

La fonction main() , précédée du type de données int , commence à la ligne 11. Les lignes 12 et 18
contiennent respectivement l'accolade ouvrante et l'accolade fermante de la fonction main() . Une
variable entière, somme, est déclarée à la ligne 13.

L'instruction de la ligne 15 appelle la fonction integer_add() que vous avez examinée dans la section
précédente. Notez que deux constantes entières, 5 et 12, sont transmises à la fonction integer_add() et
que la variable sum reçoit le résultat renvoyé par la fonction integer_add() .
Machine Translated by Google

Apprendre la structure d'un programme en C 51

Vous avez vu pour la première fois la fonction printf() de la bibliothèque standard C à l'heure 2. Si vous
pensiez avoir trouvé quelque chose de nouveau ajouté à la fonction à la ligne 16, vous avez raison. Cette
fois, deux arguments sont passés à la fonction printf() . Il s'agit de la chaîne "L'addition de 5 et 12 est %d.\n"
et de la variable somme.

Notez qu'un nouveau symbole, %d, est ajouté au premier argument. Le deuxième argument est la somme de la
variable entière . Étant donné que la valeur de sum va être imprimée à l'écran, vous pourriez penser que %d a
quelque chose à voir avec la variable entière sum. Vous avez encore raison. %d indique à l'ordinateur le format
dans lequel la somme doit être affichée à l'écran.

Plus de détails sur %d sont couverts dans l'heure 4. La relation entre %d et la somme est discutée dans
l'heure 5, "Gestion des entrées et sorties standard".

Plus important encore, vous devez vous concentrer sur le programme du Listing 3.2 et faire attention à la
façon d'appeler soit une fonction générée par l'utilisateur, soit une fonction standard de la bibliothèque C à 3
partir de la fonction main() .

Résumé
Dans cette leçon, vous avez appris les concepts et opérateurs importants suivants :

• Une constante dans C est une valeur qui ne change jamais. Une variable, en revanche, peut présenter
différentes valeurs.

• Une combinaison de constantes, de variables et d'opérateurs est appelée une expression dans la
Langage C. Une expression est utilisée pour désigner différents calculs.

• Les opérateurs arithmétiques incluent +, ­, *, / et %. • Une

instruction se compose d'une expression complète suffixée par un point­virgule. • Le compilateur

C traite un bloc d'instructions comme une instruction unique, bien que le bloc d'instructions puisse
contenir plusieurs instructions.

• Le type de fonction spécifié dans la déclaration d'une fonction détermine le type de


la valeur renvoyée par la fonction.
• Vous devez suivre certaines règles pour créer un nom de fonction valide.

• Un argument contient des informations que vous souhaitez transmettre à une fonction. Une liste
d'arguments contient deux ou plusieurs arguments séparés par des virgules.

• L'accolade ouvrante ({) et l'accolade fermante (}) sont utilisées pour marquer le début et la fin d'un
Fonction C.

• Un corps de fonction contient des déclarations et des instructions de variables. •

Habituellement, une fonction ne doit accomplir qu'une seule tâche.

Dans la leçon suivante, vous en apprendrez plus sur les types de données en langage C.
Machine Translated by Google

52 Heure 3

Questions et réponses

Q Quelle est la différence entre une constante et une variable ?

A La principale différence est que la valeur d'une constante ne peut pas être modifiée, alors que la valeur d'une
variable le peut. Vous pouvez affecter différentes valeurs à une variable chaque fois que cela est nécessaire
dans votre programme C.

Q Pourquoi avez­vous besoin d'un bloc d'instructions ?

R De nombreux mots­clés C ne peuvent contrôler qu'une seule instruction. Un bloc d'instructions fournit une
manière de regrouper plusieurs instructions et de placer le bloc d'instructions sous le contrôle d'un mot­clé
C. Ensuite, le bloc d'instructions est traité comme une seule instruction.

Q Quels opérateurs arithmétiques ont une priorité plus élevée ?

A Parmi les cinq opérateurs arithmétiques, les opérateurs de multiplication, de division et de reste ont une
priorité plus élevée que les opérateurs d'addition et de soustraction.

Q Combien de parties une fonction comporte­t­elle normalement ?

R Une fonction comporte normalement six parties : le type de fonction, le nom de la fonction, les arguments,
l'accolade ouvrante, le corps de la fonction et l'accolade fermante.

Atelier
Pour aider à consolider votre compréhension de la leçon de cette heure, nous vous encourageons à répondre aux
questions du quiz et à terminer les exercices fournis dans l'atelier avant de passer à la leçon suivante. Les
réponses et les conseils aux questions et exercices sont donnés dans l'annexe D, « Réponses aux questions et
exercices du quiz ».

Questionnaire

1. En langage C, 74 est­ il une constante ? Que diriez ­vous de 571?

2. Est­ce que x = 570 + 1 est une expression ? Que diriez­ vous de x = 12 + y?

3. Les noms de fonction suivants sont­ils valides ?

2méthodes

m2_algorithme

*start_function

Taille de la chambre

.End_Exe

_turbo_add

4. Est­ce que 2 + 5 * 2 est égal à (2 + 5) * 2 ?

5. Est­ce que 7 % 2 produit le même résultat que 4 % 3 ?


Machine Translated by Google

Apprendre la structure d'un programme en C 53

Des exercices

1. Étant donné deux énoncés, x = 3 ; et y = 5 + x ; , comment pouvez­vous construire une déclaration


bloc avec les deux déclarations?

2. Quel est le problème avec la fonction suivante ? int


3integer_add( int x, int y, int z) {

int somme ;
somme = x + y + z ;
somme de retour ;
}

3. Quel est le problème avec la fonction suivante ? int


entier_add( int x, int y, int z) {

int somme ; 3
somme = x + y + z
retour somme ;
}

4. Écrivez une fonction C qui peut effectuer une multiplication de deux entiers et renvoyer la
résultat calculé.

5. Écrivez un programme C qui appelle la fonction C que vous venez d'écrire dans l'exercice 4 pour
calculer la multiplication de 3 fois 5, puis imprimez la valeur de retour de la fonction à l'écran.
Machine Translated by Google
Machine Translated by Google

HEURE 4
Comprendre les données
Types et mots­clés
Qu'est­ce qu'il y a dans un nom? Ce qu'on appelle une rose

Par n'importe quel autre nom sentirait bon.

—W. Shakespeare

Vous avez appris à créer un nom valide pour une fonction C à l'heure 3, "Apprentissage

de la structure d'un programme C". Maintenant, vous allez en savoir plus sur le nommage d'une
variable et les mots­clés C réservés par le compilateur C pendant cette heure.

Au cours de cette heure également, vous découvrirez en détail les quatre types de données du
langage C :

• type de données char

• type de données int •

type de données float •

type de données double


Machine Translated by Google

56 Heure 4

Mots­clés C
Le langage C réserve certains mots qui ont des significations particulières pour le langage. Ces mots
réservés sont parfois appelés mots­clés C. Vous ne devez pas utiliser les mots clés C pour vos
propres noms de variables, constantes ou fonctions dans vos programmes. Le tableau 4.1 répertorie
les 32 mots clés C réservés.

TABLEAU 4.1 Mots clés réservés en C Mot


clé Description
auto Spécificateur de classe de stockage

Déclaration
Pause

Déclaration
Cas

carboniser Spécificateur de type

constante Modificateur de classe de stockage

Déclaration
Continuez

défaut Étiquette

Déclaration
faire

double Spécificateur de type

Déclaration
autre

énumération Spécificateur de type

externe Spécificateur de classe de stockage

flotter Spécificateur de type

Déclaration
pour

Déclaration
aller à

si Déclaration

entier Spécificateur de type

longue Spécificateur de type

S'inscrire Spécificateur de classe de stockage

Déclaration
revenir

court Spécificateur de type

signé Spécificateur de type

taille de Opérateur

statique Spécificateur de classe de stockage

structure Spécificateur de type

Déclaration
changer
Machine Translated by Google

Comprendre les types de données et les mots­clés 57

Mot­clé La description

typedef
Déclaration

syndicat Spécificateur de type

non signé Spécificateur de type

vide Spécificateur de type

volatil Modificateur de classe de stockage

tandis que Déclaration

Ne vous inquiétez pas si vous ne vous souvenez pas de tous les mots­clés C la première fois. Dans le reste
du livre, vous vous familiariserez avec eux et commencerez à utiliser de nombreux mots clés à travers des
exemples et des exercices.

Notez que tous les mots­clés C sont écrits en lettres minuscules. Comme je l'ai mentionné, C est un langage
sensible à la casse. Par conséquent, int, comme indiqué dans la liste ici, est considéré comme un mot clé C,
mais INT ne l'est pas.

Le type de données char


4
Un objet du type de données char représente un seul caractère du jeu de caractères utilisé par votre
ordinateur. Par exemple, A est un caractère, et a aussi. Mais 7 est un nombre.

Cependant, un ordinateur ne peut stocker que du code numérique. Par conséquent, les caractères tels que
A, a, B, b, etc. ont tous un code numérique unique utilisé par les ordinateurs pour représenter les caractères.
Habituellement, un caractère prend 8 bits (c'est­à­dire 1 octet) pour stocker son code numérique.

Pour de nombreux ordinateurs, les codes ASCII sont les codes standard de facto pour représenter un
jeu de caractères. (ASCII, juste pour votre information, signifie American Standard Code for Information
Interchange.) Le jeu de caractères ASCII d'origine n'a que 128 caractères car il utilise les 7 bits inférieurs qui
peuvent représenter 27 (c'est­à­dire 128) caractères.

Sur les PC compatibles IBM, cependant, le jeu de caractères est étendu pour contenir un total de 256 (c'est­à­
dire 28 ) caractères.

Une chose que je voudrais mentionner ici est que la norme ANSI C spécifie uniquement
la valeur du caractère nul, qui est toujours zéro (c'est­à­dire un octet avec tous les bits
définis sur 0.) Les valeurs numériques des autres caractères sont déterminées par les
types d'ordinateurs, de systèmes d'exploitation et de compilateurs C. Nous vous
encourageons à explorer le jeu de caractères de l'ordinateur que vous utilisez. Cela peut
être fait avec le programme du Listing 4.1.
Machine Translated by Google

58 Heure 4

Dans le monde informatique, un bit est la plus petite unité de stockage de données et il ne peut
avoir qu'une des deux valeurs suivantes : 0 ou 1. Ces valeurs représentent deux états des
commutateurs électroniques utilisés dans la mémoire et le processeur de l'ordinateur. Un octet
est une unité plus grande qu'un bit. En fait, huit bits sont égaux à un octet.

Variables de caractère
Une variable qui peut représenter différents caractères est appelée une variable de caractère.

Vous pouvez définir le type de données d'une variable sur char en utilisant le format de déclaration suivant :

char nom de la variable ;

où variablename est le nom que vous fournissez dans lequel stocker les valeurs de ce type.

Si vous avez plusieurs variables à déclarer, vous pouvez soit utiliser le format suivant :

char nom_variable1 ; char


nom_variable2 ; char
nom_variable3 ;

ou celui­ci :

char nom_variable1, nom_variable2, nom_variable3 ;

Par exemple, l'instruction suivante déclare MyCharacter et le définit sur "A" :

char MonCaractère = 'A';

De même, les instructions suivantes déclarent x, y et z en tant que variables de type caractère, puis
leur attribuent des valeurs :

caractère x, y,
z ; x = 'A' ; y =
'f'; z = '7';

Notez que la dernière affectation, z = '7', définit z pour qu'il soit égal à la valeur numérique représentant
le caractère '7' dans le jeu de caractères ­ et non au nombre réel 7.

Vous en apprendrez plus sur la variable caractère et sur son utilisation dans vos programmes C plus loin
dans ce livre.

Constantes de caractères
Un caractère entouré de guillemets simples (') est appelé une constante de caractère. Par exemple,
'A', 'a', 'B' et 'b' sont toutes des constantes de caractères qui ont leurs valeurs numériques uniques
Machine Translated by Google

Comprendre les types de données et les mots­clés 59

dans un jeu de caractères donné. Par exemple, vous pouvez voir les valeurs numériques uniques du jeu de caractères
ASCII.

Il est important de se rappeler que les constantes de caractères sont toujours entourées de guillemets simples (')
alors qu'une chaîne de plusieurs caractères utilise les guillemets doubles (").
Si cela semble déroutant, rappelez­vous simplement que les guillemets simples vont avec des caractères simples. Vous
avez vu un exemple de guillemets doubles et de chaînes de caractères avec les appels de fonction printf() au cours de
l'heure précédente.

À partir du jeu de caractères ASCII, vous constaterez que les valeurs numériques (décimales) uniques de 'A', 'a', 'B' et 'b'
sont respectivement 65, 97, 66 et 98 . Par conséquent, étant donné x comme variable de caractère et étant donné le jeu
de caractères ASCII, par exemple, les deux instructions d'affectation suivantes sont équivalentes :

x = 'A' ;
x = 65 ;

Ainsi sont les deux déclarations suivantes :

x = 'un' ;
x = 97 ;

Plus tard dans cette heure, vous verrez un programme, présenté dans le Listing 4.2, qui reconvertit les valeurs
4
numériques en caractères correspondants.

Ne confondez pas x = 'a'; avec x = a;. La première instruction affecte la valeur numérique
du caractère a à la variable x, c'est­à­dire que x contiendra la valeur 97 (la valeur ASCII de la lettre
'a') après l'affectation. Énoncé x = a ; affecte cependant la valeur contenue dans la variable a à la
variable x.
Vous en apprendrez plus sur la différence plus loin dans ce livre.

Le caractère d'échappement (\)


En fait, vous avez vu le caractère d'échappement (\) pour la première fois dans l'heure 2, "Votre premier programme C",
lorsque vous avez appris à utiliser le caractère de nouvelle ligne (\n) pour diviser un message en deux morceaux.
Par conséquent, la barre oblique inverse (\) est appelée caractère d'échappement dans le jeu de caractères ASCII.
Le caractère d'échappement est utilisé dans le langage C pour indiquer à l'ordinateur qu'un caractère spécial suit.

Par exemple, lorsque l'ordinateur voit \ dans le caractère de retour à la ligne \n, il sait que le caractère suivant, n,
provoque une séquence de retour chariot et de saut de ligne.
Machine Translated by Google

60 Heure 4

Outre le caractère de nouvelle ligne, certains des autres caractères spéciaux du langage C sont les
suivants :

Personnage Description

\b Le caractère de retour arrière ; déplace le curseur d'un caractère vers la gauche.

\F Le caractère de saut de page ; va en haut d'une nouvelle page.

\r Le caractère de retour ; revient au début de la ligne courante.

\t Le caractère de tabulation ; passe au taquet de tabulation suivant.

Caractères d'impression
Vous savez déjà que la fonction printf() , définie dans le fichier d'en­tête C stdio.h, peut être utilisée
pour imprimer des messages à l'écran. (Réf. Listing 2.1 de l'heure 2.) Dans cette section, vous allez
apprendre à utiliser le spécificateur de format de caractère, %c, qui indique à la fonction printf() que
l'argument à afficher est un caractère. (Vous en apprendrez plus sur le spécificateur de format dans
l'heure 5, "Gestion des entrées et sorties standard". Ici, vous venez de vous mouiller les pieds.) La
chose importante à savoir pour l'instant est que chaque spécificateur de format dans la chaîne que vous
passez à printf() correspondra à l'une des variables que vous transmettez à la fonction. Voyons d'abord
le programme du Listing 4.1, qui imprime les caractères à l'écran.

TAPER LISTE 4.1 Impression de caractères à l'écran

1 : /* 04L01.c : Impression des caractères */ 2 : #include


<stdio.h> 3 : 4 : main() 5 : { 6 : 7 :

caractère c1 ;
caractère c2 ;

c1 = 'A' ; c2
= 'un' ;
8 : 9 : 10 : 11printf("Convertir
: la valeur de c1 en caractère : %c.\n", c1); printf("Convertir la
12 : valeur de c2 en caractère : %c.\n", c2); renvoie 0 ;
13 :
14 : }

Une fois le fichier exécutable de 04L01.c du Listing 4.1 créé, vous pouvez l'exécuter pour voir ce qui
sera imprimé à l'écran. Sur ma machine, le fichier exécutable est nommé 04L01.exe. Voici la sortie
imprimée sur l'écran de mon ordinateur après avoir lancé l'exécutable :
Machine Translated by Google

Comprendre les types de données et les mots­clés 61

Convertissez la valeur de c1 en caractère : A.


SORTIR Convertissez la valeur de c2 en caractère : a.

Comme vous le savez, la ligne 2 inclut le fichier d'en­tête, stdio.h, pour la fonction printf() .
UNE ANALYSE
Les lignes 5 à 15 constituent le corps de la fonction main() .

Les lignes 6 et 7 déclarent deux variables de caractère, c1 et c2, tandis que les lignes 9 et 10 affectent c1 et
c2 avec les constantes de caractère 'A' et 'a', respectivement.

Notez que le spécificateur de format %c est utilisé dans la fonction printf() aux lignes 11 et 12, qui indique
à l'ordinateur que le contenu contenu par c1 et c2 doit être imprimé sous forme de caractères. Lorsque les
deux instructions des lignes 11 et 12 sont exécutées, deux caractères sont formatés et affichés à l'écran, en
fonction des valeurs numériques contenues respectivement par c1 et c2 .

Maintenant, regardez le programme montré dans le Listing 4.2. Cette fois, %c est utilisé pour reconvertir
les valeurs numériques en caractères correspondants.

TAPER LISTE 4.2 Conversion de valeurs numériques en caractères

1 : /* 04L02.c : reconversion des valeurs numériques en caractères */ 2 : #include <stdio.h>


3 : 4 : main() 5 : { 6 : 7 : 8 : 9 : 10 : 11 : 12 : 13 :14: } 4

caractère c1 ;
caractère c2 ;

c1 =65 ;
c2 = 97 ;
printf("Le caractère qui a la valeur numérique de 65 est : %c.\n", c1); printf("Le caractère qui a la valeur numérique
de 97 est : %c.\n", c2); renvoie 0 ;

Voici la sortie imprimée sur l'écran de mon ordinateur après avoir exécuté le fichier exe cutable, 04L02.exe.
(Vous pouvez recevoir une sortie différente de votre ordinateur ; cela dépend de l'implémentation. C'est­à­
dire que cela dépend du type de votre ordinateur, du système d'exploitation et de l'ordinateur C que vous
utilisez) :

Le caractère qui a la valeur numérique de 65 est : A.


SORTIR Le caractère qui a la valeur numérique de 97 est : un

Le programme de l'extrait 4.2 est similaire à celui de l'extrait 4.1, à l'exception des deux instructions
UNE ANALYSE
des lignes 9 et 10. Notez qu'aux lignes 9 et 10 de l'extrait 4.2, les variables de caractère c1 et c2
reçoivent respectivement 65 et 97 .
Machine Translated by Google

62 Heure 4

Comme vous le savez, 65 est la valeur numérique (décimal) du caractère A dans le jeu de caractères ASCII ; 97
est la valeur numérique de a. Aux lignes 11 et 12, le spécificateur de format %c convertit les valeurs numériques,
65 et 97, en A et a, respectivement. Les caractères A et a sont alors imprimés à l'écran.

Le type de données int


Vous avez vu le type de données entier dans l'heure 3. Le mot­clé int est utilisé pour spécifier le type d'une
variable sous forme d'entier. Les nombres entiers sont également appelés nombres entiers, qui n'ont ni partie
fractionnaire ni virgule décimale. Par conséquent, le résultat d'une division entière est tronqué, simplement parce
que toute partie fractionnaire est ignorée.

Selon le système d'exploitation et le compilateur C que vous utilisez, la longueur d'un entier varie. Sur la
plupart des stations de travail UNIX, par exemple, un entier a une longueur de 32 bits, ce qui signifie que la
plage d'un entier va de 2147483647 (c'est­à­dire 231–1) à ­2147483648. La plage d'un entier 16 bits va de
32767 (c'est­à­dire 215–1) à ­32768.
Encore une fois, cela peut varier d'un système à l'autre, vous pouvez donc vérifier les documents de référence
de votre compilateur pour en être sûr.

Certains compilateurs C, tels que Visual C++ 1.5, fournissent uniquement l'entier 16 bits, tandis que d'autres
compilateurs C 32 bits, tels que Visual C++ 5.0, prennent en charge l'entier 32 bits.

Déclaration de variables entières


Vous avez également vu la déclaration d'un entier dans l'heure 3. Voici le format de déclaration de base :

int nom de la variable ;

Semblable à la déclaration de caractères, si vous avez plus d'une variable à déclarer, vous pouvez soit utiliser
le format comme ceci :

int nom_variable1 ; int


nom_variable2 ; int
nom_variable3 ;

ou comme ceci :

int nom_variable1, nom_variable2, nom_variable3 ;

Ici variablename1, variablename2 et variablename3 indiquent les endroits où vous mettez les noms des variables
int .

Par exemple, l'instruction suivante déclare MyInteger en tant que variable entière et lui attribue une valeur :

int MonEntier = 2314;


Machine Translated by Google

Comprendre les types de données et les mots­clés 63

De même, l'instruction suivante déclare A, a, B et b comme des variables entières :

entier A, a, B, b ;
A = 37 ;
un = –37 ;
B = ­2418 ; b =
12 ;

Vous en apprendrez plus sur le type de données entier plus tard dans le livre.

Affichage des valeurs numériques des caractères


Comme le spécificateur de format de caractère (%c) utilisé pour formater un seul caractère, %d, appelé
spécificateur de format d'entier, est utilisé pour formater un entier. Vous vous souviendrez peut­être qu'à la
ligne 16 du Listing 3.2, %d est utilisé dans la fonction printf() pour formater le second argument de la fonction
en entier.

Dans cette section, vous allez étudier un programme, présenté dans le Listing 4.3, qui peut imprimer les
valeurs numériques des caractères en utilisant le spécificateur de format entier %d avec printf().

TAPER LISTE 4.3 Affichage des valeurs numériques des caractères

1 : /* 04L03.c : affiche les valeurs numériques des caractères */ 2 : #include <stdio.h> 4


3 : 4 : main() 5 : { 6 : 7 :

caractère c1 ;
caractère c2 ;

c1 = 'A' ; c2
= 'un' ;
8 : 9 : 10 : 11printf("La
: valeur numérique de A est : %d.\n", c1); printf("La valeur
12 : numérique de a est : %d.\n", c2); renvoie 0 ;
13 :
14 : }

J'obtiens la sortie suivante sur l'écran de mon ordinateur après avoir exécuté le fichier exécutable, 04L03.exe.
(Vous pouvez obtenir une sortie différente si votre machine n'utilise pas le jeu de caractères ASCII.)

La valeur numérique de A est : 65.


SORTIR
La valeur numérique de a est : 97.

UNE ANALYSE
Vous constaterez peut­être que le programme du Listing 4.3 est assez similaire à celui du Listing 4.1.
En fait, j'ai simplement copié le code source du Listing 4.1 vers le Listing 4.3 et apporté des
modifications aux lignes 11 et 12. Le changement majeur que j'ai apporté a été de remplacer le spécificateur
de format de caractère (%c) par le spécificateur de format entier (% ré).
Machine Translated by Google

64 Heure 4

Les deux spécificateurs de format font fondamentalement la même chose ­ insérez des données dans la chaîne
que vous transmettez à printf() ­ mais la différence réside dans la façon dont printf() affiche ces données. Le
spécificateur %c imprime toujours un caractère ; le spécificateur %d imprime toujours un nombre. Même
lorsqu'ils font référence aux mêmes données, elles seront imprimées comme vous l'indiquez dans le
spécificateur de format, quel que soit le type de données réel.

Les deux instructions des lignes 11 et 12 formatent les deux variables de caractères (c1 et c2) en utilisant le
spécificateur de format entier %d, puis impriment deux messages indiquant les valeurs numériques 65 et 97
qui représentent, respectivement, les caractères A et a dans le jeu de caractères ASCII.

Le type de données flottant


Le nombre à virgule flottante est un autre type de données du langage C. Contrairement à un nombre entier,
un nombre à virgule flottante contient un point décimal. Par exemple, 7.01 est un nombre à virgule flottante ; il
en va de même pour 5,71 et –3,14. Un nombre à virgule flottante est aussi appelé un nombre réel.

Un nombre à virgule flottante est spécifié par le mot­clé float dans le langage C. Les constantes de pointeur
flottant peuvent être suffixées avec f ou F pour spécifier float. Un nombre à virgule flottante sans suffixe est
double par défaut. Le type de données double est présenté plus loin dans cette leçon.

Comme un nombre entier, un nombre à virgule flottante a une plage limitée. La norme ANSI exige que la
plage soit au moins plus ou moins 1,0 × 1037. Dans la plupart des cas, un nombre à virgule flottante est
représenté en prenant 32 bits. Par conséquent, un nombre à virgule flottante en C a une précision d'au moins
six chiffres. Autrement dit, pour un nombre à virgule flottante, il y a au moins six chiffres (ou décimales) à droite
de la virgule décimale.

Contrairement à une division entière dont le résultat est tronqué et la fraction est supprimée, une
division à virgule flottante produit un autre nombre à virgule flottante. Une division à virgule flottante est
effectuée si le diviseur et le dividende, ou l'un d'eux, sont des nombres à virgule flottante.

Par exemple, 571.2 / 10.0 produit un autre nombre à virgule flottante, 57.12. Il en va de même pour 571.2/10
et 5712/10.0.

Déclaration de variables à virgule flottante


Voici le format de déclaration d'une variable à virgule flottante :

float nom de la variable ;


Machine Translated by Google

Comprendre les types de données et les mots­clés 65

Semblable à la déclaration de caractères ou d'entiers, si vous avez plus d'une variable à déclarer,
vous pouvez soit utiliser le format comme ceci :

float nom_variable1 ; float


nom_variable2 ; float
nom_variable3 ;

ou comme celui­ci :

float nom_variable1, nom_variable2, nom_variable3 ;

Par exemple, l'instruction suivante déclare myFloat en tant que variable flottante et lui attribue une valeur :

float myFloat = 3.14;

De même, l'instruction suivante déclare a, b et c comme variables flottantes :

flottant a, b, c ; a
= 10,38 ; b = –
32,7 ; c = 12,0f ;

Le spécificateur de format à virgule flottante (%f)


4
Vous pouvez également utiliser le spécificateur de format à virgule flottante (%f) pour formater votre
sortie. Le Listing 4.4 montre un exemple d'utilisation du spécificateur de format %f avec la fonction printf() .

TAPER LISTE 4.4 Impression des résultats de la division entière et virgule flottante

1 : /* 04L04.c : Divisions entières ou à virgule flottante */ 2 : #include


<stdio.h> 3 : 4 : main() 5 : { 6 :

int_num1, int_num2, int_num3 ; /* Déclare des variables entières */ float


flt_num1, flt_num2, flt_num3 ; /* Déclare les variables à virgule flottante */
7:

8:
9: int_num1 = 32 / 10 ; /* Le diviseur et le dividende sont tous deux
entiers */ flt_num1 = 32 /
10: 10 ; int_num2 = 32,0 /
11: 10 ; /* Le diviseur est un entier */ flt_num2 = 32.0 / 10; int_num3 = 32 /
12 : 10.0 ; /* Le dividende est un entier */ flt_num3 = 32 / 10.0;
13:
14:

15h16: printf("La division entière de 32/10 est : %d\n", int_num1);

continue
Machine Translated by Google

66 Heure 4

LISTE 4.4 suite

17: printf("La division en virgule flottante de 32/10 est : %f\n", flt_num1); printf("La
division entière de 32.0/10 est : %d\n", int_num2); printf("La division en virgule
flottante de 32.0/10 est : %f\n", flt_num2); printf("La division entière de 32/10.0 est :
%d\n", int_num3); printf("La division en virgule flottante de 32/10.0 est : %f\n",
18h19h20h21h
flt_num3); renvoie 0 ;
22:
23 : }

La sortie suivante provient de l'écran de mon ordinateur après l'exécution du fichier


exécutable, 04L04.exe, sur ma machine :

J'ai reçu plusieurs messages d'avertissement concernant les conversions de type


pendant que je compilais le programme dans le Listing 4.4, mais je les ai tous ignorés
car je voulais créer un fichier exécutable afin de vous montrer les différences entre le
type de données int et le type de données float .

L'entier divis. de 32/10 est : 3 La division


SORTIR en virgule flottante. de 32/10 est : 3,000000 L'entier divis. de
32,0/10 est : 3 La division en virgule flottante. de 32,0/10 est :
3,200000 L'entier divis. de 32/10.0 est : 3 La division en virgule
flottante. de 32/10.0 est : 3.200000

UNE ANALYSE
Dans la fonction main() , les deux instructions des lignes 6 et 7 déclarent trois variables
entières, int_num1 , int_num2 et int_num3, et trois variables à virgule flottante.
ables, flt_num1 , flt_num2 et flt_num3.

Les lignes 9 et 10 attribuent le résultat de 32/10 à int_num1 et flt_num1, respectivement ;


32.0/10 à int_num2 et flt_num2 aux lignes 11 et 12, et 32/10.0 à int_num3 et flt_num3 aux lignes
13 et 14.

Ensuite, les lignes 16 à 21 impriment les valeurs contenues par les trois variables int et les trois
variables à virgule flottante. Notez que %d est utilisé pour les variables entières et que le
spécificateur à virgule flottante (%f) est utilisé pour formater les variables à virgule flottante dans la
fonction printf() .

Étant donné que la troncature se produit dans la division entière de 32/10, flt_num1 contient
3,000000, et non 3,200000, ce que vous pouvez voir sur la deuxième ligne de la sortie. Cependant,
flt_num2 et flt_num3 se voient attribuer 3,200000 car 32,0/10 et 32/10,0 sont considérés comme la
division à virgule flottante.
Machine Translated by Google

Comprendre les types de données et les mots­clés 67

Mais int_num2 et int_num3, en tant que variables entières, rejettent respectivement les parties fractionnaires
des divisions à virgule flottante de 32.0/10 et 32/10.0. Par conséquent, vous ne voyez que l'entier 3 dans les
troisième et cinquième lignes de la sortie.

Le double type de données


Dans le langage C, un nombre à virgule flottante peut également être représenté par un autre type de données,
appelé type de données double . En d'autres termes, vous pouvez spécifier une variable par le mot­clé double
et affecter à la variable un nombre à virgule flottante.

La différence entre un type de données double et un type de données flottant est que le premier utilise deux
fois plus de bits que le second. Par conséquent, un nombre à virgule flottante double a une précision d'au moins
10 chiffres, bien que la norme ANSI ne le spécifie pas pour le type de données double .

Dans l'heure 8, "Utilisation des opérateurs conditionnels", vous apprendrez à utiliser l' opérateur
sizeof pour obtenir la longueur en octets d'un type de données, tel que char, int, float ou double,
spécifié sur votre système informatique.

4
Utiliser la notation scientifique
Le langage C utilise la notation scientifique pour vous aider à écrire de longs nombres à virgule flottante.

En notation scientifique, un nombre peut être représenté par la combinaison de la mantisse et de l' exposant.
Le format de la notation est que la mantisse est suivie de l'exposant, qui est préfixé par e ou E. Voici deux
exemples :

exponentielle la mantisse

et

exposant de la mantisse

Veuillez noter que la mantisse et l'exposant ci­dessus sont tous deux des espaces réservés et que vous
devez les remplacer par des valeurs numériques.

Par exemple, 5000 peut être représenté par 5e3 en notation scientifique. De même, ­300 peut être représenté
par ­3e2 et 0,0025 par 2,5e­3.

De même, le spécificateur de format, %e ou %E, est utilisé pour formater un nombre à virgule flottante en
notation scientifique. L'utilisation de %e ou %E dans la fonction printf() est la même
comme %f.
Machine Translated by Google

68 Heure 4

Nommer une variable


Il y a quelques points à garder à l'esprit lors de la création de vos propres noms de variables.
N'oubliez pas que puisque les noms de variables sont des identificateurs, vous devez suivre les règles pour les
identificateurs qui ont été décrites dans l'heure précédente.

Tout comme les noms de fonction doivent idéalement refléter la tâche que la fonction exécute, les noms de variable
doivent décrire la valeur stockée dans la variable et à quoi elle sert dans votre programme ou votre fonction. Jusqu'à
présent, la plupart des exemples de code ont utilisé des noms de variables à une seule lettre tels que i, mais à mesure
que vous écrivez des programmes plus volumineux et des fonctions plus compliquées, il devient de plus en plus
important de donner à vos variables des noms significatifs.

N'utilisez jamais les mots clés C réservés dans le langage C, ou les noms des fonctions de
la bibliothèque C standard, comme noms de variables dans votre programme C.

Résumé
Dans cette leçon, vous avez découvert les mots­clés C et les types de données importants suivants :

• Les mots clés C réservés dans le langage C • Le type de

données char et le spécificateur de format %c • Le type de

données int et le spécificateur de format %d • Le type de données

float et le spécificateur de format %f • Les nombres à virgule

flottante peuvent être suffixés avec f ou F pour spécifier float. Un nombre à virgule flottante sans suffixe est
double par défaut. • Les plages possibles des types de données char, int et float • Le type de données

double • La notation scientifique et les spécificateurs de format %e et %E • Les règles que vous devez suivre

pour créer un nom de variable valide

Dans la prochaine leçon, vous en apprendrez plus sur la fonction printf() et d'autres fonctions pour gérer les entrées
et les sorties.

Questions et réponses

Q Pourquoi les caractères ont­ils leurs valeurs numériques uniques ?

A Les caractères sont stockés dans les ordinateurs sous forme de bits. Les combinaisons de bits
peut être utilisé pour représenter différentes valeurs numériques. Un personnage doit avoir un caractère unique
Machine Translated by Google

Comprendre les types de données et les mots­clés 69

valeur numérique afin de se distinguer. De nombreux systèmes informatiques prennent en charge le jeu
de caractères ASCII, qui contient un ensemble de valeurs numériques uniques pouvant contenir jusqu'à
256 caractères.

Veuillez noter que votre ordinateur peut utiliser un jeu de caractères différent du jeu de caractères ASCII.
Ensuite, tous les caractères utilisés par le langage C, à l'exception du caractère nul, peuvent avoir des
valeurs numériques différentes des valeurs représentées par le caractère ASCII
ensemble d'acteurs.

Q Comment déclarer deux variables caractères ?

A Il y a deux façons de faire la déclaration. Le premier est

...char nom­variable1, nom­variable2 ;


Le deuxième est

char nom_variable1 ; char


nom­variable2 ;

Q Que sont %c, %d et %f ?


A Ce sont des spécificateurs de format. %c est utilisé pour obtenir le format de caractère ; %d est pour le format
entier ; %f correspond au format à virgule flottante. %c, %d et %f sont souvent utilisés avec des fonctions
C telles que printf().
4
Q Quelles sont les principales différences entre le type de données int (entier) et le type de données float
(virgule flottante) ?

A Tout d'abord, un entier ne contient aucune partie fractionnaire, mais un nombre à virgule flottante
Est­ce que. Un nombre à virgule flottante doit avoir une virgule décimale. En C, le type de données float
prend plus de bits que le type de données int . En d'autres termes, le type de données float a une plus grande
plage de valeurs numériques que le type de données int .

De plus, la division entière tronque la partie fractionnaire. Par exemple, la division entière de 16/10 produit
un résultat de 1, et non de 1,6.

Atelier
Pour aider à consolider votre compréhension de la leçon de cette heure, nous vous encourageons à répondre aux
questions du quiz et à terminer les exercices fournis dans l'atelier avant de passer à la leçon suivante. Les réponses
et les conseils aux questions et exercices sont donnés dans l'annexe C, « Réponses aux questions et exercices du
quiz ».

Questionnaire

1. Les divisions entières de 134/100 et 17/10 sont­elles égales ?

2. Le résultat de 3000 + 1,0 est­il un nombre à virgule flottante ? Que diriez ­vous de 3000/1.0 ?
Machine Translated by Google

70 Heure 4

3. Comment peux­tu représenter les nombres suivants en notation scientifique ?


• 3500

• 0,0035

• –0,0035

4. Les noms de variables suivants sont­ils valides ?

• 7ème_calcul

• Méthode_de Tom

• _index

• Libellé_1

Des exercices
1. Écrivez un programme qui imprime les valeurs numériques des caractères Z et z.

2. Étant donné deux valeurs numériques, 72 et 104, écrivez un programme pour imprimer le corre
répondant à deux caractères.

3. Pour une variable entière 16 bits, pouvez­vous attribuer à la variable une valeur entière de
72368 ?

4. Étant donné la déclaration double dbl_num = 123.456;, écrivez un programme qui imprime la valeur
de dbl_num dans les deux formats de notation à virgule flottante et scientifique.

5. Écrivez un programme capable d'imprimer la valeur numérique du caractère de saut de ligne (\n).
(Astuce : affectez '\n' à une variable de type caractère.)
Machine Translated by Google

HEURE 5

Gestion des entrées et


sorties standard
I/O, I/O, c'est parti pour le boulot on y va...

—Les Sept Nains (en quelque sorte)

Dans la dernière leçon, vous avez appris à afficher des caractères, des entiers et des nombres à
virgule flottante à l'écran en appelant la fonction printf() . Dans cette leçon, vous allez en savoir
plus sur printf(), ainsi que sur les fonctions suivantes, qui sont nécessaires pour recevoir l'entrée
de l'utilisateur ou pour afficher la sortie à l'écran :

• La fonction getc() • La

fonction putc() • La fonction

getchar() • La fonction putchar()

Avant de nous lancer dans ces nouvelles fonctions, commençons par nous faire une idée des
entrées et sorties (E/S) standard en C.
Machine Translated by Google

72 Heure 5

Présentation des E/S standard


Un fichier contient des caractères et des nombres associés. Parce que tous les caractères et les chiffres sont

représenté en bits sur les ordinateurs, et un octet est une série de bits, le langage C traite un fichier
comme une série d'octets. Une série d'octets est également appelée flux. En fait, le langage C traite tous
les flux de fichiers de la même manière, bien que certains des flux de fichiers puissent provenir d'un lecteur
de disque ou de bande, d'un terminal ou même d'une imprimante.

De plus, en C, trois flux de fichiers sont pré­ouverts pour vous, c'est­à­dire qu'ils sont toujours disponibles
pour être utilisés dans vos programmes :

• stdin—L'entrée standard pour la lecture. • stdout

—La sortie standard pour l'écriture. • stderr : l'erreur

standard pour l'écriture des messages d'erreur.

Habituellement, le flux de fichiers d'entrée standard (stdin) est lié à votre clavier, tandis que les flux de
fichiers de sortie standard (stdout) et d'erreur standard (stderr) pointent vers l'écran de votre terminal. En
outre, de nombreux systèmes d'exploitation permettent à l'utilisateur de rediriger ces flux de fichiers.

En fait, vous avez déjà utilisé stdout. Lorsque vous avez appelé la fonction printf() dans la dernière leçon,
vous envoyiez en fait la sortie au flux de fichiers par défaut, stdout, qui pointe vers votre écran.

Vous en apprendrez plus sur stdin et stdout dans les sections suivantes.

Le langage C fournit de nombreuses fonctions pour manipuler la lecture et l'écriture


de fichiers (E/S). Le fichier d'en­tête stdio.h contient les déclarations de ces fonctions.
Par conséquent, incluez toujours le fichier d' en­tête stdio.h dans votre programme C
avant de faire quoi que ce soit avec les E/S de fichiers.

Obtenir l'entrée de l'utilisateur


De nos jours, taper sur le clavier est toujours le moyen standard de facto de saisir des informations dans les
ordinateurs. Le langage C a plusieurs fonctions pour indiquer à l'ordinateur de lire les entrées de l'utilisateur
(généralement via le clavier). Dans cette leçon, les fonctions getc() et getchar() sont introduites.

Utilisation de la fonction getc()


La fonction getc() lit le caractère suivant d'un flux de fichier et renvoie le caractère sous la forme d'un entier.
Machine Translated by Google

Gestion des entrées et sorties standard 73

Entrée de syntaxe
SYNTAXE La syntaxe de la fonction getc() est #include
<stdio.h> int getc(FILE *stream);

Ici, FILE *stream déclare un flux de fichier (c'est­à­dire une variable). La fonction renvoie
la valeur numérique du caractère lu. En cas de fin de fichier ou d'erreur, la fonction renvoie
EOF.

Pour l'instant, ne vous souciez pas de la structure FILE . Plus de détails à ce sujet sont présentés dans
les heures 21, « Lecture et écriture avec des fichiers », et 22, « Utilisation des fonctions de fichiers
spéciales ». Dans cette section, le flux d'entrée standard stdin est utilisé comme flux de fichier spécifié par
FICHIER *flux.

Défini dans le fichier d'en­tête stdio.h, EOF est une constante. EOF signifie fin de fichier.
Habituellement, la valeur de EOF est ­1. Mais continuez à utiliser EOF, au lieu de ­1, pour indiquer
la fin de fichier dans vos programmes. De cette façon, si vous utilisez ultérieurement une compilation
ou un système d'exploitation qui utilise une valeur différente, votre programme fonctionnera toujours.

Le Listing 5.1 montre un exemple qui lit un caractère saisi par l'utilisateur à partir du
clavier, puis affiche le caractère à l'écran.

TAPER LISTE 5.1 Lecture d'un caractère saisi par l'utilisateur

1 : /* 05L01.c : lecture de l'entrée en appelant getc() */ 2 : #include


<stdio.h> 3 : 4 : main() 5 : { 6 : 7 :
5

int ch ;

printf("Veuillez saisir un caractère :\n"); ch =


getc( stdin ); printf("Le caractère que vous venez
d'entrer est : %c\n", ch); renvoie 0 ;
8 : 9 : 10 : 11 :

12 : }

Voici la sortie affichée sur l'écran de mon ordinateur après avoir exécuté le fichier
exécutable, 05L01.exe, saisi le caractère H et appuyé sur la touche Entrée :
Veuillez saisir un caractère :
SORTIR
H
Le caractère que vous venez d'entrer est : H
Machine Translated by Google

74 Heure 5

UNE ANALYSE Vous voyez à la ligne 2 du Listing 5.1 que le fichier d'en­tête stdio.h est inclus pour les
fonctions getc() et printf() utilisées dans le programme. Les lignes 4 à 12 donnent le
nom et corps de la fonction main() .

A la ligne 6, une variable entière, ch, est déclarée ; la valeur de retour de la fonction getc() lui
est affectée plus tard à la ligne 9. La ligne 8 imprime un message demandant à l'utilisateur d'entrer
un caractère au clavier. Comme je l'ai mentionné plus tôt dans cette leçon, l' appel de la fonction
printf() à la ligne 8 utilise la sortie standard par défaut stdout pour afficher les messages à l'écran.

À la ligne 9, le flux d'entrée standard stdin est passé à la fonction getc() , qui indique que le flux
de fichier provient du clavier. Une fois que l'utilisateur a saisi un caractère, la fonction getc()
renvoie la valeur numérique (c'est­à­dire un entier) du caractère. Vous voyez qu'à la ligne 9, la
valeur numérique est affectée à la variable entière ch.

Ensuite, à la ligne 10, le caractère saisi par l'utilisateur est affiché à l'écran à l'aide de printf(). Notez
que le spécificateur de format de caractère (%c) est utilisé dans l' appel de la fonction printf() à la
ligne 10. (L'exercice 1 de cette leçon vous demande d'utiliser %d dans un programme pour imprimer
la valeur numérique d'un caractère entré par le utilisateur.)

Utilisation de la fonction getchar()


Le langage C fournit une autre fonction, getchar(), qui exécute une fonction similaire à getc(). Plus
précisément, la fonction getchar() est équivalente à getc(stdin).

Entrée de syntaxe
La syntaxe de la fonction getchar() est #include
<stdio.h> int getchar(void);
SYNTAXE

Ici, void indique qu'aucun argument n'est nécessaire pour appeler la fonction. La fonction
renvoie la valeur numérique du caractère lu. Si une fin de fichier ou une erreur se produit, la fonction
renvoie EOF.

Le programme du Listing 5.2 montre comment utiliser la fonction getchar() pour lire l'entrée de
l'utilisateur.

TAPER
LISTE 5.2 Lire un caractère en appelant getchar()

1 : /* 05L02.c : lecture de l'entrée en appelant getchar() */ 2 : #include


<stdio.h> 3 : 4 : main() 5 : { 6 : 7 :

int ch1, ch2 ;


Machine Translated by Google

Gestion des entrées et sorties standard 75

8: printf("Veuillez saisir deux caractères ensemble :\n"); ch1 = getc( stdin ); ch2 =
9: getchar( ); printf("Le premier caractère que vous venez d'entrer est : %c\n", ch1);
10 : printf("Le deuxième caractère que vous venez d'entrer est : %c\n", ch2); renvoie 0 ;
11 :
12 :
13 :
14 : }

Après avoir exécuté le fichier exécutable, 05L02.exe, et saisi deux caractères (H et i) ensemble
sans espaces, j'appuie sur la touche Entrée et le résultat suivant s'affiche sur l'écran de mon ordinateur :

Veuillez saisir deux caractères ensemble :


SORTIR Salut

Le premier caractère que vous venez d'entrer est : H


Le deuxième caractère que vous venez de saisir est : i

Le programme du Listing 5.2 est assez similaire à celui du Listing 5.1, sauf que celui­ci se
UNE ANALYSE
lit en deux caractères.

L'instruction de la ligne 6 déclare deux entiers, ch1 et ch2. La ligne 8 affiche un message
demandant à l'utilisateur d'entrer deux caractères ensemble.

Ensuite, les fonctions getc() et getchar() sont appelées aux lignes 9 et 10, respectivement, pour lire
deux caractères saisis par l'utilisateur. Notez qu'à la ligne 10, rien n'est passé à la fonction
getchar() . En effet, comme mentionné précédemment, getchar() utilise le flux de fichier d'entrée
par défaut, stdin. Vous pouvez remplacer la fonction getchar() à la ligne 10 par getc(stdin) car
getc(stdin) est équivalent à getchar().

Les lignes 11 et 12 envoient deux caractères (conservés respectivement par ch1 et ch2 ) à l'écran.
5

Impression de la sortie à l'écran


Outre getc() et getchar() pour la lecture, le langage C fournit également deux fonctions, putc() et
putchar(), pour l'écriture. Les deux sections suivantes présentent ces fonctions.

Utilisation de la fonction putc()


La fonction putc() écrit un caractère dans le flux de fichiers spécifié, qui, dans votre cas, est la sortie
standard pointant vers votre écran.
Machine Translated by Google

76 Heure 5

Entrée de syntaxe
SYNTAXE La syntaxe de la fonction putc() est #include <stdio.h> int
putc(int c, FILE *stream);

Ici, le premier argument, int c, indique que la sortie est un caractère enregistré dans une variable
entière c ; le deuxième argument, FILE *stream, spécifie un flux de fichier. En cas de succès, putc()
renvoie le caractère écrit ; sinon, il renvoie EOF.

Dans cette leçon, la sortie standard stdout est spécifiée comme flux de fichier de sortie dans putc().

La fonction putc() est utilisée dans le Listing 5.3 pour placer le caractère A à l'écran.

TAPER LISTE 5.3 Mettre un personnage à l'écran

1 : /* 05L03.c : afficher un caractère avec putc() */ 2 : #include <stdio.h> 3 : 4 : main()


5:{6:7:

int ch ;

ch = 65 ; /* la valeur numérique de A */
printf("Le caractère qui a la valeur numérique de 65 est :\n"); putc(ch, stdout); renvoie 0 ;

8 : 9 : 10 : 11 :

12 : }

La sortie suivante est ce que j'obtiens de ma machine:


Le caractère qui a une valeur numérique de 65 est :
SORTIR
UN

Comme mentionné, le fichier d'en­tête stdio.h, contenant la déclaration de putc(), est


UNE ANALYSE
inclus à la ligne 2.

La variable entière, ch, déclarée à la ligne 6, reçoit la valeur numérique 65 à la ligne 8.


La valeur numérique du caractère A est 65 dans le jeu de caractères ASCII.

La ligne 9 affiche un message pour rappeler à l'utilisateur la valeur numérique du caractère qui va
être mis à l'écran. Ensuite, la fonction putc() de la ligne 10 place le caractère A à l'écran. Notez que
le premier argument de la fonction putc() est la variable entière (ch) qui contient 65, et le second
argument est le flux de fichier de sortie standard, stdout.
Machine Translated by Google

Gestion des entrées et sorties standard 77

Une autre fonction d'écriture : putchar()


Comme putc(), putchar() peut également être utilisé pour mettre un caractère à l'écran. La seule
différence entre les deux fonctions est que putchar() n'a besoin que d'un seul argument pour
contenir le caractère. Vous n'avez pas besoin de spécifier le flux de fichier car la sortie standard
(stdout) est définie comme flux de fichier pour putchar().

Entrée de syntaxe La

SYNTAXE
syntaxe de la fonction putchar() est #include <stdio.h> int
putchar(int c);

Ici int c est l'argument qui contient la valeur numérique d'un caractère. La fonction renvoie EOF si une
erreur se produit ; sinon, il renvoie le caractère qui a été écrit.

Un exemple d'utilisation de putchar() est démontré dans le Listing 5.4.

TAPER
LISTE 5.4 Sortie de caractères avec putchar().

1 : /* 05L04.c : afficher des caractères avec putchar() */ 2 : #include <stdio.h> 3 : 4 : main()


5:{6:

putchar(65);
7: putchar(10);
8: putchar(66);
9: putchar(10);
10 :
5
putchar(67); putchar(10);
11 : renvoie 0 ;
12 :
13 : }

Après avoir exécuté le fichier exécutable, 05L04.exe, j'obtiens le résultat suivant :


UN
SORTIR
B

La manière d'écrire le programme du Listing 5.4 est un peu différente. Il n'y a pas de variable
UNE ANALYSE
déclarée dans le programme. Au lieu de cela, les entiers sont passés directement à putchar() ,
comme indiqué aux lignes 6 à 11.

Comme vous l'avez peut­être compris, 65, 66 et 67 sont respectivement les valeurs numériques des
caractères A, B et C dans le jeu de caractères ASCII. À partir de l'exercice 5 de l'heure 4, « Comprendre
les types de données et les mots clés », vous pouvez découvrir que 10 est la valeur numérique du caractère
de retour à la ligne (\n).
Machine Translated by Google

78 Heure 5

Ainsi, respectivement, les lignes 6 et 7 placent le caractère A sur l'écran et font démarrer l'ordinateur
au début de la ligne suivante. De même, la ligne 8 met B à l'écran et la ligne 9 commence une nouvelle
ligne. Ensuite, la ligne 10 place C à l'écran et la ligne 11 commence une autre nouvelle ligne. En
conséquence, A, B et C sont placés au début de trois lignes consécutives, comme indiqué dans la section
de sortie.

Revisiter la fonction printf()


La fonction printf() est la première fonction de la bibliothèque C que vous avez utilisée dans ce livre pour
imprimer des messages à l'écran. printf() est une fonction très importante en C, il vaut donc la peine d'y
consacrer plus de temps.

Entrée de syntaxe
SYNTAXE
La syntaxe de la fonction printf() est #include
<stdio.h> int printf(const char *format­string, .
. .);

Ici const char *format­string est le premier argument qui contient le(s) spécificateur(s) de format ; ...
indique la section d'expression qui contient la ou les expressions à formater selon les spécificateurs de
format. Le nombre d'expressions est déterminé par le nombre de spécificateurs de format à l'intérieur
du premier argument. La fonction renvoie le nombre d'expressions formatées si elle réussit. Il renvoie
une valeur négative en cas d'erreur.

const char * est expliqué plus loin dans ce livre. Pour le moment, considérez le premier argument de la
fonction printf() comme une chaîne (une série de caractères entourés de guillemets doubles) avec
quelques spécificateurs de format à l'intérieur. Par exemple, vous pouvez passer "La somme de deux
entiers %d + %d est : %d.\n" à la fonction comme premier argument.

La figure 5.1 montre la relation entre la chaîne de format et les expressions. Notez que les spécificateurs
de format et les expressions correspondent dans l'ordre de gauche à droite.

FIGURE 5.1
Format chaîne Expressions
La relation entre
la chaîne de format et les
expressions dans printf().

printf("Une virgule flottante : %f ; Un entier : %d.", 123.45, 12345);


Machine Translated by Google

Gestion des entrées et sorties standard 79

N'oubliez pas que vous devez utiliser exactement le même nombre d'expressions que le nombre de spécificateurs de

format dans la chaîne de format.

Voici tous les spécificateurs de format qui peuvent être utilisés dans printf() :

%c Le spécificateur de format de caractère.

%ré Le spécificateur de format entier.

%je Le spécificateur de format entier (identique à %d).

%F Le spécificateur de format à virgule flottante.

%et Le spécificateur de format de notation scientifique (notez le e minuscule).

%ET Le spécificateur de format de notation scientifique (notez le E majuscule).

%g Utilise %f ou %e, selon le résultat le plus court.

%G Utilise %f ou %E, selon le résultat le plus court.

%Les Spécificateur de format octal non signé.

%s Le spécificateur de format de chaîne.

%dans
Le spécificateur de format d'entier non signé.

%X Le spécificateur de format hexadécimal non signé (notez le x minuscule).

%X Le spécificateur de format hexadécimal non signé (notez le X majuscule).

%p Affiche l'argument correspondant qui est un pointeur.

%n Enregistre le nombre de caractères écrits jusqu'à présent.


5
%% Affiche un signe de pourcentage (%).

Parmi les spécificateurs de format de cette liste, %c, %d, %f, %e et %E ont été introduits jusqu'à présent. Plusieurs autres sont expliqués plus loin

dans ce livre. La section suivante vous montre comment convertir des nombres décimaux en nombres hexadécimaux en utilisant %x ou %X.

Conversion en nombres hexadécimaux


Étant donné que toutes les données d'un ordinateur sont constituées de données binaires (une série de zéros et de

uns), toutes les données avec lesquelles nous travaillons ou que nous imprimons ne sont en réalité qu'une sorte de

représentation lisible par l'homme des données binaires. En tant que programmeur, il est souvent nécessaire de traiter

directement des données binaires, mais il est extrêmement long de déchiffrer une chaîne de zéros et de uns et d'essayer de

les convertir en données numériques ou de caractères significatives.


Machine Translated by Google

80 Heure 5

La solution à ce problème est la notation hexadécimale (ou hexadécimal), qui est une sorte de raccourci pour
représenter les nombres binaires. Hex est un compromis entre le système de numération en base 2 (ou binaire)
lisible par ordinateur et notre système plus familier en base 10 (ou décimal).
Convertir des nombres de l'hexadécimal au décimal (ou du binaire à l'hexadécimal) et inversement est
beaucoup plus facile (pour ne pas dire plus rapide) que de convertir directement du binaire au décimal ou vice­versa.

La différence entre un nombre décimal et un nombre hexadécimal est que l'hexa

décimal est un système de numération en base 16. Un nombre hexadécimal peut être représenté par quatre
bits. (24 ] est égal à 16, ce qui signifie que quatre bits peuvent produire 16 nombres uniques.)

Les nombres hexadécimaux 0 à 9 utilisent les mêmes symboles numériques trouvés dans les nombres
décimaux 0 à 9. A, B, C, D, E et F sont utilisés pour représenter, respectivement, les nombres 10 à 15 en
majuscules. (De même, en minuscules, a, b, c, d, e et f sont utilisés pour représenter ces nombres hexadécimaux.
Les hexagones majuscules et minuscules sont interchangeables et ne sont qu'une question de style.)

Le Listing 5.5 fournit un exemple de conversion de nombres décimaux en nombres hexadécimaux en utilisant
%x ou %X dans la fonction printf() .

TAPER LISTE 5.5 Conversion en nombres hexadécimaux

1 : /* 05L05.c : Conversion en nombres hexadécimaux */ 2 : #include <stdio.h>


3 : 4 : main() 5 : { 6 : 7 :

printf(“Hex(majuscule) printf(“%X Hex (minuscule) %x Décimal\n » ); %d\n",


printf(“%X printf(“%X printf(“%X 0, 0, 0); %d\n", 1, 1, 1);
printf(“%X printf(“%X printf(“%X %X %d\n", 2, 2, 2); %d\n", 3, 3,
printf(“%X printf(“ %X printf("%X %X 3); %d\n", 4, 4, 4); %d\n", 5,
printf("%X printf("%X printf("%X %X 5, 5); %d\n", 6, 6, 6); %d\n",
8 : 9 : 10 : 11printf("%X
: printf("%X printf("%X return %X 7, 7, 7); %d\n", 8, 8, 8);
12 : 0; %X %d\n", 9, 9, 9); %d\n", 10,
13: %X 10, 10); %d\n", 11, 11, 11);
14: %X %d\n", 12, 12, 12); %d\n",
%X 13, 13, 13); %d\n", 14, 14,
%X 14); %d\n", 15, 15, 15);
15 : 16 : 17 : %X
%X
%X
%X
18h19h20h21h %X
22: %X
23 :

24 : }
Machine Translated by Google

Gestion des entrées et sorties standard 81

La sortie suivante est obtenue en exécutant le fichier exécutable, 05L05.exe, sur mon ordinateur :

SORTIR Hex (majuscule) Hex (minuscule) Décimal 0 1


0 0

1 1

2 2 2

3 3 3
4 4 4

5 5 5

6 6 6
7 7 7

8 8 8

9 9 9
UN 10
B un B 11

C 12

ré CD 13
ET si 14

F 15

UNE ANALYSE
Ne paniquez pas lorsque vous voyez autant d' appels de fonction printf() utilisés dans le Listing
5.5. En fait, le programme du Listing 5.5 est très simple. Le programme n'a qu'un seul corps de
fonction des lignes 5 à 23.

La fonction printf() de la ligne 6 imprime un titre qui contient trois champs :


Hex(majuscule), Hex(minuscule) et Decimal.

Ensuite, les lignes 7 à 22 impriment les nombres hexadécimaux et décimaux de 0 à 15. Seize
appels printf() sont effectués pour accomplir le travail. Chacun des appels printf() a une chaîne de format
comme premier argument suivi de trois entiers comme trois expressions. Notez que les spécificateurs de 5
format hexadécimal %X et %x sont utilisés dans la chaîne de format dans chacun des appels printf() pour
convertir les expressions correspondantes au format hexadécimal (majuscules et minuscules).

En réalité, personne n'écrirait un programme comme celui du Listing 5.5. Au lieu de cela, une boucle peut
être utilisée pour appeler la fonction printf() à plusieurs reprises. La boucle (ou itération) est introduite dans
l'heure 7, "Travailler avec les boucles".

Spécification de la largeur de champ minimale


Le langage C vous permet d'ajouter un entier entre le signe de pourcentage (%) et la lettre dans un
spécificateur de format. L'entier est appelé spécificateur de largeur de champ minimale car il spécifie la
largeur de champ minimale et garantit que la sortie atteint la largeur minimale. Par exemple, dans %10f,
10 est un spécificateur de largeur de champ minimum qui garantit que la sortie comporte au moins 10
espaces de caractères. Ceci est particulièrement utile lors de l'impression d'une colonne de nombres.
Machine Translated by Google

82 Heure 5

L'exemple du Listing 5.6 montre comment utiliser le spécificateur de largeur de champ minimum.

TAPER LISTE 5.6 Spécification de la largeur de champ minimale

1 : /* 05L06.c : Spécification de la largeur de champ minimale */


2 : #include <stdio.h> 3 : 4 : main() 5 : { 6 : 7 :

entier num1, num2 ;

nombre1 =
12 ; num2 =
12345 ; printf("%d\n", num1);
8 : 9 : 10 : 11printf("%d\n",
: num2);
12 : printf("%5d\n", num1);
13: printf("%05d\n", num1);
14: printf("%2d\n", num2); renvoie
15 : 0;
16 : }

Voici la sortie que j'obtiens en exécutant le fichier exécutable 05L06.exe :

12
SORTIR
12345
12
00012
12345

UNE ANALYSE Dans le Listing 5.6, deux variables entières, num1 et num2, sont déclarées à la ligne 6 et
affectées respectivement de 12 et 12345 aux lignes 8 et 9.

Sans utiliser de spécificateurs de largeur de champ minimum, les lignes 10 et 11 affichent les deux entiers
en appelant la fonction printf() . Vous pouvez voir dans la section de sortie que la sortie de l'instruction de la
ligne 10 est 12, ce qui prend deux espaces de caractères, tandis que la sortie 12345 de la ligne 11 prend
cinq espaces de caractères.

À la ligne 12, une largeur de champ minimale, 5, est spécifiée par %5d. La sortie de la ligne 12 prend donc
cinq espaces de caractères, avec trois espaces blancs plus deux espaces de caractères de 12.
(Voir la troisième ligne de sortie dans la section de sortie.)

Le %05d dans printf(), affiché à la ligne 13, indique que la largeur de champ minimale est de 5, et le 0 indique
que des zéros sont utilisés pour remplir, ou "compléter", les espaces. Par conséquent, vous voyez que la
sortie effectuée par l'exécution de l'instruction de la ligne 13 est 00012.
Machine Translated by Google

Gestion des entrées et sorties standard 83

Le %2d à la ligne 14 définit la largeur de champ minimale sur 2, mais vous voyez toujours la sortie pleine grandeur
de 12345 à partir de la ligne 14. Cela signifie que lorsque la largeur de champ minimale est plus courte que la

largeur de la sortie, celle­ci est prise et la sortie est toujours imprimée dans son intégralité.

Alignement de la sortie
Comme vous l'avez peut­être remarqué dans la section précédente, toutes les sorties sont justifiées à droite.
En d'autres termes, par défaut, toutes les sorties sont placées sur le bord droit du champ, tant que la largeur du
champ est supérieure à la largeur de la sortie.

Vous pouvez modifier cela et forcer la sortie à être justifiée à gauche. Pour ce faire, vous devez préfixer le
spécificateur de champ minimum avec le signe moins (­). Par exemple, %­12d spécifie la largeur de champ
minimale à 12 et justifie la sortie à partir du bord gauche du champ.

Le Listing 5.7 donne un exemple d'alignement de la sortie par justification à gauche ou à droite.

TAPER LISTE 5.7 Sortie justifiée à gauche ou à droite

1 : /* 05L07.c : Alignement de la sortie */


2 : #include <stdio.h> 3 : 4 : main() 5 : { 6 : 7 :

entier num1, num2, num3, num4, num5 ;

nombre1 =
1 ; nombre2
= 12 ; nombre3
8 : 9 : 10 : 11=: 123 ; nombre4
12 :
5
= 1234 ; num5 =
13: 12345 ; printf("%8d %­8d\n", num1, num1);
14: printf("%8d %­8d\n", num2, num2); printf("%8d
%­8d\n", num3, num3); printf("%8d %­8d\n",
num4, num4); printf("%8d %­8d\n", num5,
15 : 16 : 17 num5);
: renvoie 0 ;
18 :
19 : }

J'obtiens la sortie suivante affichée sur l'écran de mon ordinateur après avoir exécuté l'exe cutable 05L07.exe :

1 1
SORTIR
12 12
123 123
1234 1234
12345 12345
Machine Translated by Google

84 Heure 5

UNE ANALYSE
Dans le Listing 5.7, il y a cinq variables entières, num1, num2, num3, num4 et num5, qui
sont déclarées à la ligne 6 et qui reçoivent des valeurs aux lignes 8 à 12.

Ces valeurs représentées par les cinq variables entières sont ensuite imprimées par les fonctions printf()
aux lignes 13–17. Notez que tous les appels printf() ont le même premier argument : "%8d %­8d\n". Ici, le
premier spécificateur de format, %8d, aligne la sortie sur le bord droit du champ, et le deuxième spécificateur,
%­8d, aligne la sortie sur le bord gauche du champ.

Après l'exécution des instructions des lignes 13 à 17, l'alignement est accompli et la sortie est affichée à l'écran
comme ceci :

1 1
12 12
123 123
1234 1234
12345 12345

Utilisation du spécificateur de précision


Vous pouvez mettre un point . et un entier juste après le spécificateur de largeur de champ minimum. La
combinaison du point (.) et de l'entier constitue un spécificateur de précision. Vous pouvez utiliser le spécificateur
de précision pour déterminer le nombre de décimales pour les nombres à virgule flottante ou pour spécifier la
largeur (ou longueur) maximale du champ pour les entiers ou les chaînes. (Les cordes en do sont introduites dans
l'heure 13, "Manipuler les cordes".)

Par exemple, avec %10.3f, la longueur minimale de la largeur de champ est spécifiée sur 10 caractères et le
nombre de décimales est défini sur 3. (N'oubliez pas que le nombre de décimales par défaut est 6.) Pour les
nombres entiers, %3.8d indique que la largeur de champ minimale est de 3 et que la largeur de champ maximale
est de 8.

Le Listing 5.8 donne un exemple d'utilisation de spécificateurs de précision.

TAPER LISTE 5.8 Utilisation des spécificateurs de précision

1 : /* 05L08.c : Utilisation de spécificateurs de précision */


2 : #include <stdio.h> 3 : 4 : main() 5 : { 6 : 7 :

entier
entier_num ; double flt_num ;

int_num = 123 ;
flt_num = 123,456789 ;
8 : 9 : 10 : 11printf("Format
: entier par défaut : %d\n", int_num);
Machine Translated by Google

Gestion des entrées et sorties standard 85

12 : printf("Avec spécificateur de précision : %2.8d\n", int_num); printf("Format flottant


13 : par défaut : %f\n", flt_num); printf("Avec spécificateur de précision
flt_num); : %­10.2f\n",
renvoie 0;
14 :
15 :
16 : }

Après avoir exécuté le fichier exécutable 05L08.exe sur mon ordinateur, j'obtiens le résultat suivant à
l'écran :

Format entier par défaut : Avec 123


SORTIR spécificateur de précision : 00000123 Format flottant
par défaut : 123,456789 Avec spécificateurprécision
de :
123,46

Le programme du Listing 5.8 déclare une variable entière, int_num, à la ligne 6, et un nombre à
UNE ANALYSE
virgule flottante, flt_num, à la ligne 7. Les lignes 9 et 10 attribuent 123 et 123,456789 à int_num
et flt_num, respectivement.

À la ligne 11, le format entier par défaut est spécifié pour la variable entière, int_num, tandis que
l'instruction de la ligne 12 spécifie le format entier avec un spécificateur de précision qui indique que la
largeur maximale du champ est de huit caractères. Par conséquent, vous voyez que cinq zéros sont
remplis avant l'entier 123 dans la deuxième ligne de la sortie.

Pour la variable à virgule flottante, flt_num, la ligne 13 imprime la valeur à virgule flottante dans le format
par défaut, et la ligne 14 réduit les décimales à deux en plaçant le spécificateur de précision .2 dans le
spécificateur de format %­10.2f. Notez ici que la justification à gauche est également spécifiée par le
signe moins (­) dans le spécificateur de format à virgule flottante.

Le nombre à virgule flottante 123,46 dans la quatrième ligne de la sortie est produit par l'instruction 5
de la ligne 14 avec le spécificateur de précision pour deux décimales. Par conséquent, 123,456789
arrondi à deux décimales devient 123,46.

Résumé
Dans cette leçon, vous avez appris les concepts, spécificateurs et fonctions importants suivants :

• Le langage C traite un fichier comme une série d'octets. •

stdin, stdout et stderr sont trois flux de fichiers qui sont pré­ouverts et que vous pouvez toujours
utiliser.

• Les fonctions de la bibliothèque C getc() et getchar() peuvent être utilisées pour lire un caractère à
partir de l'entrée standard.

• Les fonctions de la bibliothèque C putc() et putchar() peuvent être utilisées pour écrire un caractère
à la sortie standard.
Machine Translated by Google

86 Heure 5

• %x ou %X peuvent être utilisés pour convertir des nombres décimaux en nombres hexadécimaux.

• Une largeur de champ minimale peut être spécifiée et garantie en ajoutant un entier dans un
spécificateur de format.

• Une sortie peut être alignée sur le bord gauche ou droit du champ de sortie. • Un spécificateur

de précision peut être utilisé pour spécifier le nombre de décimales pour flottant
nombres de points ou la largeur de champ maximale pour les entiers ou les chaînes.

Dans la prochaine leçon, vous découvrirez certains opérateurs importants en C.

Questions et réponses

Q Que sont stdin, stdout et stderr ?


A En C, un fichier est traité comme une série d'octets appelée file stream. stdin, stdout,
et stderr sont tous des flux de fichiers pré­ouverts. stdin est l'entrée standard pour la lecture ; stdout est
la sortie standard pour l'écriture ; stderr est l'erreur standard pour afficher les messages d'erreur.

Q Combien coûte l'hexagone numéro 32 ?

Un hexadécimal, ou hexadécimal en abrégé, est un système numérique de base 16. Par conséquent, 32
(hex) est égal à 3*161 +2*160 , ou 50 en décimal.

Q Est­ ce que getc(stdin) et getchar() sont équivalents ?

R Étant donné que la fonction getchar() lit à partir du flux de fichiers stdin par défaut, getc(stdin) et
getchar() sont équivalents dans ce cas.

Q Dans la fonction printf("L'entier %d est identique à l'hex %x", 12, 12), quelle est la relation entre les
spécificateurs de format et les expressions ?

A Les deux spécificateurs de format, %d et %x, spécifient les formats des valeurs numériques contenues
dans la section expression. Ici, la première valeur numérique de 12 va être imprimée au format entier,
tandis que la seconde 12 (dans la section expression) sera affichée au format hexadécimal. D'une
manière générale, le nombre de spécificateurs de format dans la section format doit correspondre au
nombre d'expressions dans la section expression.

Atelier
Pour aider à consolider votre compréhension de la leçon de cette heure, nous vous encourageons à répondre
aux questions du quiz et à terminer les exercices fournis dans l'atelier avant de passer à la leçon suivante. Les
réponses et les conseils aux questions et exercices sont donnés dans l'annexe D, « Réponses aux questions et
exercices du quiz ».
Machine Translated by Google

Gestion des entrées et sorties standard 87

Questionnaire

1. Pouvez­vous aligner votre sortie sur le bord gauche, plutôt que sur le bord droit, de la sortie
domaine?

2. Quelle est la différence entre putc() et putchar() ?

3. Que renvoie getchar() ?

4. Dans %10.3f, quelle partie est le spécificateur de largeur de champ minimum et lequel est le spécificateur de
précision ?

Des exercices

1. Écrivez un programme pour assembler les caractères B, y et e à l'écran.

2. Affichez les deux nombres 123 et 123.456 et alignez­les sur le bord gauche du
domaine.

3. Étant donné trois nombres entiers, 15, 150 et 1500, écrivez un programme qui imprime les nombres entiers sur
l'écran au format hexadécimal.

4. Écrivez un programme qui utilise getchar() et putchar() pour lire un caractère saisi
par l'utilisateur et écrivez le caractère à l'écran.

5. Si vous compilez le programme C suivant, quels messages d'avertissement ou d'erreur


obtenir?

principale()

{
int ch ;
ch = getchar();
putchar(ch); 5
renvoie 0 ;
}
Machine Translated by Google
Machine Translated by Google

PARTIE II
Opérateurs et instructions
de flux de contrôle
Heure
6 Manipulation des données

7 Travailler avec des boucles

8 Utilisation des opérateurs conditionnels

9 Utilisation des modificateurs de données et des mathématiques


Les fonctions

10 Contrôle du déroulement du programme


Machine Translated by Google
Machine Translated by Google

HEURE 6

Manipulation des données


"La question est," dit Humpty Dumpty, "qui doit
être le maître ­ c'est tout."

—L. Carroll

Vous pouvez considérer les opérateurs comme des verbes en C qui vous permettent de
manipuler des données (qui sont comme des noms). En fait, vous avez appris certains
opérateurs, tels que + (addition), ­ (soustraction), * (multiplication), / (division) et % (reste), à
l'heure 3, "Apprendre la structure d'un programme C .” Le langage C possède un riche ensemble
d'opérateurs. Au cours de cette heure, vous découvrirez d'autres opérateurs, tels que

• Opérateurs d'affectation arithmétique •

Opérateur moins unaire • Opérateurs

d'incrémentation et de décrémentation •

Opérateurs relationnels • Opérateur de

distribution
Machine Translated by Google

92 Heure 6

Opérateurs d'affectation arithmétique


Avant de passer aux opérateurs d'affectation arithmétiques, examinons d'abord de plus près
l'opérateur d'affectation lui­même.

L'opérateur d'affectation (=)


Dans le langage C, l' opérateur = est appelé un opérateur d'affectation, que vous avez vu et utilisé
pendant plusieurs heures.

Le formulaire de déclaration générale pour utiliser un opérateur d'affectation est

opérande gauche = opérande droit ;

Ici, l'instruction provoque l' affectation (ou l'écriture) de la valeur de l' opérande de droite à
l'emplacement mémoire de l' opérande de gauche. Ainsi, après l'affectation, l'opérande gauche
sera égal à la valeur de l'opérande droit. De plus, l'ensemble de l'expression d'affectation est évalué
à la même valeur que celle qui est affectée à l' opérande de gauche.

Par exemple, l'énoncé a = 5 ; écrit la valeur de l'opérande de droite (5) dans l'emplacement mémoire
de la variable entière a (qui est l'opérande de gauche dans ce cas).

De même, l'énoncé b = a = 5 ; attribue d'abord 5 à la variable entière a , puis à la variable entière b.


Après l'exécution de l'instruction, a et b contiennent la valeur 5.

Il est important de se rappeler que l'opérande de gauche de l'opérateur d'affectation doit être une
expression dans laquelle vous pouvez légalement écrire des données. Une expression telle que 6
= a, bien qu'elle puisse sembler correcte en un coup d'œil, est en fait inversée et ne fonctionnera
pas. L' opérateur = fonctionne toujours de droite à gauche ; par conséquent, la valeur de gauche
doit être une forme de variable pouvant recevoir les données de l'expression de droite.

Ne confondez pas l'opérateur d'affectation (=) avec l'opérateur relationnel ==


(appelé opérateur égal à). L' opérateur == est introduit plus tard dans cette
heure.

Combinaison d'opérateurs arithmétiques avec =


Considérez cet exemple : Étant donné deux variables entières, x et y, comment assignez­vous
l'addition de x et y à une autre variable entière, z ?
Machine Translated by Google

Manipulation des données 93

En utilisant l'opérateur d'affectation (=) et l'opérateur d'addition (+), vous obtenez ce qui suit
déclaration:

z=x+y;

Comme vous pouvez le voir, c'est assez simple. Maintenant, considérons à nouveau le même exemple.
Cette fois, au lieu d'affecter le résultat à la troisième variable, z, réécrivons le résultat de l'addition dans la
variable entière, x :

x=x+y;

N'oubliez pas que l' opérateur = fonctionne toujours de droite à gauche, donc le côté droit sera évalué en
premier. Ici, sur le côté droit de l'opérateur d'affectation (=), l'addition de x et y est exécutée ; du côté gauche
de =, la valeur précédente de x est remplacée par le résultat de l'addition du côté droit.

Le langage C vous donne un nouvel opérateur, +=, pour faire l'addition et l'affectation ensemble. Par
conséquent, vous pouvez réécrire l'énoncé x = x + y ; comme

x += y ;

Les combinaisons de l'opérateur d'affectation (=) avec les opérateurs arithmétiques, +, ­, *, / et %, vous
donnent un autre type d' opérateurs, les opérateurs d'affectation arithmétique :

Opérateur La description
+= Opérateur d'affectation d'addition

­=
Opérateur d'affectation de soustraction

*=
Opérateur d'affectation de multiplication

/= Opérateur d'affectation de division

%= Opérateur d'affectation de reste

Ce qui suit montre l'équivalence des déclarations :

x += y ; est équivalent à x = x + y ;
6
x­= y ; est équivalent à x = x ­ y ;

x *= *
y; est équivalent à x = x Y;

x /= y ; est équivalent à x = x / y ;

x %= y ; est équivalent à x = x % y ;

Notez que la déclaration


Machine Translated by Google

94 Heure 6

z=z *
x+y ;

n'est pas équivalent à l'énoncé

z*=x+y;
car

z *= x + y

multiplie z par tout le côté droit de l'instruction, de sorte que le résultat serait le
pareil que

z=z *(x+y);

Le Listing 6.1 donne un exemple d'utilisation de certains des opérateurs d'affectation arithmétiques.

TAPER LISTE 6.1 Utilisation des opérateurs d'affectation arithmétique

1 : /* 06L01.c : Utilisation des opérateurs d'affectation arithmétique */


2 : #include <stdio.h> 3 : 4 : main() 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 : }

entier x, y, z ;

x = 1 ; /* initialiser x */ y = 3; /* initialise y
*/ z = 10; /* initialiser
donné xz =*/ %d,
printf("Étant
y = %d, et
z = %d,\n", x, y, z);

x=x+y;
printf("x = x + y affecte %d à x ;\n", x);

x = 1 ; /* réinitialiser x */ x += y;
printf("x += y assigne %d à x ;
\n", x);

x = 1 ; /* réinitialiser x */ x + y;
z=z *
printf("z = z
*
x + y affecte %d à z ;\n", z );

z = 10 ; /* réinitialiser z */ * (x +
z=z y); printf(“z = z * (x + y)
assigne %d à z;\n”, z);

z = 10 ; /* réinitialiser z */ z *= x
+ y; printf("z *= x + y affecte %d
à z.\n", z);

renvoie 0 ;
Machine Translated by Google

Manipulation des données 95

Une fois ce programme compilé et lié, un fichier exécutable est créé. Sur ma machine, ce fichier exécutable
est nommé 06L01.exe. Voici la sortie affichée après avoir lancé l'exécutable :

Étant donné x = 1, y = 3 et z = 10, x = x + y


SORTIR attribue 4 à x ; x += y attribue 4 à x ;

z=z *
x + y attribue 13 à z ; * (x + y)
z=z attribue 40 à z ; z *= x + y attribue 40
à z.

UNE ANALYSE
La ligne 2 du Listing 6.1 inclut le fichier d'en­tête stdio.h en utilisant la directive include . Le
fichier d'en­tête stdio.h est nécessaire pour la fonction printf() utilisée dans les lignes 4–33.

Les lignes 8 à 10 initialisent trois variables entières, x, y et z, qui sont déclarées à la ligne 6.
La ligne 11 imprime ensuite les valeurs initiales affectées à x, y et z.

L'instruction de la ligne 13 utilise un opérateur d'addition et un opérateur d'affectation pour additionner les
valeurs contenues par x et y, puis affecte le résultat à x. La ligne 14 affiche le résultat à l'écran.

De même, les lignes 17 et 18 font la même addition et affichent à nouveau le résultat, après que la
variable x est réinitialisée à la valeur 1 à la ligne 16. Cette fois, l'opérateur d'affectation arithmétique, +=, est
utilisé.

La valeur de x est à nouveau réinitialisée à la ligne 20. La ligne 21 effectue une multiplication et une addition
et enregistre le résultat dans la variable entière z ; c'est­à­dire z = zx + y;.*L' le
appel
résultat,
printf()
13,ààlal'écran.
ligne 22
Encore
affiche
une fois, le x = 1 ; L'instruction à la ligne 20 réinitialise la variable entière, x.

Les lignes 24 à 30 affichent deux résultats de deux calculs. Les deux résultats sont en fait les mêmes (c'est­
à­dire 40) car les deux calculs des lignes 25 et 29 sont équivalents. La seule différence entre les deux
instructions aux lignes 25 et 29 est que l'opérateur d'affectation arithmétique, *=, est utilisé à la ligne 29.

6
Obtenir des négations de valeurs numériques
Si vous souhaitez modifier le signe d'un nombre, vous pouvez placer l'opérateur moins (­) juste avant
le nombre. Par exemple, étant donné un entier de 7, vous pouvez obtenir sa valeur négative en changeant
le signe de l'entier comme ceci : ­7. Ici, ­ est l'opérateur moins.

Le symbole ­ utilisé de cette manière est appelé l' opérateur moins unaire. En effet, l'opérateur ne prend
qu'un seul opérande : l'expression immédiatement à sa droite. Le type de données de l'opérande peut être
n'importe quel entier ou nombre à virgule flottante.
Machine Translated by Google

96 Heure 6

Vous pouvez également appliquer l'opérateur moins unaire à un nombre entier ou à une variable à virgule flottante.
Par exemple, étant donné x = 1,234, ­x est égal à ­1,234. Ou, étant donné x = ­1,234, ­x est égal à 1,234
puisque la négation d'une valeur négative donne un nombre positif.

Ne confondez pas l'opérateur moins unaire avec l'opérateur de soustraction, bien


que les deux opérateurs utilisent le même symbole. Par exemple, la déclaration
suivante :

z = x ­ ­y ;
est en fait la même que cette déclaration:

z = x ­ (­y);
ou celui­ci :

z=x+y;
Ici, dans les deux déclarations, le premier symbole ­ est utilisé comme opérateur de
soustraction, tandis que le second symbole ­ est l'opérateur moins unaire.

Incrémenter ou décrémenter de un
Les opérateurs d'incrémentation et de décrémentation sont très pratiques à utiliser lorsque vous souhaitez ajouter
ou soustraire 1 à une variable. Le symbole de l'opérateur d'incrémentation est ++. L'opérateur de décrémentation
est ­­.

Par exemple, vous pouvez réécrire la déclaration x = x + 1 ; comme ++x;, ou vous pouvez remplacer x = x ­ 1;
avec ­­x;.

En fait, il existe deux versions des opérateurs d'incrémentation et de décrémentation. Dans le ++x ; , où ++
apparaît avant son opérande, l'opérateur d'incrémentation est appelé opérateur de pré­incrémentation. Cela fait
référence à l'ordre dans lequel les choses se produisent : l'opérateur ajoute d'abord 1 à x, puis donne la nouvelle
valeur de x. De même, dans l'instruction ­­x;, l' opérateur de pré­décrémentation soustrait d'abord 1 de x , puis
donne la nouvelle valeur de x.

Si vous avez une expression comme x++, où ++ apparaît après son opérande, vous utilisez l' opérateur de post­
incrémentation. De même, dans x­­, l'opérateur de décrémentation est appelé opérateur de post­décrémentation.

Par exemple, dans l'instruction y = x++;, y reçoit d'abord la valeur d'origine de x , puis x est augmenté de 1.

L'opérateur de post­décrémentation a une histoire similaire. Dans l'instruction y = x­­ ; l'affectation de y à la


valeur de x a lieu d'abord, puis x est décrémenté. Le programme du Listing 6.2 montre les différences entre les
deux versions des opérateurs d'incrémentation et des opérateurs de décrémentation.
Machine Translated by Google

Manipulation des données 97

TAPER LISTE 6.2 Utilisation des opérateurs de pré­ ou post­incrémentation et de décrémentation

1 : /* 06L02.c : opérateurs de pré­ ou post­incrémentation (décrémentation) */ 2 : #include


<stdio.h> 3 : 4 : main() 5 : { 6 :

int w, x, y, z, résultat ;
7:
8: w = x = y = z = 1 ; /* initialiser x et y */ printf("Étant donné w = %d, x
9: = %d, y = %d, et z = %d,\n", w, x, y, z);
10 :
11 : résultat = ++w ;
12 : printf("++w est évalué à %d et w est maintenant %d\n", résultat, w); résultat = x++ ;
13 : printf("x++ est évalué à %d et x est maintenant %d\n", résultat, x); résultat = ­­y ; printf("­­
14 : y est évalué à %d et y est maintenant %d\n", résultat, y); résultat = z­­ ; printf("z­­ est
15 : évalué à %d et z est maintenant %d\n", résultat, z); renvoie 0 ;
16 :
17 :
18 :
19 :
20 : }

Le résultat suivant est obtenu en lançant le fichier exécutable 06L02.exe :

Étant donné w = 1, x = 1, y = 1 et z = 1, ++w est évalué


SORTIR
à 2 et w est maintenant 2 x++ est évalué à 1 et x est
maintenant 2 ­­y est évalué à 0 et y est maintenant 0 z
­­ évalue à 1 et z vaut maintenant 0

Dans la fonction main() , la ligne 8 du Listing 6.2 affecte 1 à chacune des variables entières, w, x,
UNE ANALYSE
y et z. L' appel printf() à la ligne 9 affiche les valeurs contenues par les quatre variables entières.

Ensuite, l'instruction de la ligne 11 est exécutée et le résultat de la pré­incrémentation de w est affecté


à la variable entière résultat. À la ligne 12, la valeur de result, qui est 2, est imprimée à l'écran, ainsi que
la valeur de w après l'instruction de pré­incrémentation.
6
Notez que w est toujours égal à 2 puisque l'incrément a eu lieu avant que la nouvelle valeur de w ne
soit affectée au résultat.

Les lignes 13 et 14 obtiennent le post­incrément de x et impriment le résultat. Comme vous le savez, le


résultat est obtenu avant que la valeur de x ne soit augmentée. Par conséquent, vous voyez la valeur 1
(l'ancienne valeur de x) à partir du résultat de x++, tandis que la nouvelle valeur de x est 2 puisqu'elle a été
incrémentée après l'affectation pour obtenir le résultat de la ligne 13 L'opérateur de pré­décrémentation de
la ligne 15 provoque la valeur de y doit être réduite de 1 avant que la nouvelle valeur ne soit affectée à la
variable entière résultat. Par conséquent, vous voyez 0 comme résultat de ­­y affiché à l'écran, qui reflète
la nouvelle valeur de y, qui est également 0.
Machine Translated by Google

98 Heure 6

À la ligne 17, cependant, l'opérateur de post­décrémentation n'a aucun effet sur l'affectation car la valeur
d'origine de z est donnée à la variable entière résultat avant que z ne soit diminué de 1.
La post­décrémentation agit comme si la ligne 17 était simplement résultat = z, z étant ensuite décrémenté
de 1 après l'exécution de l'instruction. La ligne 18 imprime donc le résultat 1, qui est bien sûr la valeur
originale de z, ainsi que 0, la valeur de z après la post­décrémentation.

Supérieur ou inférieur à ?
Il existe six types de relations entre deux expressions : égal à, différent de, supérieur à, inférieur à, supérieur
ou égal à et inférieur ou égal à. Ainsi, le langage C fournit ces six opérateurs relationnels :

Opérateur La description
== Égal à

!= Pas égal à

> Plus grand que

< Moins que

>= Plus grand ou égal à

<= Inférieur ou égal à

Tous les opérateurs relationnels ont une priorité inférieure aux opérateurs arithmétiques.
Par conséquent, toutes les opérations arithmétiques de part et d'autre d'un opérateur relationnel sont
effectuées avant toute comparaison. Vous devez utiliser des parenthèses pour délimiter les opérations des
opérateurs qui doivent être effectuées en premier.

Parmi les six opérateurs relationnels, les opérateurs >, <, >= et <= ont une priorité plus élevée que les
opérateurs == et != .

Par exemple, l'expression


*
X y<z+3

est interprété comme

(x * y) < (z + 3)

Un autre point important est que toutes les expressions relationnelles produisent un résultat de 0 ou 1.
En d'autres termes, une expression relationnelle est évaluée à 1 si la relation spécifiée est vérifiée.
Sinon, 0 est renvoyé.

Étant donné x = 3 et y = 5, par exemple, l'expression relationnelle x < y donne un résultat de 1.

Le Listing 6.3 montre d'autres exemples d'utilisation d'opérateurs relationnels.


Machine Translated by Google

Manipulation des données 99

Lorsque plusieurs opérateurs différents apparaissent ensemble dans une expression,


les opérandes intermédiaires sont associés à des opérateurs dans un ordre donné.
La priorité des opérateurs fait référence à l'ordre dans lequel les opérateurs et les
opérandes sont regroupés. Les opérateurs qui ont la priorité la plus élevée dans une
expression sont regroupés avec leurs opérandes en premier, Par exemple, dans l'expression
y­3
z+x *

L' opérateur * a une priorité plus élevée que les opérateurs + et ­ . Par conséquent, y sera
X * évalué en premier et son résultat devient l'opérande de droite de l' opérateur + . Le
résultat est ensuite donné à l' opérateur ­ comme opérande de gauche.

Si vous souhaitez remplacer la priorité des opérateurs par défaut, vous pouvez
utiliser des parenthèses pour regrouper les opérandes dans une expression. Si, par
exemple, vous vouliez réellement multiplier z + x par y ­ 3, vous pourriez réécrire
l'expression ci­dessus sous la forme (z + x) * (y ­ 3)

De plus, vous pouvez toujours utiliser les parenthèses lorsque vous n'êtes pas tout à fait
sûr des effets de la priorité des opérateurs ou que vous souhaitez simplement faciliter la
lecture de votre code.

TAPER LISTE 6.3 Résultats produits par des expressions relationnelles

1 : /* 06L03.c : Utilisation des opérateurs relationnels */ 2 : #include


<stdio.h> 3 : 4 : main() 5 : { 6 : 7 : 8 : 9 : 10 : 11 : 12 : 13 : 14 : 15 :
16 : 17 : 18 : 19 : 20 : }

int x, y ;
double z ;

x=7;y
= 25 ; z = 6
24,46 ;
printf("Étant donné x = %d, y = %d, et z = %.2f,\n", x, y, z); printf(“x >= y produit :
%d\n”, x >= y); printf("x == y produit : %d\n", x == y); printf("x < z produit : %d\n", x <
z); printf("y > z produit : %d\n", y > z); printf(“x != y ­ 18 produit : %d\n”, x != y ­ 18);
printf(“x + y != z produit : %d\n”, x + y != z); renvoie 0 ;
Machine Translated by Google

100 Heure 6

Une fois l'exécutable 06L03.exe exécuté, la sortie suivante s'affiche sur l'écran de mon
ordinateur :
Étant donné x = 7, y = 25 et z = 24,46, x >= y produit :
SORTIR 0 x == y produit : 0 x < z produit : 1 y > z produit : 1
x != y ­ 18 produit : 0 x + y != z donne : 1

UNE ANALYSE Il y a deux variables entières, x et y, et une variable à virgule flottante z, déclarées
respectivement aux lignes 6 et 7.

Les lignes 9 à 11 initialisent les trois variables. La ligne 12 imprime les valeurs affectées aux
variables.

Comme la valeur de x est 7 et la valeur de y est 25, y est supérieur à x. Par conséquent, la ligne 13
imprime 0, qui est le résultat obtenu par l'expression relationnelle x >= y.

De même, à la ligne 14, l'expression relationnelle x == y donne 0.

Les lignes 15 et 16 impriment le résultat de 1, qui est obtenu par les évaluations de x < z et y
> z.

L'instruction de la ligne 17 affiche 0, qui est le résultat de l'expression relationnelle x != y ­ 18.


Étant donné que y ­ 18 donne 7 et que la valeur de x est 7, la relation != ne tient pas. A la ligne
18, l'expression x + y != z produit 1, qui s'affiche sur la
écran.

Soyez prudent lorsque vous comparez deux valeurs pour l'égalité. En raison de la
troncature ou de l'arrondi, certaines expressions relationnelles, qui sont algébriquement
vraies, peuvent donner 0 au lieu de 1. Par exemple, regardez l'expression relationnelle suivante :

1 / 2 + 1 / 2 == 1
Ceci est algébriquement vrai et on s'attendrait à ce qu'il soit évalué à 1.
L'expression, cependant, donne 0, ce qui signifie que la relation d'égal à ne tient pas.
En effet, la troncature de la division entière, c'est­à­dire 1/2 , produit un entier : 0, et
non 0,5.
Un autre exemple est 1.0 / 3.0, qui produit 0.33333... C'est un nombre avec un nombre
infini de décimales. Mais l'ordinateur ne peut contenir qu'un nombre limité de décimales.
Par conséquent, l'expression

1.0 / 3.0 + 1.0 / 3.0 + 1.0 / 3.0 == 1.0


peut ne pas donner 1 sur certains ordinateurs, bien que l'expression soit
algébriquement vraie.
Machine Translated by Google

Manipulation des données 101

Utilisation de l'opérateur Cast


En C, vous pouvez convertir le type de données d'une variable, d'une expression ou d'une constante en
un autre en préfixant l'opérateur cast. Cette conversion ne change pas l'opérande lui­même ; lorsque
l'opérateur cast est évalué, il produit la même valeur (mais représentée sous la forme d'un type différent),
que vous pouvez ensuite utiliser dans le reste d'une expression.

La forme générale de l'opérateur cast est

(type de données) x

Ici data­type spécifie le nouveau type de données que vous voulez. x est une variable (ou constante ou
expression) d'un type de données différent. Vous devez inclure les parenthèses ( et ) autour du nouveau
type de données pour créer un opérateur de conversion.

Par exemple, l'expression (float)5 convertit l'entier 5 en un nombre à virgule flottante,


5.0.

Le programme du Listing 6.4 montre un autre exemple d'utilisation de l'opérateur cast.

TAPER LISTE 6.4 Jouer avec l'opérateur Cast

1 : /* 06L04.c : Utilisation de l'opérateur cast */ 2 : #include


<stdio.h> 3 : 4 : main() 5 : { 6 :

int x, y ;
7:
8: x=7;y
9: =5;
10 : printf("Étant donné x = %d, y = %d\n", x, y); printf("x / y
11 : produit : %d\n", x / y); printf("(float)x / y produit : %f\n",
12 : (float)x / y); renvoie 0 ;
13 :
14 : }
6
La sortie suivante est obtenue en exécutant l'exécutable 06L04.exe sur mon ordinateur :

Étant donné x = 7, y = 5 x /
SORTIR
y produit : 1 (float)x / y
produit : 1,400000

Dans le Listing 6.4, il y a deux variables entières, x et y, déclarées à la ligne 6, et initialisées aux
UNE ANALYSE
lignes 8 et 9, respectivement. La ligne 10 affiche alors les valeurs contenues par les variables
entières x et y.
Machine Translated by Google

102 Heure 6

L'instruction de la ligne 11 imprime la division entière de x/y. Comme la partie fractionnaire est tronquée, le
résultat de la division entière est 1.

Cependant, à la ligne 12, l'opérateur cast (float) convertit la valeur de x en une valeur à virgule flottante. Par
conséquent, l' expression (float)x/y devient une division à virgule flottante qui renvoie un nombre à virgule
flottante. C'est pourquoi vous voyez le nombre à virgule flottante 1,400000 affiché à l'écran après l'exécution
de l'instruction de la ligne 12.

Résumé
Dans cette leçon, vous avez découvert les opérateurs importants suivants :

• L'opérateur d'affectation =, qui a deux opérandes (un de chaque côté). La valeur de l'opérande de
droite est affectée à l'opérande de gauche. L'opérande sur le côté gauche doit être une forme de
variable qui peut accepter la nouvelle valeur.

• Les opérateurs d'affectation arithmétique +=, ­=, *=, /= et %=, qui sont combinés
des opérateurs arithmétiques avec l'opérateur d'affectation.

• L'opérateur moins unaire (­), qui correspond à la négation d'une valeur numérique. • Les deux

versions de l'opérateur d'incrémentation, ++. Vous savez que dans ++x, l' opérateur ++ est appelé
opérateur de pré­incrémentation ; et dans x++, ++ est l'opérateur de post­incrémentation.

• Les deux versions de l'opérateur de décrémentation, ­­. Vous avez appris que, par exemple, dans ­­x,
l' opérateur ­­ est l'opérateur de pré­décrémentation, et dans x­­, ­­ est appelé l'opérateur de post­
décrémentation.

• Les six opérateurs relationnels en C : == (égal à), != (différent de), > (supérieur à), < (inférieur à), >=
(supérieur ou égal à) et <= (moins supérieur ou égal à). • Comment changer le type de données

d'une expression en préfixant un opérateur cast à la


Les données.

Dans la prochaine leçon, vous découvrirez les boucles en langage C.

Questions et réponses

Q Quelle est la différence entre l'opérateur de pré­incrémentation et l'opérateur de post­incrémentation


opérateur ?

A L'opérateur de pré­incrémentation augmente d'abord la valeur de l'opérande de 1, puis produit la valeur


modifiée. D'autre part, l'opérateur de post­incrémentation donne d'abord la valeur d'origine de son
opérande, puis incrémente l'opérande. Par exemple, étant donné x = 1, l' expression ++x donne 2,
alors que l'expression x++ est évaluée à 1 avant de modifier réellement x.
Machine Translated by Google

Manipulation des données 103

Q L'opérateur moins unaire (­) est ­il le même que l'opérateur de soustraction (­) ?

R Non, ce ne sont pas les mêmes, bien que les deux opérateurs partagent le même symbole. La
signification du symbole est déterminée par le contexte dans lequel il apparaît. L'opérateur moins
unaire est utilisé pour changer le signe d'une valeur numérique. En d'autres termes, l'opérateur
moins unaire donne la négation de la valeur. L'opérateur de soustraction est un opérateur arithmétique
qui effectue une soustraction entre ses deux opérandes.

Q Lequel a une priorité plus élevée, un opérateur relationnel ou un opérateur arithmétique


opérateur?

A Un opérateur arithmétique a une priorité plus élevée qu'un opérateur relationnel. Pour y + z > x
exemple, dans l'expression x du * + y, la priorité des opérateurs de
plus haut au plus bas va de * à + et enfin >. L'expression entière est donc interprétée comme ((x *
y) + z) > (x + y).

Q Quelle valeur est donnée par une expression relationnelle ?

A Une expression relationnelle est évaluée à 0 ou 1. Si la relation indiquée par un opérateur relationnel
dans une expression est vraie, l'expression est évaluée à 1 ; sinon, l'expression est évaluée à 0.

Atelier
Pour aider à consolider votre compréhension de la leçon de cette heure, nous vous encourageons à
répondre aux questions du quiz et à terminer les exercices fournis dans l'atelier avant de passer à la leçon
suivante. Les réponses et les conseils aux questions et exercices sont donnés dans l'annexe C, « Réponses
aux questions et exercices du quiz ».

Questionnaire

1. Quelle est la différence entre l' opérateur = et l' opérateur == ?

2. Dans l'expression x + ­ y ­ ­ z, quel(s) opérateur(s) sont des opérateurs de soustraction, et


lesquels sont des opérateurs moins unaires ?

3. Étant donné x = 15 et y = 4, quelles valeurs valent les expressions x / y et


6
(float)x / rendement y, respectivement ?

4. L'expression y *= x + 5 est­elle équivalente à l'expression y = y * X+5?

Des exercices

1. Étant donné x = 1 et y = 3, écrivez un programme pour afficher les résultats de ces


expressions : x += y, x += ­y, x ­= y, x ­= ­y, x *= y , et x *= ­Y.
Machine Translated by Google

104 Heure 6

2. Étant donné x = 3 et y = 6, quelle est la valeur de z après l'énoncé


z = x * et == 18 ;

est exécuté?

3. Écrivez un programme qui initialise la variable entière x avec 1 et génère les résultats avec les
deux instructions suivantes : printf(“x++ produit : %d\n”, x++); printf("Maintenant x contient :
%d\n", x);

4. Réécrivez le programme que vous avez écrit dans l'exercice 3. Cette fois, incluez les deux
déclarations :
printf("x = x++ produit : %d\n", x = x++);
printf("Maintenant x contient : %d\n", x);

Qu'obtenez­vous après avoir lancé l'exécutable du programme ? Pouvez­vous expliquer pourquoi


vous obtenez un tel résultat ?

5. Le programme suivant est supposé comparer les deux variables, x et y, pour


égalité. Quel est le problème avec le programme ? (Astuce : exécutez le programme pour voir ce
qu'il imprime.)
#include <stdio.h>

principale()

int x, y ;

x=y=0;
printf("Le résultat de la comparaison est : %d\n", x = y); renvoie

}
Machine Translated by Google

HEURE 7
Travailler avec des boucles
Le ciel et la terre:
Sutra inouï chant répété…

—Proverbe zen

Dans les leçons précédentes, vous avez appris les bases du programme C, plusieurs
fonctions C importantes, les E/S standard et quelques opérateurs utiles. Dans cette
leçon, vous apprendrez une fonctionnalité très importante du langage C : le bouclage.
La boucle, également appelée itération, est utilisée en programmation pour exécuter le même
ensemble d'instructions encore et encore jusqu'à ce que certaines conditions spécifiées soient remplies.

Trois instructions en C sont conçues pour les boucles :

• L' instruction while

• L' instruction do­while

• L' instruction for

Les sections suivantes explorent ces déclarations.


Machine Translated by Google

106 Heure 7

La boucle while
Le but du mot­clé while est d'exécuter une instruction de manière répétée tant qu'une condition
donnée est vraie. Lorsque la condition de la boucle while n'est plus logiquement vraie, la boucle se
termine et l'exécution du programme reprend à l'instruction suivante suivant la boucle.

La forme générale de l' instruction while est

instruction while
(expression);

Ici , expression est la condition de l' instruction while . Cette expression est évaluée en premier. Si
l'expression est évaluée à une valeur différente de zéro , alors l' instruction est exécutée. Après cela,
l'expression est évaluée une fois de plus. L'instruction est ensuite exécutée une fois de plus si
l'expression est toujours évaluée à une valeur différente de zéro. Ce processus est répété encore et
encore jusqu'à ce que l' expression soit évaluée à zéro ou fausse logique.

L'idée est que le code à l'intérieur de la boucle (instruction; ci­dessus) finira par rendre l'
expression logiquement fausse la prochaine fois qu'elle sera évaluée, mettant ainsi fin à la boucle.

Bien sûr, vous souhaitez souvent utiliser un mot­clé while pour contrôler la boucle sur plusieurs
instructions. Lorsque c'est le cas, utilisez un bloc d'instructions entouré d'accolades { et }. Chaque fois
que l' expression while est évaluée, le bloc d'instructions entier sera exécuté si l'expression est évaluée
comme vraie.

Maintenant, regardons un exemple d'utilisation de l' instruction while . Le programme du listing 7.1
utilise une boucle while pour lire continuellement, puis afficher, l'entrée de caractères tant que l'entrée
de caractères n'est pas égale à 'x'.

TAPER LISTE 7.1 Utilisation d'une boucle while

1 : /* 07L01.c : Utilisation d'une boucle while */


2 : #include <stdio.h> 3 : 4 : main() 5 : { 6 :

entier c ;
7:
8: c = ' ';
9: printf("Entrez un caractère :\n(entrez x pour quitter)\n"); tandis
10 : que (c != 'x') { c = getc(stdin); putchar(c);
11 :
12 :
13 :
14 : } printf("\nSortie de la boucle while. Au revoir !\n");
15 : renvoie 0 ;
16 : }
Machine Translated by Google

Travailler avec des boucles 107

Ce qui suit est une copie de la sortie de l'écran de mon ordinateur. (Notez que les caractères que j'ai
saisis sont en gras.)

Entrez un caractère : (entrez x


SORTIR pour quitter)
H
H
je

je

X
X
7
Hors de la boucle while. Au revoir!

Comme vous pouvez le voir dans la sortie, le programme réimprime chaque caractère
UNE ANALYSE
saisi, puis s'arrête après x.

La ligne 8 met la variable c à la valeur ' ' (un espace). C'est ce qu'on appelle l' initialisation de
la variable, et nous avons juste besoin de l'initialiser à autre chose que 'x'.

La ligne 10 est l' instruction while . La condition entre parenthèses, c != 'x', signifie que la boucle
continuera à s'exécuter encore et encore jusqu'à ce que c soit réellement égal à 'x'. Comme nous
' , la
venions d'initialiser c pour être égal à ' Après larelation c != xfermante
parenthèse est bien se
sûrtrouve
vraie. une accolade ouvrante,
la boucle s'exécutera jusqu'à ce qu'une accolade fermante soit rencontrée.

Les lignes 11 et 12 lisent un caractère et l'impriment à nouveau, et ce faisant, attribuent la valeur


du caractère à la variable c. La ligne 13 est l'accolade fermante, donc la boucle est terminée et
l'exécution revient à la ligne 10, l' instruction while . Si le caractère qui a été tapé est autre chose que
"x", la boucle se poursuivra ; sinon, c != x sera logiquement faux et l'exécution passe à l'instruction
suivante après l'accolade fermante à la ligne 13. Dans ce cas, elle passe à l' appel printf() à la ligne 14.

La boucle do­while
Dans l' instruction while que nous avons vue, l'expression conditionnelle est définie tout en haut de la
boucle. Cependant, dans cette section, vous allez voir une autre instruction utilisée pour la boucle,
do­while, qui place l'expression au bas de la boucle. De cette manière, les instructions de la boucle
sont garanties d'être exécutées au moins une fois avant que l'expression ne soit testée. Notez que les
instructions d'une boucle while ne sont pas du tout exécutées si l'expression conditionnelle est évaluée
à zéro la première fois.
Machine Translated by Google

108 Heure 7

La forme générale de l' instruction do­while est

faire
{ instruction1 ;
instruction2 ;
.
.
.
} tandis que (expression);

Ici, les instructions à l'intérieur du bloc d'instructions sont exécutées une fois, puis l' expression est
évaluée afin de déterminer si la boucle doit continuer. Si l'expression donne une valeur différente de
zéro, la boucle do­ while continue ; sinon, la boucle s'arrête et l'exécution passe à l'instruction suivante
suivant la boucle.

Notez que l' instruction do­while se termine par un point­virgule, ce qui constitue une distinction
importante par rapport aux instructions if et while .

Le programme du Listing 7.2 affiche les caractères A à G en utilisant une boucle do­ while pour répéter
l'impression et l'ajout.

TAPER LISTE 7.2 Utilisation d'une boucle do­while

1 : /* 07L02.c : Utilisation d'une boucle do­while */ 2 : #include


<stdio.h> 3 : 4 : main() 5 : { 6 : 7 :

int je ;

je = 65 ;
do
{ printf("La valeur numérique de %c est %d.\n", i, i); je++ ; } tandis que (i<72);
8 : 9 : 10 : 11 : renvoie 0 ;
12 :
13 :
14 : }

Après avoir exécuté l'exécutable 07L02.exe du Listing 7.6, j'ai les caractères A à G, ainsi que leurs
valeurs numériques, affichés à l'écran comme suit :
La valeur numérique de A est 65.
SORTIR
La valeur numérique de B est 66.
La valeur numérique de C est 67.
La valeur numérique de D est 68.
La valeur numérique de E est 69.
La valeur numérique de F est 70.
La valeur numérique de G est 71.
Machine Translated by Google

Travailler avec des boucles 109

UNE ANALYSE
L'instruction de la ligne 8 du Listing 7.6 initialise la variable entière i avec 65.
La variable entière a été déclarée à la ligne 6.

Les lignes 9 à 12 contiennent la boucle do­ while. L'expression i<72 se trouve au bas de la boucle de
la ligne 12. Lorsque la boucle démarre pour la première fois, les deux instructions des lignes 10 et 11
sont exécutées avant que l'expression ne soit évaluée. Comme la variable entière i contient la valeur
initiale de 65, la fonction printf() de la ligne 10 affiche la valeur numérique ainsi que le caractère A
correspondant à l'écran.
7
Après que la variable entière i est augmentée de 1 à la ligne 11, le contrôle du programme atteint le
bas de la boucle do­ while. Ensuite, l'expression i<72 est évaluée. Si la relation dans l'expression est
toujours valable, le contrôle du programme saute au sommet de la boucle do­ while, puis le processus
est répété. Lorsque l'expression est évaluée à 0 après que i est augmenté à 72 (i est alors égal à 72
et n'est donc pas inférieur à 72), la boucle do­ while se termine immédiatement.

Boucle sous l' instruction for


La forme générale de l' instruction for est

pour (expression1; expression2; expression3) {


déclaration;
}
ou alors

for (expression1; expression2; expression3) { instruction1;


instruction2 ;

.
.
.
}

Vous voyez dans cet exemple que l' instruction for utilise trois expressions (expression1, expression2
et expression3) séparées par des points­virgules.

Une boucle for peut contrôler une seule instruction comme dans le premier exemple, ou plusieurs
instructions, telles que instruction1 et instruction2, placées entre accolades ({ et }).

La première fois que l' instruction for est exécutée, elle évalue d'abord expression1, qui est généralement
utilisée pour initialiser une ou plusieurs variables.

La deuxième expression, expression2, agit de la même manière que l'expression


conditionnelle d'une boucle do ou do­ while. Cette deuxième expression est évaluée immédiatement
après expression1, puis plus tard est à nouveau évaluée après chaque bouclage réussi par le
Machine Translated by Google

110 Heure 7

pour déclaration. Si expression2 donne une valeur différente de zéro (vrai logique), les instructions
entre accolades sont exécutées. Sinon, la boucle est arrêtée et l'exécution reprend à l'instruction
suivante après la boucle.

La troisième expression de l' instruction for , expression3, n'est pas évaluée lorsque l' instruction
for est rencontrée pour la première fois. Cependant, expression3 est évaluée après chaque boucle et
avant que l'instruction ne revienne tester à nouveau expression2 .

Dans l'Heure 5, « Gestion des entrées et sorties standard », vous avez vu un exemple (Liste 5.5) qui
convertit les nombres décimaux de 0 à 15 en nombres hexadécimaux. À l'époque, les conversions
devaient être écrites dans des déclarations séparées. Maintenant, avec l' instruction for , vous pouvez
réécrire le programme du Listing 5.5 de manière très efficace. Le Listing 7.3 montre la version réécrite
du programme.

TAPER LISTE 7.3 Conversion de 0 à 15 en nombres hexadécimaux

1 : /* 07L03.c : Conversion de 0 à 15 en nombres hexadécimaux */ 2 : #include <stdio.h> 3 : 4 : main()


5:{6:7:

int je ;

printf("Hex(majuscule) Hex(minuscule) Décimal\n"); for (i=0; i<16; i++){ printf(“%X

%X %d\n", je, je, je);


8 : 9 : 10 : 11 }:
12 : renvoie 0 ;
13 : }

Après avoir créé le fichier exécutable 07L03.exe, j'obtiens la sortie suivante en exécutant
07L03.exe. (La sortie est en fait la même que celle de 05L05.exe à l'heure 5.)

Hex (majuscule) Hex (minuscule) Décimal 0 1


SORTIR
0 0

1 1

2 2 2
3 3 3
4 4 4
5 5 5
6 6 6
7 7 7

8 8 8
9 9 9
UN 10
B un B 11
Machine Translated by Google

Travailler avec des boucles 111

C 12

ré CD 13

ET 14

F par f 15

UNE ANALYSE Maintenant, regardons le code de l'extrait 7.3. Comme vous le savez, la ligne 2 inclut le
fichier d'en­tête stdio.h pour la fonction printf() utilisée plus tard dans le programme.

Dans le corps de la fonction main() , l'instruction de la ligne 6 déclare une variable entière, i. La ligne 7
8 affiche le titre de la sortie à l'écran.

Les lignes 9 à 11 contiennent l' instruction for . Notez que la première expression de l' instruction for
est i = 0, qui est une expression d'affectation qui initialise la variable entière i à 0.

La deuxième expression de l' instruction for est i < 16, qui est une expression relationnelle.
Cette expression a une valeur différente de zéro (vrai) tant que la relation indiquée par l'opérateur
inférieur à (<) est vérifiée. Comme mentionné précédemment, la deuxième expression est évaluée
par l' instruction for à chaque fois après une boucle réussie. Si la valeur de i est inférieure à 16, ce
qui signifie que l'expression relationnelle reste vraie, l' instruction for démarrera une autre boucle.
Sinon, il s'arrêtera de boucler et sortira.

La troisième expression de l' instruction for est i++. Lorsque cette expression est évaluée, la variable
entière i est augmentée de 1. Ceci est fait après l'exécution de chaque instruction à l'intérieur du corps
de l' instruction for . Ici, peu importe que l'opérateur de post­incrémentation (i++) ou l'opérateur de pré­
incrémentation (++i) soit utilisé dans la troisième expression.

En d'autres termes, lorsque la boucle for est rencontrée pour la première fois, i est défini sur 0,
l'expression i<16 est évaluée et trouvée vraie, et par conséquent les instructions dans le corps de la
boucle for sont exécutées. Après l'exécution de la boucle for , la troisième expression i++ est exécutée
en incrémentant i à 1, et i<16 est à nouveau évalué et trouvé vrai, ainsi le corps de la boucle est exécuté
à nouveau. Le bouclage dure jusqu'à ce que l'expression conditionnelle i<16 ne soit plus vraie.

Il n'y a qu'une seule instruction dans le corps de l'instruction for , comme vous pouvez le voir à la ligne
10. L'instruction contient la fonction printf() , qui est utilisée pour afficher les nombres hexadécimaux
(majuscules et minuscules) convertis à partir des valeurs décimales à l'aide de la spécificateurs de
format, %X et %x.

La valeur décimale est fournie par la variable entière i. Comme expliqué précédemment, i contient la
valeur initiale de 0 juste avant et pendant le premier bouclage. Après chaque boucle, i est augmenté
de 1 à cause de la troisième expression, i++, dans l' instruction for . La dernière valeur fournie par i
est 15. Lorsque i atteint 16, la relation indiquée par la deuxième expression,
Machine Translated by Google

112 Heure 7

i<16, n'est plus vrai. Par conséquent, la boucle est arrêtée et l'exécution de l' instruction for est
terminée.

Ensuite, l'instruction de la ligne 12 renvoie 0 pour indiquer une fin normale du programme, et
enfin, la fonction main() se termine et renvoie le contrôle au système d'exploitation.

Comme vous le voyez, avec l' instruction for , vous pouvez écrire un programme très concis. En fait,
le programme du Listing 7.3 est plus court de plus de 10 lignes que celui du Listing 5.5, bien que les deux
programmes finissent par faire exactement la même chose.

En fait, vous pouvez rendre le programme du Listing 7.3 encore plus court en supprimant les accolades
({ et }) puisqu'il n'y a qu'une seule instruction à l'intérieur du bloc d'instructions.

La déclaration nulle
Comme vous pouvez le remarquer, l' instruction for ne se termine pas par un point­virgule. L' instruction
for contient soit un bloc d'instructions qui se termine par l'accolade fermante (}), soit une seule instruction
qui se termine par un point­virgule. L' instruction for suivante contient un seul
déclaration:

pour (i=0; i<8; i++)


somme += i;

Notez que les accolades ({ et }) sont supprimées car l' instruction for ne contient qu'une seule
déclaration.

Considérons maintenant une déclaration comme celle­ci :

pour (i=0; i<8; i++);

Ici, l' instruction for est immédiatement suivie d'un point­virgule.

Dans le langage C, il existe une instruction spéciale appelée instruction nulle. Une instruction nulle ne
contient rien d'autre qu'un point­virgule. En d'autres termes, une instruction nulle est une instruction sans
expression.

Par conséquent, lorsque vous examinez l'instruction for (i=0; i<8; i++);, vous pouvez voir qu'il s'agit en fait
d'une instruction for avec une instruction nulle. En d'autres termes, vous pouvez le réécrire comme

pour (i=0; i<8; i++)


;

Étant donné que l'instruction null n'a pas d'expression, l' instruction for ne fait en réalité rien d'autre
qu'une boucle. Vous verrez quelques exemples utilisant l'instruction null avec l' instruction for plus loin
dans le livre.
Machine Translated by Google

Travailler avec des boucles 113

Étant donné que l'instruction null est parfaitement légale en C, vous devez faire attention
à placer des points­virgules dans vos instructions for. Par exemple, supposons que vous
ayez l'intention d'écrire une boucle for comme ceci : for (i=0; i<8; i++) sum += i;

Si vous mettez accidentellement un point­virgule à la fin de l'instruction for comme celle­ci,


cependant,
pour (i=0; i<8; i++);
7
somme += je ;

votre compilateur C l'acceptera toujours, mais les résultats des deux instructions for
seront assez différents. (Voir l'exercice 1 dans cette leçon pour un exemple.)

N'oubliez pas que la boucle do­ while est la seule instruction en boucle qui utilise un point­virgule
immédiatement après dans sa syntaxe. Les instructions while et for sont immédiatement suivies
d'une boucle, qui peut être une seule instruction suivie d'un point­virgule, un bloc d'instructions sans
point­virgule ou juste un point­virgule (instruction nulle) seul.

Utilisation d'expressions complexes dans une instruction for


Le langage C vous permet d'utiliser l'opérateur virgule pour combiner plusieurs expressions dans les
trois parties de l' instruction for .

Par exemple, la forme suivante est valide en C :

for (i=0, j=10; i!=j; i++, j­­){ /* bloc


d'instructions */
}

Ici, dans la première expression, les deux variables entières i et j sont initialisées, respectivement, avec 0
et 10 lorsque l' instruction for est rencontrée pour la première fois. Ensuite, dans le deuxième champ, les
expressions relationnelles i!=j sont évaluées et testées. S'il est évalué à zéro (faux), la boucle est terminée.
Après chaque itération de la boucle, i est augmenté de 1 et j est réduit de 1 dans la troisième expression.
Ensuite, l'expression i!=j est évaluée pour déterminer s'il faut ou non exécuter à nouveau la boucle.

Maintenant, regardons un vrai programme. Le Listing 7.4 montre un exemple d'utilisation de


plusieurs expressions dans l' instruction for .
Machine Translated by Google

114 Heure 7

TAPER LISTE 7.4 Ajout d'expressions multiples à l' instruction for

1 : /* 07L04.c : plusieurs expressions */ 2 : #include


<stdio.h> 3 : 4 : main() 5 : { 6 :

int je, j ;
7:
8: for (i=0, j=8; i<8; i++, j­­) printf(“%d +
9: %d = %d\n”, i, j, i+j); renvoie 0 ;
10 :
11 : }

J'obtiens la sortie suivante affichée à l'écran après avoir exécuté le fichier exécutable,
07L04.exe :
0+8=81+7=
SORTIR 82+6=83+
5=84+4=85
+3=86+2=8
7+1=8

Dans le Listing 7.4, la ligne 6 déclare deux variables entières, i et j, qui sont utilisées dans une
UNE ANALYSE
boucle for .

A la ligne 8, i est initialisé avec 0 et j est mis à 8 dans la première expression de l' instruction for . La
deuxième expression contient une condition, i < 8, qui indique à l'ordinateur de continuer à boucler
tant que la valeur de i est inférieure à 8.

Chaque fois, après l'exécution de l'instruction contrôlée par for à la ligne 9, la troisième expression
est évaluée, ce qui fait que i est augmenté (incrémenté) de 1 tandis que j est réduit (décrémenté) de
1. Parce qu'il n'y a qu'une seule instruction à l'intérieur de for boucle, aucune accolade ({ et }) n'est
utilisée pour former un bloc d'instructions.

L'instruction de la ligne 9 affiche l'addition de i et j à l'écran pendant la boucle, qui produit huit résultats
pendant la boucle en ajoutant les valeurs des deux variables, i et j.

L'ajout de plusieurs expressions dans l' instruction for est un moyen très pratique de manipuler plus
d'une variable dans une boucle. Pour en savoir plus sur l'utilisation de plusieurs expressions dans une
boucle for , regardez l'exemple du Listing 7.5.
Machine Translated by Google

Travailler avec des boucles 115

LISTE 7.5 Un autre exemple d'utilisation de plusieurs expressions dans l' instruction for
TAPER

1 : /* 07L05.c : un autre exemple d'expressions multiples */ 2 : #include


<stdio.h> 3 : 4 : main() 5 : { 6 :

int je, j ;
7:
8:
7
for (i=0, j=1; i<8; i++, j++) printf(“%d ­
9: %d = %d\n”, j, i, j return 0; ­ je);
10 :
11 : }

La sortie suivante s'affiche à l'écran après l'exécution de l'exécutable 07L05.exe sur ma machine :

1­0=121=1
SORTIR 3 ­ 2­ = 114­ ­43==
1 5 66 ­=51=81­ 77 ­
=1

Dans le programme du Listing 7.5, deux variables entières, i et j, sont déclarées à la ligne 6.
UNE ANALYSE

Notez qu'à la ligne 8, il y a deux expressions d'affectation, i=0 et j=1, dans la première expression de l'
instruction for . Ces deux expressions d'affectation initialisent respectivement les variables entières i et
j.

Il y a une expression relationnelle, i<8, dans le deuxième champ, qui est la condition qui doit être
remplie avant que le bouclage puisse être effectué. Parce que i commence à 0 et est incrémenté de
1 après chaque boucle, il y a un total de 8 boucles qui seront exécutées par le for
déclaration.

La troisième expression contient deux expressions, i++ et j++, qui augmentent les deux variables
entières de 1 à chaque fois après l'exécution de l'instruction de la ligne 9.

La fonction printf() de la ligne 9 affiche la soustraction des deux variables entières, j et i, dans la
boucle for . Comme il n'y a qu'une seule instruction dans le bloc d'instructions, les accolades ({ et })
ne sont pas nécessaires.
Machine Translated by Google

116 Heure 7

Utilisation de boucles imbriquées


Il est souvent nécessaire de créer une boucle même lorsque vous êtes déjà dans une boucle. Vous pouvez mettre une
boucle (une boucle interne) à l'intérieur d'une autre (une boucle externe) pour créer des boucles imbriquées. Lorsque
le programme atteint une boucle interne, il s'exécute comme n'importe quelle autre instruction à l'intérieur de la boucle
externe.

Le Listing 7.6 est un exemple du fonctionnement des boucles imbriquées.

TAPER LISTE 7.6 Utilisation de boucles imbriquées

1 : /* 07L06.c : démonstration de boucles imbriquées */


2 : #include <stdio.h> 3 : 4 : main() 5 : { 6 :

int je, j ;
7:
8: pour (je=1; je<=3; je++) { /* boucle externe */
9: printf("Le début de l'itération %d de la boucle externe.\n", i); for (j=1; j<=4; j+
10 : +) /* boucle interne */ printf(“
11 : Itération %d de la boucle interne.\n”, j); printf("La
12 : fin de l'itération %d de la boucle externe.\n", i);
13 :
14 : } renvoie 0 ;
15 : }

Le résultat suivant est obtenu en lançant le fichier exécutable 07L06.exe :

Le début de l'itération 1 de la boucle externe.


SORTIR Itération 1 de la boucle interne.
Itération 2 de la boucle interne.
Itération 3 de la boucle interne.
Itération 4 de la boucle interne.
La fin de l'itération 1 de la boucle externe.
Le début de l'itération 2 de la boucle externe.
Itération 1 de la boucle interne.
Itération 2 de la boucle interne.
Itération 3 de la boucle interne.
Itération 4 de la boucle interne.
La fin de l'itération 2 de la boucle externe.
Le début de l'itération 3 de la boucle externe.
Itération 1 de la boucle interne.
Itération 2 de la boucle interne.
Itération 3 de la boucle interne.
Itération 4 de la boucle interne.
La fin de l'itération 3 de la boucle externe.
Machine Translated by Google

Travailler avec des boucles 117

UNE ANALYSE
Dans le Listing 7.6, deux boucles for sont imbriquées. La boucle for externe commence à la ligne
8 et se termine à la ligne 13, tandis que la boucle for interne commence à la ligne 10 et se termine à
la ligne 11.

La boucle interne est une seule instruction qui imprime le numéro d'itération en fonction de la valeur numérique
de la variable entière j. Comme vous le voyez à la ligne 10, j est initialisé avec 1, et est augmenté de 1 après
chaque bouclage (c'est­à­dire, itération). L'exécution de la boucle interne s'arrête lorsque la valeur de j est
supérieure à 4.
7
Outre la boucle interne, la boucle externe contient deux instructions aux lignes 9 et 12, respectivement.
La fonction printf() à la ligne 9 affiche un message indiquant le début d'une itération à partir de la boucle
externe. Un message de fin est envoyé à la ligne 12 pour montrer la fin de l'itération à partir de la boucle externe.

À partir de la sortie, vous pouvez voir que la boucle interne est terminée avant que la boucle externe ne
commence une autre itération. Lorsque la boucle externe commence une autre itération, la boucle interne est
rencontrée et exécutée à nouveau. La sortie du programme du Listing 7.6 montre clairement les ordres
d'exécution des boucles internes et externes.

Ne confondez pas les deux opérateurs relationnels (< et <=) et abusez­en dans
les expressions de boucles.
Par exemple, ce qui suit for
(j=1; j<10; j++){ /* bloc
d'instructions */
}

signifie que si j est inférieur à 10, continuez à boucler. Ainsi, le nombre total
d'itérations est de 9. Cependant, dans l'exemple suivant, pour (j=1 ; j<=10 ; j++){

/* bloc d'instructions */
}

le nombre total d'itérations est de 10 car l'expression relationnelle j<=10 est évaluée
dans ce cas. Notez que l'expression est évaluée à 1 (vrai logique) tant que j est
inférieur ou égal à 10.
Par conséquent, vous voyez que la différence entre les opérateurs < et <= fait
que la boucle dans le premier exemple est une itération plus courte que la boucle
dans le deuxième exemple.
Machine Translated by Google

118 Heure 7

Résumé
Dans cette leçon, vous avez appris les concepts et énoncés importants suivants :

• La boucle peut être utilisée pour exécuter le même ensemble d'instructions encore et encore jusqu'à ce que
conditions spécifiées sont remplies.

• La boucle rend votre programme plus concis. • Il y a

trois instructions, while, et do­while, et for, qui sont utilisées pour la boucle
en C.

• L' instruction while contient une expression, qui est l'expression conditionnelle qui contrôle la boucle.

• L' instruction while ne se termine pas par un point­virgule.

• L' instruction do­while place son expression conditionnelle au bas de la boucle.


• L' instruction do­while se termine par un point­virgule.

• Il y a trois expressions dans l' instruction for . La deuxième expression est l'expression conditionnelle.

• L' instruction for ne se termine pas par un point­virgule.

• Plusieurs expressions, combinées via des virgules, peuvent être utilisées comme une seule expression dans le
pour déclaration.

• Dans une boucle imbriquée, la boucle interne se termine avant que la boucle externe ne reprenne son itération dans

boucles imbriquées.

Dans la leçon suivante, vous découvrirez d'autres opérateurs utilisés dans le langage C.

Questions et réponses

Q Quelle est la différence entre les instructions while et do­while ?

A La principale différence est que dans l' instruction while , l'expression conditionnelle est évaluée en
haut de la boucle, tandis que dans l' instruction do­while , l'expression conditionnelle est évaluée en
bas de la boucle. Par conséquent, les instructions contrôlées par l' instruction do­while sont garanties
d'être exécutées au moins une fois alors que la boucle d'une instruction while peut ne jamais être
exécutée du tout.

Q Comment fonctionne une boucle for ?

A Il y a trois expressions dans l' instruction for . Le premier champ contient une initiale
izer qui est évalué en premier et une seule fois avant l'itération. La deuxième expression est l'expression
conditionnelle qui doit être évaluée à une valeur différente de zéro (vrai logique) avant que les
instructions contrôlées par l' instruction for ne soient exécutées. Si le conditionnel
Machine Translated by Google

Travailler avec des boucles 119

expression prend une valeur différente de zéro (vrai), ce qui signifie que la condition spécifiée est
remplie, une itération de la boucle for est effectuée. Après chaque itération, la troisième expression
est évaluée, puis le deuxième champ est à nouveau évalué. Ce processus avec les deuxième et
troisième expressions est répété jusqu'à ce que l'expression conditionnelle soit évaluée à zéro
(faux logique).

Q L' instruction while peut­elle se terminer par un point­virgule ?

R Par définition, l' instruction while ne se termine pas par un point­virgule. Cependant, il est légal
en C de mettre un point­virgule juste après l' instruction while comme ceci : while(expression);,
7
ce qui signifie qu'il y a une instruction nulle contrôlée par l' instruction while . N'oubliez pas que
le résultat sera très différent de ce à quoi vous vous attendiez si vous mettez accidentellement
un point­virgule à la fin de l' instruction while .

Q Si deux boucles sont imbriquées, laquelle doit finir en premier, la boucle intérieure ou
la boucle externe ?

A L'intérieur doit finir en premier. Ensuite, la boucle externe continuera jusqu'à la fin, puis
commencera une autre itération si sa condition spécifiée est toujours remplie.

Atelier
Pour vous aider à consolider votre compréhension de la leçon de cette heure, nous vous encourageons
à essayer de répondre aux questions du quiz et à terminer les exercices fournis dans l'atelier avant de
passer à la leçon suivante. Les réponses et les conseils aux questions et aux exercices sont donnés à
l'annexe D, « Réponses aux quiz et aux exercices ».

Questionnaire

1. La boucle while suivante peut­elle afficher quelque chose ?


entier k = 100 ; tandis que (k<100){ printf("%c", k); k++ ;

2. La boucle do­while suivante peut­elle imprimer quelque chose ?


entier k = 100 ;
faire
{ printf("%c", k); k+
+ ; } tandis que
(k<100);

3. Les deux boucles for suivantes ont­elles le même nombre d'itérations ?


pour (j=0; j<8; j++); pour
(k=1; k<=8; k++);
Machine Translated by Google

120 Heure 7

4. La boucle for suivante est­elle


for (j=65; j<72; j++) printf("%c", j);

équivalent à la boucle while suivante ? entier k =


65 ; tant que (k<72) printf("%c", k); k++ ;

Des exercices

1. Quelle est la différence entre les deux morceaux de code suivants ?


for (i=0, j=1; i<8; i++, j++) printf(“%d
+ %d = %d\n”, i, j, i+j);

pour (i=0, j=1; i<8; i++, j++); printf("%d


+ %d = %d\n", je, j, je+j);

2. Écrivez un programme contenant les deux morceaux de code présentés dans l'exercice 1, puis
exécutez le programme. Qu'allez­vous voir à l'écran ?

3. Réécrivez le programme du Listing 7.1. Cette fois, vous voulez que l' instruction while continue de
tourner en boucle jusqu'à ce que l'utilisateur entre le caractère K.

4. Réécrivez le programme présenté dans le Listing 7.2 en remplaçant la boucle do­ while par un
pour la boucle.

5. Réécrivez le programme du Listing 7.6. Cette fois, utilisez une boucle while comme boucle externe et
une boucle do­ while comme boucle interne.
Machine Translated by Google

HEURE 8

Utilisation du conditionnel
Les opérateurs
La civilisation progresse en augmentant le nombre d'opérations importantes que nous
pouvons effectuer sans y penser.

—AN Whitehead

Au cours de l'heure 6, "Manipuler des données", vous avez découvert certains opérateurs
importants en C, tels que les opérateurs d'affectation arithmétique, l'opérateur moins unaire,
les opérateurs d'incrémentation et de décrémentation et les opérateurs relationnels. Dans
cette leçon, vous apprendrez plus d'opérateurs qui sont très importants dans la
programmation C, y compris

• L' opérateur sizeof • Les

opérateurs logiques • Les

opérateurs de manipulation de bits

• L'opérateur conditionnel
Machine Translated by Google

122 Heure 8

Mesurer la taille des données


Vous vous souvenez peut­être qu'à l'heure 4, "Comprendre les types de données et les mots­clés", j'ai
mentionné que chaque type de données a sa propre taille. Selon le système d'exploitation et le compilateur C
que vous utilisez, la taille d'un type de données varie. Par exemple, sur la plupart des stations de travail UNIX,
un entier a une longueur de 32 bits, alors que la plupart des compilateurs C ne prennent en charge que les
entiers de 16 bits sur une machine DOS.

Alors, comment connaître la taille d'un type de données sur votre machine ? La réponse est que vous pouvez
mesurer la taille du type de données en utilisant l' opérateur sizeof fourni par C.

La forme générale de l' opérateur sizeof est

taillede (expression)

Ici , expression est le type de données ou la variable dont la taille est mesurée par l' opérateur sizeof . L'
opérateur sizeof évalue la taille, en octets, de son opérande. L'opérande de l' opérateur sizeof peut être un mot­
clé du langage C désignant un type de données (comme int, char ou float), ou il peut s'agir d'une expression
faisant référence à un type de données dont la taille peut être déterminée (comme une constante ou le nom
d'une variable).

Les parenthèses sont facultatives dans la forme générale de l'opérateur. Si l'expression n'est pas un mot­clé C
pour un type de données, les parenthèses peuvent être ignorées. Par exemple, la déclaration suivante :

taille = taillede(entier);

Place la taille, en octets, du type de données int dans une variable nommée size. Le programme du Listing 8.1
trouve les tailles des types de données char, int, float et double sur ma machine.

TAPER LISTE 8.1 Utilisation de la taille de l' opérateur

1 : /* 08L01.c : Utilisation de l'opérateur sizeof */


2 : #include <stdio.h> 3 : 4 : main() 5 : { 6 :

char ch = ' '; entier


entier_num
float= 0flt_num
; =
0.0f ; double dbl_num = 0.0 ;

printf("La taille de char est : %d­byte\n", sizeof(char)); printf("La taille


de ch est : %d­byte\n", sizeof ch ); printf("La taille de int est : %d­
byte\n", sizeof(int)); printf("La taille de int_num est : %d­byte\n", sizeof
7 : 8 : 9 : 10 :int_num);
11 : 12 : 13 : 14 :
Machine Translated by Google

Utilisation d'opérateurs conditionnels 123

15 : printf("La taille de float est : %d­byte\n", sizeof(float)); printf("La taille


16 : de flt_num est : %d­byte\n", sizeof flt_num); printf("La taille de double est :
17 : %d­byte\n", sizeof(double)); printf("La taille de dbl_num est : %d­byte\n", 8
18 : sizeof dbl_num); renvoie 0 ;
19 :
20 : }

Une fois ce programme compilé et lié, un fichier exécutable, 08L01.exe, est créé. Voici la sortie
imprimée à l'écran après l'exécution de l'exécutable sur ma machine :

La taille de char est : 1 octet


SORTIR La taille de ch est : 1 octet
La taille de int est : 2 octets
La taille de int_num est : 2 octets
La taille du flottant est : 4 octets
La taille de flt_num est : 4 octets
La taille de double est : 8 octets

La taille de dbl_num est : 8­byte[ic:analysis]La ligne 2 du Listing 8.1 inclut le fichier d'en­tête stdio.h
pour la fonction printf() utilisée dans les instructions à l'intérieur du corps de la fonction main() . Les
lignes 6 à 9 déclarent respectivement une variable char (ch), une variable int (int_num), une variable
float (flt_num) et une variable double (dbl_num) . De plus, ces quatre variables sont initialisées. Notez
qu'à la ligne 8, la valeur initiale de flt_num est suffixée par f pour spécifier float. (Comme vous l'avez
appris à l'heure 4, vous pouvez utiliser f ou F pour spécifier le type flottant d'un nombre à virgule
flottante.)

Les lignes 11 et 12 affichent la taille du type de données char , ainsi que la variable char ch.
Notez que l' opérateur sizeof est utilisé à la fois dans la ligne 11 et la ligne 12 pour obtenir le nombre
d'octets que le type de données char ou la variable ch peut avoir. Comme la variable ch n'est pas un
mot­clé en C, les parenthèses sont ignorées pour l' opérateur sizeof à la ligne 12.

Les deux premières lignes de la sortie sont imprimées par les deux instructions des lignes 11 et 12,
respectivement. À partir de la sortie, vous voyez que la taille du type de données char est de 1 octet,
ce qui est identique à la taille de la variable ch. Ce n'est pas surprenant car la variable ch est déclarée
comme la variable char .

De même, les lignes 13 et 14 affichent les tailles du type de données int et de la variable int int_num
en utilisant l' opérateur sizeof . Vous voyez que la taille de chacun est de 2 octets.

De plus, en utilisant l' opérateur sizeof , les lignes 15 à 18 donnent respectivement les tailles du type de
données flottant , de la variable flottante flt_num, du type de données double et de la variable double
dbl_num . Les résultats dans la section de sortie montrent que le type de données float et la variable
flt_num ont la même taille (4 octets). Les tailles du type de données double et de la variable dbl_num
sont toutes deux de 8 octets.
Machine Translated by Google

124 Heure 8

Tout Est Logique


Il est maintenant temps de découvrir un nouvel ensemble d'opérateurs : les opérateurs logiques.

Il existe trois opérateurs logiques dans le langage C :

&& L'opérateur logique ET

|| L'opérateur logique OU

! L'opérateur NÉGATION logique

Les deux premiers, les opérateurs AND et OR, sont des opérateurs binaires ; c'est­à­dire qu'ils prennent
tous les deux deux opérandes (un à gauche et un à droite de l'opérateur). L'opérateur logique ET (&&)
est utilisé pour évaluer la vérité ou la fausseté d'une paire d'expressions. Si l'une ou l'autre des
expressions est évaluée à 0 (c'est­à­dire, logiquement faux), l'opérateur donne une valeur de 0.
Sinon, si ­ et seulement si ­ les deux expressions d'opérande donnent des valeurs non nulles, l'opérateur
logique ET donne la valeur 1 (logiquement vrai).

L'opérateur logique OR (||) donne la valeur 1 chaque fois qu'une ou les deux expressions d'opérande
ont une valeur différente de zéro (logiquement vraie). Le || L'opérateur renvoie 0 uniquement si les deux
expressions d'opérande ont la valeur 0 (faux). L'opérateur de négation logique (!) est un opérateur
unaire ; c'est­à­dire qu'il ne prend qu'un seul opérande (l'expression à sa droite). Si l'opérande est
évalué à une valeur différente de zéro, le ! l'opérateur donne 0 (logiquement faux) ; ce n'est que lorsque
l'expression de l'opérande est évaluée à 0 que l'opérateur donne 1 (logiquement vrai).

Les trois sections suivantes contiennent des exemples qui vous montrent comment utiliser les trois
opérateurs logiques.

L'opérateur ET logique (&&)


Un format général de l'opérateur logique ET est :

exp1 && exp2

où exp1 et exp2 sont deux expressions d'opérandes évaluées par l'opérateur AND.

Une bonne façon de comprendre l'opérateur AND est de consulter un tableau qui montre les valeurs
fournies par l'opérateur AND en fonction des valeurs possibles de exp1 et exp2. Voir le tableau 8.1, qui
peut être appelé la table de vérité de l'opérateur ET.

TABLEAU 8.1 Les valeurs renvoyées par l'opérateur AND


exp1 exp2 && Rendements

non nul non nul 1

non nul 0 0

non nul 0

00 0
Machine Translated by Google

Utilisation d'opérateurs conditionnels 125

Le Listing 8.2 est un exemple d'utilisation de l'opérateur logique ET (&&).

TAPER
8
LISTE 8.2 Utilisation de l'opérateur logique ET (&&)

1 : /* 08L02.c : Utilisation de l'opérateur logique AND */


2 : #include <stdio.h> 3 : 4 : main() 5 : { 6 : 7 :

int si;

nombre =
0 ; printf("L'opérateur ET donne : %d\n", (num%2
== 0) && (num%3 == 0)); nombre = 2 ;
8 : 9 : 10 : 11printf("L'opérateur
: ET donne : %d\n", (num%2 ==
12 : 0) && (num%3 == 0)); nombre = 3 ; printf("L'opérateur
13: ET donne : %d\n", (num%2 == 0) &&
14: (num%3 == 0)); nombre = 6 ; printf("L'opérateur ET
donne : %d\n", (num%2 == 0) && (num%3 == 0));

15 : 16 : 17 :

18h19h20h21h
renvoie 0 ;
22 : }

Une fois ce programme compilé et lié, un fichier exécutable, 08L02.exe, est créé. La sortie suivante
s'affiche après l'exécution de l'exécutable sur ma machine :

L'opérateur ET donne : 1
SORTIR
L'opérateur ET donne : 0
L'opérateur ET donne : 0
L'opérateur ET donne : 1

Dans le Listing 8.2, une variable entière, num, est déclarée à la ligne 6 et initialisée pour la
UNE ANALYSE
première fois à la ligne 8. Les lignes 9 et 10 affichent la valeur obtenue par l'opérateur logique
AND dans l'expression suivante :

(num%2 == 0) && (num%3 == 0)

Ici, vous voyez deux expressions relationnelles, num%2 == 0 et num%3 == 0. Dans l'heure 3
"Apprentissage de la structure d'un programme C", vous avez appris que l'opérateur arithmétique %
peut être utilisé pour obtenir le reste après son premier opérande est divisé par le deuxième opérande.
Par conséquent, num%2 donne le reste de num divisé par 2. L'expression relationnelle num%2
== 0 donne 1 si le reste est égal à 0, c'est­à­dire que la valeur de num peut être complètement
divisée par 2 . De même, si la valeur de num peut être divisée par 3, la valeur relationnelle
Machine Translated by Google

126 Heure 8

expression num%3 == 0 donne également 1 . Ensuite, selon la table de vérité de l' opérateur &&
(voir Tableau 8.1), vous savez que la combinaison de l'opérateur logique ET (&&) et des deux expressions
relationnelles donne 1 si les deux expressions relationnelles sont toutes deux non nulles ; sinon, il donne
0.

Dans notre cas, lorsque num est initialisé à 0 à la ligne 8, 0%2 et 0%3 produisent des restes de zéro,
de sorte que les deux expressions relationnelles sont évaluées à 1. Par conséquent, l'opérateur
logique ET donne 1.

Cependant, lorsque num reçoit la valeur 2 ou 3 , comme indiqué aux lignes 11 et 14, l'opérateur
logique ET de la ligne 13 ou de la ligne 16 donne 0. La raison en est que 2 ou 3 ne peuvent pas être
divisés à la fois par 2 et 3 .

La ligne 17 attribue alors à num la valeur de 6. Comme 6 est un multiple de 2 et de 3, l'opérateur logique
ET de la ligne 19 donne 1 qui est affiché par la fonction printf() aux lignes 18 et 19.

L'opérateur logique OU (||)


Comme mentionné précédemment, l'opérateur logique OU donne 1 (logiquement vrai) si l'une ou les
deux expressions donnent une valeur différente de zéro. Le || L'opérateur donne 0 si (et seulement si)
les deux expressions donnent 0.

Un format général de l'opérateur logique OU est :

exp1 || exp2

où exp1 et exp2 sont deux expressions d'opérandes évaluées par l'opérateur OR.

Le tableau 8.2 est la table de vérité de l'opérateur OU.

TABLEAU 8.2 Les valeurs renvoyées par l'opérateur OR


exp1 exp2 || Rendements

non nul non nul 1

non nul 0 1

0 non nul 1

0 00

Le programme du Listing 8.3 montre comment utiliser l'opérateur logique OU (||).

TAPER LISTE 8.3 Utilisation de l'opérateur logique OU ||

1 : /* 08L03.c : Utilisation de l'opérateur logique OU */


2 : #include <stdio.h>
Machine Translated by Google

Utilisation d'opérateurs conditionnels 127

3 : 4 : principal()
5:{6:7:8: 8
9 : 10 : 11 :int si;
12 : 13 : }
printf("Entrez un seul chiffre qui peut être divisé\npar 2 et 3 :\n"); pour (num = 1; (num%2 !=
0) || (num%3 != 0); )
num = getchar() – '0' ;
printf("Vous avez un tel nombre : %d\n", num); renvoie

Voici la sortie affichée après l'exécution du fichier exécutable 08L03.exe sur ma machine. Les
chiffres en gras sont ceux que j'ai saisis. (La touche Entrée est enfoncée à chaque fois après la
saisie d'un des nombres.) Dans la plage de 0 à 9, 0 et 6 sont les deux seuls nombres qui peuvent
être complètement divisés par 2 et 3 :

Entrez un seul chiffre qui peut être divisé par 2 et


SORTIR 3:23456

Vous avez un tel nombre : 6 Dans le Listing 8.3, une variable entière, num, est déclarée à
UNE ANALYSE
la ligne 6. La ligne 8 du Listing 8.3 imprime deux titres demandant à l'utilisateur d'entrer un
seul chiffre.

A la ligne 9, la variable entière num est initialisée dans la première expression de l' instruction
for . La raison d'initialiser num avec 1 est que 1 est un nombre divisible
par ni 2 ni 3. De cette façon, la boucle for est garantie d'être exécutée au moins une fois.

La partie clé du programme du Listing 8.3 est l'expression logique dans l' instruction for :

(num%2 != 0) || (num%3 != 0)

Ici, les deux expressions relationnelles num%2 != 0 et num%3 != 0 sont évaluées.


Selon la table de vérité du || (voir Tableau 8.2), vous savez que si l'une des expressions
relationnelles prend la valeur non nulle, indiquant dans ce cas que la valeur de num ne peut pas
être complètement divisée par 2 ou 3, alors l'expression OU logique prend la valeur 1, ce qui permet
à la boucle for de continuer.

La boucle for ne s'arrête que si l'utilisateur saisit un chiffre qui peut être divisé à la fois par 2 et 3. En
d'autres termes, lorsque les deux expressions relationnelles sont évaluées à 0, l'opérateur logique
OR donne 0, ce qui provoque la fin de la boucle for . boucle.
Machine Translated by Google

128 Heure 8

L'opérateur de NÉGATION logique (!)


Le format général d'utilisation de l'opérateur logique NÉGATION est :

!expression

où expression est l'opérande de l'opérateur NÉGATION.

La table de vérité de l'opérateur NÉGATION est présentée dans le tableau 8.3.

TABLEAU 8.3 Les valeurs renvoyées par le ! Opérateur Valeur


expression renvoyée par !
non nul 0

0 1

Examinons maintenant l'exemple présenté dans le Listing 8.4, qui montre comment utiliser l'opérateur
de négation logique (!).

TAPER
LISTE 8.4 Utilisation de l'opérateur de négation logique (!)

1 : /* 08L04.c : Utilisation de l'opérateur de négation logique */


2 : #include <stdio.h> 3 : 4 : main() 5 : { 6 : 7 :

int si;

nombre =
7 ; printf("Num donné = 7\n");
printf(“!(num < 7) donne : %d\n”, !(num < 7)); printf(“!(num > 7)
8 : 9 : 10 : 11donne
: : %d\n”, !(num > 7)); printf(“!(num == 7) donne : %d\n”, !
12 : (num == 7)); renvoie 0 ;

13 : 14 : }

Le résultat suivant s'affiche en exécutant le fichier exécutable 08L04.exe :


Donné num = 7 !
SORTIR
(num < 7) renvoie : 1 !(num
> 7) renvoie : 1 !(num == 7)
renvoie : 0

UNE ANALYSE À la ligne 8, notez qu'une variable entière num est initialisée à 7, qui est ensuite affichée par
la fonction printf() à la ligne 9.
Machine Translated by Google

Utilisation d'opérateurs conditionnels 129

À la ligne 10, l'expression relationnelle num < 7 est évaluée à 0 car la valeur de num n'est pas inférieure à 7.
Cependant, en utilisant l'opérateur de négation logique, !(num < 7) donne 1.
(Reportez­vous à la table de vérité de l' opérateur ! présenté dans le tableau 8.3.)
8
De même, l'expression logique !(num > 7) donne 1 à la ligne 11.

Comme num a la valeur 7, l'expression relationnelle num == 7 donne 1 ; cependant, l'expression logique !(num == 7) à
la ligne 12 est évaluée à 0.

Manipuler des bits


Au cours des heures précédentes, vous avez appris que les données et les fichiers informatiques sont constitués
de bits. Dans cette section, vous découvrirez un ensemble d'opérateurs qui vous permettent d'accéder à des bits
spécifiques et de les manipuler. Mais avant d'aller plus loin, apprenons­en plus sur les nombres binaires et
hexadécimaux, et comment convertir un nombre décimal en sa représentation binaire ou hexadécimale.

Conversion de décimal en hexadécimal ou binaire


Comme je l'ai déjà mentionné, un bit est la plus petite unité de stockage du monde informatique. Un bit ne peut
contenir que les valeurs 0 et 1 (0 et 1 sont utilisés pour représenter les états d'arrêt et de marche des commutateurs
électroniques qui composent le processeur et la mémoire d'un ordinateur.) Chaque chiffre d'un nombre hexadécimal
se compose de 4 bits. Il est facile de convertir un nombre décimal en nombre hexadécimal ou binaire. Le tableau 8.4
montre les nombres hexadécimaux de 0 à F et leurs représentations binaires et décimales correspondantes.

TABLEAU 8.4 Nombres exprimés dans différents formats


Hexagone
Binaire Dé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

UN 1010 dix

continue
Machine Translated by Google

130 Heure 8

TABLEAU 8.4 suite

Hexagone
Binaire Décimal

B 1011 11

C 1100 12

ré 1101 13

ET 1110 14

F 1111 15

Voyons comment convertir un nombre décimal en nombre binaire ou hexadécimal, ou vice versa.
Comme vous le savez, le binaire est un système de numérotation basé sur 2. Chaque chiffre d'un nombre binaire
est appelé un bit et peut être 1 ou 0. Si la position d'un bit dans un nombre binaire est n, le bit peut avoir une valeur
de 0 ou 2 à la puissance n. La position d'un bit dans un nombre binaire est comptée à partir de la droite du nombre
binaire. Le bit le plus à droite est à la position zéro.
Ainsi, étant donné un nombre binaire 1000 (sa valeur hexadécimale est 8), nous pouvons calculer sa valeur décimale
comme ceci :
3
1000 → 1 * 23 + 0 * 22 + 0 * 21 + 0 * 20 → 2 → 8 (décimal)

Autrement dit, la valeur décimale du nombre binaire 1000 est 8.

De même, étant donné un nombre binaire 1110, sa valeur hexadécimale est E, vous pouvez calculer sa valeur
décimale comme ceci :
3
1110 → 1 * 23 + 1 * 22 + 1 * 21 + 0 * 20 → 2 → 14 (décimal)

En d'autres termes, la valeur décimale du nombre binaire 1110 est 14.

Si vous voulez convertir un nombre décimal, par exemple 10, en son homologue binaire, vous avez le processus
suivant :
3
10 → 2 + 21 → 1 * 23 + 0 * 22 + 1 * 21 + 0 * 20 → 1010 (binaire) ou A (hex)

De même, vous pouvez convertir le reste des nombres décimaux du tableau 8.4 en leurs homologues binaires, ou
vice versa.

Utilisation d'opérateurs au niveau du bit

Il existe six opérateurs de manipulation de bits dans le langage C :

Opérateur La description

& L'opérateur ET au niveau du bit

| L'opérateur OR au niveau du bit


^
L'opérateur OU exclusif au niveau du bit (XOR)
Machine Translated by Google

Utilisation d'opérateurs conditionnels 131

Opérateur La description

~ L'opérateur de complément au niveau du bit 8


>> L'opérateur de décalage à droite

<< L'opérateur de décalage à gauche

Cette section et la suivante donnent des explications et des exemples des opérateurs de manipulation de bits.

Les formes générales des opérateurs au niveau du bit sont les suivantes :

x & yx
| aa
^
X
~x

Ici x et y sont des opérandes.

L' opérateur & compare chaque bit de x au bit correspondant de y. Si les deux bits sont à 1, 1 est placé à la même
position du bit dans le résultat. Si l'un des bits ou les deux sont 0, 0 est placé dans le résultat.

Par exemple, l'expression avec deux opérandes binaires, 01 et 11, donne 01.

Le | place 1 dans le résultat si l'un ou l'autre des opérandes est 1. Par exemple, l'expression 01 | 11 donne 11. Le |
l'opérateur donne un bit 0 si ­ et seulement si ­ les deux bits d'opérande
sont 0.

L' opérateur ^ place 1 dans le résultat si exactement un opérande, mais pas les deux, vaut 1. Par conséquent, l'expression
01 ^ 11 donne 10.

Enfin, l' opérateur ~ ne prend qu'un seul opérande. Cet opérateur inverse chaque bit de l'opérande. Par exemple,
~01 donne 10.

Le tableau 8.5 montre d'autres exemples d'utilisation des opérateurs au niveau du bit dans les formats décimal, hexadécimal
et binaire (dans les trois colonnes de gauche). Les résultats correspondants, aux formats binaire, hexadécimal et décimal,
sont répertoriés dans les trois colonnes de droite. Les numéros hexadécimaux sont préfixés par 0x.

TABLEAU 8.5 Exemples utilisant des expressions d'opérateurs au niveau

du bit Résultats

Décimal hexadécimal Binaire Décimal Hex Binaire


12 & 10 0x0C & 0x0A 1100 & 1010 8 0x08 1000

12 | dix 0x0C | 0x0A 1100 | 1010 14 0x0E 1110

12 ^ 10 0x0C ^ 0x0A 1100 ^ 1010 6 0x06 0110

~12 ~0x000C ~0000000000001100 65523 FFF3 1111111111110011


Machine Translated by Google

132 Heure 8

Notez que la valeur complémentaire de 12 est 65 523 car le type de données entier non signé (16 bits) a le
nombre maximum 65 535. En d'autres termes, 65 523 est le résultat de la soustraction de 12 à 65 535. (Le
modificateur de données non signé est introduit dans l'heure 9, "Travailler avec les modificateurs de données
et les fonctions mathématiques".)

Le programme du Listing 8.5 illustre l'utilisation des opérateurs au niveau du bit.

TAPER LISTE 8.5 Utilisation des opérateurs au niveau du bit

1 : /* 08L05.c : Utilisation d'opérateurs au niveau du bit */


2 : #include <stdio.h> 3 : 4 : main() 5 : { 6 : 7 :

entier x, y, z ;

x = 4321 ; y
= 5678 ;
printf("Étant donné x = %u, c'est­à­dire 0X%04X\n", x, x); printf("
8 : 9 : 10 : 11y: = %u, c'est­à­dire 0X%04X\n",
renvoie : %6u, y, y);
c'est­à­dire
z = x & y0X%04X\n",
; printf("x & yz,
12 : z) ; z = x | y; printf("x | y renvoie : %6u, c'est­à­dire 0X%04X\n",
13: z, z) ;
14:

^
z=x y;
15 : 16 : 17 printf("x
: ^ y renvoie : %6u, c'est­à­dire 0X%04X\n", z, z) ;
18 : printf(" ~x renvoie : %6u, c'est­à­dire 0X%04X\n", ~x, ~x); renvoie 0 ;
19 :
20 : }

Une fois le fichier exécutable, 08L05.exe, créé et exécuté sur mon ordinateur, la sortie suivante s'affiche à
l'écran :

Étant donné x = 4321, c'est­à­dire


SORTIR
0X10E1 y = 5678, c'est­à­dire
0X162E x & y renvoie : 4128, c'est­à­dire 0X1020
x | y renvoie : 5871, c'est­à­dire 0X16EF y renvoie :
^
X 1743, c'est­à­dire 0X06CF ~x renvoie :
61214, c'est­à­dire 0XEF1E

Dans le Listing 8.5, trois variables entières, x, y et z, sont déclarées à la ligne 6. Les lignes 8 et 9
UNE ANALYSE
fixent x et y à 4321 et 5678, respectivement. Lignes 10 et 11 puis imprimez
les valeurs de x et y dans les formats décimal et hexadécimal. Les numéros hexadécimaux sont préfixés
par 0X.

L'instruction de la ligne 12 affecte le résultat de l'opération effectuée par l'opérateur ET au niveau du bit
(&) avec les variables x et y. Ensuite, la ligne 13 affiche le résultat aux formats décimal et hexadécimal.
Machine Translated by Google

Utilisation d'opérateurs conditionnels 133

Les lignes 14 et 15 effectuent l'opération spécifiée par l'opérateur OU au niveau du bit (|) et impriment le
résultat aux formats décimal et hexadécimal. De même, les lignes 16 et 17 donnent le résultat de
l'opération effectuée par l'opérateur XOR au niveau du bit (^).
8
Enfin, l'instruction de la ligne 18 imprime la valeur complémentaire de x en utilisant l'opérateur de
complément au niveau du bit (~). Le résultat est affiché à l'écran aux formats décimal et hexadécimal.

Notez que le spécificateur de format entier non signé avec une largeur de champ minimale de 6,
%6u, et le spécificateur de format hexadécimal majuscule avec une largeur minimale de 4, %04X, sont
utilisés dans la fonction printf() . Le type de données entier non signé est utilisé ici afin que la valeur
complémentaire d'un entier puisse être affichée et comprise facilement. Plus de détails sur le
modificateur de données non signées sont introduits dans l'heure 9.

Ne confondez pas les opérateurs bit à bit & et | avec les opérateurs logiques && et
||. Par exemple,

(x=1) & (y=10)


est une expression complètement différente de

(x=1) && (y=10)

Utilisation des opérateurs de décalage

Il y a deux opérateurs de décalage en C. L' opérateur >> décale les bits d'un opérande vers la droite ;
l' opérateur << décale les bits vers la gauche.

Les formes générales des deux opérateurs de décalage sont

x >> yx
<< y

Ici x est un opérande qui va être décalé. y contient le nombre spécifié de places à décaler.

Par exemple, l'expression 8 >> 2 indique à l'ordinateur de décaler l'opérande 8 vers la droite de 2 bits,
ce qui donne le nombre 2 en décimal. Ce qui suit:

8 >> 2 qui équivaut à (1 * 23 + 0 * 22 + 0 * 21 + 0 * 20 ) >> 2

produit ce qui suit :

(0 * 23 + 0 * 22 + 1 * 21 + 0 * 20 ) qui équivaut à 0010 (au format binaire) ou 2 (au format décimal).


Machine Translated by Google

134 Heure 8

De même, l' expression 5 << 1 décale l'opérande 5 vers la gauche de 1 bit et donne 10 en décimal.

Le programme du Listing 8.6 imprime plus de résultats en utilisant les opérateurs de décalage.

TAPER
LISTE 8.6 Utilisation des opérateurs de décalage

1 : /* 08L06.c : Utilisation des opérateurs de décalage */


2 : #include <stdio.h> 3 : 4 : main() 5 : { 6 : 7 :

entier x, y, z ;

x = 255 ; y
=5;
printf("Étant donné x = %4d, c'est­à­dire 0X%04X\n", x, x); printf(" y =
8 : 9 : 10 : 11%4d,
: c'est­à­dire 0X%04X\n",
%6d, c'est­à­dire
y, y); z =0X%04X\n",
x >> y ; printf("x
z, z);>>
z =y xdonne
<< y ;:
12 : printf("x << y donne : %6d, c'est­à­dire 0X%04X\n", z, z); renvoie 0 ;
13:
14:
15 :
16 :
17 : }

La sortie suivante est obtenue en exécutant le fichier exécutable 08L06.exe sur mon ordinateur :

Soit x = 255, c'est­à­dire 0X00FF 5, c'est­


SORTIR
>> y donneà­dire 0X0005 y = x
: 7, c'est­à­dire
0X0007 x << y donne : 8160, c'est­à­dire
0X1FE0

UNE ANALYSE Trois variables entières, x, y et z, sont déclarées à la ligne 6 du Listing 8.6. x est initialisé à 255
à la ligne 8 ; y est initialisé à 5 à la ligne 9. Ensuite, les lignes 10 et 11 dis
jouer les valeurs de x et y sur l'écran.

L'instruction de la ligne 12 décale y bits de l'opérande x vers la droite, puis affecte le résultat à z. La ligne
13 imprime le résultat du décalage effectué à la ligne 12. Le résultat est 7 en décimal ou 0X0007 en
hexadécimal.

Les lignes 14 et 15 décalent l'opérande x vers la gauche de y bits et affichent également le résultat à
l'écran. Le résultat du décalage vers la gauche est 8160 en décimal, ou 0x1FE0 en hexadécimal.
Machine Translated by Google

Utilisation d'opérateurs conditionnels 135

L'opération de l'opérateur de décalage vers la droite (>>) équivaut à diviser par des
puissances de deux. Autrement dit, ce qui suit :
8
x >> y

est équivalent à ce qui suit :


x/2

Ici x est un entier non négatif.


D'autre part, se déplacer vers la gauche équivaut à multiplier par des puissances de
deux ; C'est,
x << y

est équivalent à
X *2

Que signifie x?y:z ?


L'opérateur ? : est appelé l' opérateur conditionnel, qui est le seul opérateur qui prend trois opérandes.
La forme générale de l'opérateur conditionnel est

X?y:z

Ici x, y et z sont trois expressions d'opérandes. Parmi eux, x contient la condition de test, et y et z
représentent les deux valeurs finales possibles de l'expression. Si x est évalué comme non nul
(logiquement vrai), alors y est choisi ; sinon, z est le résultat obtenu par l'expression conditionnelle.
L'opérateur conditionnel est utilisé comme une sorte de raccourci pour un if
déclaration.

Par exemple, l'expression

x > 0 ? 'T' : 'F'

prend la valeur 'T' si la valeur de x est supérieure à 0. Sinon, l'expression conditionnelle prend la
valeur 'F'.

Le Listing 8.7 montre l'utilisation de l'opérateur conditionnel.

TAPER LISTE 8.7 Utilisation de l'opérateur conditionnel

1 : /* 08L07.c : Utilisation de l'opérateur ?: */


2 : #include <stdio.h> 3 : 4 : main() 5 : {

continue
Machine Translated by Google

136 Heure 8

LISTE 8.7 suite

6: entier x ;
7:
8: x = taillede(entier);
9: printf(“%s\n”, (x == 2)
dix:
11 : ? "Le type de données int a 2 octets." : "int n'a
12 : pas 2 octets."); printf("La valeur maximale de int
13: est : %d\n", (x != 2) ? ~(1 << x * 8 ­ 1) : ~(1 << 15) ); renvoie 0 ;
14:
15:
16 : }

La sortie suivante s'affiche à l'écran lorsque j'exécute le fichier exécutable 08L07.exe sur ma
machine :
Le type de données int a 2 octets
SORTIR La valeur maximale de int est : 32767

Dans le Listing 8.7, la taille du type de données int est mesurée en premier à la ligne 8 en
UNE ANALYSE
utilisant l' opérateur sizeof , et le nombre d'octets est affecté à la variable entière x.

Les lignes 9 à 12 contiennent une instruction, dans laquelle l'opérateur conditionnel (?:) est utilisé
pour tester si le nombre d'octets enregistrés dans x est égal à 2, et le résultat est imprimé. Si l'
expression x == 2 est différente de zéro, la chaîne Le type de données int a 2 octets est imprimée
par la fonction printf() dans l'instruction. Sinon, la deuxième chaîne, int n'a pas 2 octets, s'affiche à
l'écran.

De plus, l'instruction des lignes 11 et 12 essaie de trouver la valeur maximale du type de données
int sur la machine actuelle. L' expression x != 2 est évaluée en premier dans l'instruction. Si
l'expression renvoie une valeur différente de zéro (c'est­à­dire que le nombre d'octets du type de
données int n'est pas égal à 2), l' expression
comme valeur
~(1 <<de
x *retour
8 ­ 1) .est
Ici,évaluée
l' expression
et le résultat
~(1 << xest
* 8choisi
­ 1) est
une forme générale pour calculer la valeur maximale du type*de
[ic:super](x 8 ­données intl'opérateur
1) ­ 1. (Le , qui équivaut
de à
complément, ~, et l'opérateur de décalage, <<, ont été introduits dans les sections2 précédentes de
cette heure.)

En revanche, si la condition de test x != 2 à la ligne 12 renvoie 0, ce qui signifie que la valeur


de x est bien égale à 2, le résultat de l' expression ~(1 << 15) est choisi. Ici, vous avez peut­être
déjà compris que ~(1 << 15) équivaut à 215–1, qui est la valeur maximale que le type de données
int 16 bits peut avoir.

Le résultat affiché à l'écran montre que le type de données int sur ma machine a une longueur de
2 octets (ou 16 bits) et que la valeur maximale du type de données int est 32767.
Machine Translated by Google

Utilisation d'opérateurs conditionnels 137

Résumé
Dans cette leçon, vous avez appris les très importants opérateurs logiques et de manipulation de bits 8
suivants en C :

• L' opérateur sizeof correspond au nombre d'octets qu'un type de données spécifié
a. Vous pouvez utiliser cet opérateur pour mesurer la taille d'un type de données sur votre machine.

• L'opérateur ET logique (&&) donne 1 (vrai logique) uniquement si ses deux


expressions d'opérande) donnent des valeurs non nulles. Sinon, l'opérateur donne 0.

• L'opérateur logique OU (||) ne donne 0 que si ses deux opérandes sont évalués à 0. Sinon, l'opérateur
donne 1.

• L'opérateur de négation logique (!) donne 0 lorsque son opérande est différent de zéro,
et ne donne 1 que si son opérande vaut 0.

• Il existe six opérateurs de manipulation de bits : l'opérateur ET au niveau du bit (&), l'opérateur OU au
niveau du bit (|), l'opérateur XOR au niveau du bit (^), l'opérateur de complément au niveau du bit ~),
l'opérateur de décalage vers la droite (>>), et l'opérateur de décalage à gauche (<<).

• L'opérateur conditionnel (?:) est le seul opérateur en C qui peut prendre trois
opérandes.

Dans la prochaine leçon, vous découvrirez les modificateurs de type de données dans le langage C.

Questions et réponses

Q Pourquoi avons­nous besoin de la taille de l' opérateur ?

A L' opérateur sizeof peut être utilisé pour mesurer la taille de tous les types de données définis en C.
Lorsque vous écrivez un programme C portable qui a besoin de connaître la taille d'une variable entière,
il est déconseillé de coder en dur la taille en fonction de la machine que vous utilisez actuellement. La
meilleure façon d'indiquer au programme la taille de la variable est d'utiliser l' opérateur sizeof , qui donne
la taille de la variable entière au moment de l'exécution.

Q Quelle est la différence entre | et ||?

Un | est l'opérateur OU au niveau du bit qui prend deux opérandes. Le | l'opérateur compare
chaque bit d'un opérande au bit correspondant d'un autre opérande. Si les deux bits sont 0, 0 est placé à
la même position du bit dans le résultat. Sinon, 1 est placé dans le résultat.

D'autre part, ||, en tant qu'opérateur logique OU, nécessite deux opérandes (ou expressions).
L'opérateur ne donne 0 que si ses deux opérandes sont évalués à 0.
Sinon, l'opérateur donne 1.
Machine Translated by Google

138 Heure 8

Q Pourquoi 1 << 3 est­il équivalent à 1 * 23 ?

A L' expression 1 << 3 indique à l'ordinateur de décaler 3 bits de l'opérande 1 vers


la gauche. Le format binaire de l'opérande est 0001. (Notez que seuls les quatre bits les plus bas sont
affichés ici.) Après avoir été décalé de 3 bits vers la gauche, le nombre binaire devient 1000, ce qui
équivaut à 1 * 23 +0 * 22 +0 * 21 +0 * 20 ; c'est­à­dire 1 * 23 .

Q Que peut faire l'opérateur conditionnel (?:) ?

R S'il y a deux réponses possibles sous certaines conditions, vous pouvez utiliser l' opérateur ?: pour
sélectionner l'une des deux réponses en fonction du résultat obtenu en testant les conditions. Par
exemple, l'expression (âge > 65) ? « Retraité » : « Non retraité » indique à l'ordinateur que si la valeur de
l' âge est supérieure à 65 ans, la chaîne Retraité doit être choisie ; sinon, Non retiré est sélectionné.

Atelier
Pour aider à consolider votre compréhension de la leçon de cette heure, nous vous encourageons à répondre
aux questions du quiz et à terminer les exercices fournis dans l'atelier avant de passer à la leçon suivante. Les
réponses et les conseils aux questions et exercices sont donnés dans l'annexe D, « Réponses aux questions et
exercices du quiz ».

Questionnaire

1. Que donnent les expressions (x=1) && (y=10) et (x=1) & (y=10) , respectivement
activement ?

2. Étant donné x = 96, y = 1 et z = 69, à quoi correspond l'expression !y ? x == z : y


évaluer?

3. Si vous avez deux variables int x et y, avec x défini sur la valeur binaire
0011000000111001 et y mis à la valeur binaire 1100111111000110, quelles valeurs sont fournies par
les deux expressions ~x et ~y ?

4. Étant donné x=9, que donne (x%2==0)||(x%3==0) ? Que diriez­vous


(x%2==0)&&(x%3==0) ?

5. Est­ ce que 8 >> 3 équivaut à 8 / 23 ? Que diriez­ vous de 1 << 3 ?

Des exercices

1. Étant donné x = 0xEFFF et y = 0x1000 (c'est­à­dire EFFF et 1000 comme valeurs hexadécimales), quel
valeurs hexadécimales obtenez­vous en évaluant ~x et ~y ?

2. En prenant les valeurs de x et y assignées dans l'exercice 1, écrivez un programme qui imprime les
valeurs de !x et !y en utilisant à la fois les formats %d et %u dans la fonction printf() .
Machine Translated by Google

Utilisation d'opérateurs conditionnels 139

3. Étant donné x = 123 et y = 4, écrivez un programme qui affiche les résultats de l'expression
sions x << y et x >> y.
8
4. Écrivez un programme qui affiche les valeurs (en hexadécimal) des expressions 0xFFFF^0x8888,
0xABCD & 0x4567, et 0xDCBA | 0x1234.
5. Utilisez l' opérateur ?: et l'instruction for pour écrire un programme qui continue à prendre les
caractères saisis par l'utilisateur jusqu'à ce que le caractère q soit pris en compte. (Astuce : placez
?1 l'expression x!='q' : 0 comme deuxième expression dans une instruction for .)
Machine Translated by Google
Machine Translated by Google

HEURE 9

Travailler avec des données


Modificateurs et mathématiques
Les fonctions
Si au début vous ne réussissez pas, transformez vos données.

—Les lois de Murphy sur les ordinateurs

Au cours de l'heure 4, "Comprendre les types de données et les mots­clés", vous


avez découvert plusieurs types de données, tels que char, int, float et double, en langage C.
Au cours de cette heure, vous découvrirez quatre modificateurs de données qui vous permettent
d'avoir un meilleur contrôle sur les données. Les mots clés C pour les quatre modificateurs de données sont

• signé

• non signé
• court

• longue
Machine Translated by Google

142 Heure 9

Vous allez également découvrir plusieurs fonctions mathématiques fournies par le langage C,
telles que

• La fonction sin()

• La fonction cos()

• La fonction tan()

• La fonction pow()

• La fonction sqrt()

Activation ou désactivation du bit de signe


Comme vous le savez, il est très facile d'exprimer un nombre négatif en décimal. Tout ce que vous
avez à faire est de mettre un signe moins devant la valeur absolue du nombre. (La valeur absolue
étant la distance du nombre à zéro.) Mais comment l'ordinateur représente­t­il un nombre négatif au
format binaire ?

Normalement, un bit peut être utilisé pour indiquer si la valeur d'un nombre représenté au format
binaire est négative. Ce bit est appelé bit de signe. Les deux sections suivantes présentent deux
modificateurs de données, signés et non signés, qui peuvent être utilisés pour activer ou désactiver le
bit de signe.

Il convient de noter que certains ordinateurs peuvent ne pas exprimer les nombres négatifs de la
manière décrite ; en fait, la norme du langage C n'exige pas l'utilisation d'un bit de signe, bien qu'il
s'agisse d'une méthode courante. La chose importante à comprendre est la différence entre les types
de données signés et non signés .

Le modificateur signé Pour les entiers, le

bit le plus à gauche peut être utilisé comme bit de signe. Par exemple, si le type de données int a une longueur
de 16 bits et que le bit le plus à droite est compté comme bit 0, vous pouvez utiliser le bit 15 comme bit de signe.
Lorsque le bit de signe est défini sur 1, le compilateur C sait que la valeur représentée par la variable
de données est négative.

Il existe plusieurs façons de représenter une valeur négative des types de données float ou double .
Les implémentations des types de données float et double sortent du cadre de ce livre. Vous pouvez
vous référer au livre de Kernighan et Ritchie, The C Programming Language, pour plus de détails sur
les implémentations des valeurs négatives de type float ou double .

Le langage C fournit un modificateur de données, signé, qui peut être utilisé pour indiquer
au compilateur que les types de données entiers (char, int, short int et long int) utilisent le signe
Machine Translated by Google

Utilisation des modificateurs de données et des fonctions mathématiques 143

bit. (Les modificateurs courts et longs sont présentés plus loin dans ce chapitre). Par défaut, tous les types de
données entiers à l'exception du type de données char sont des quantités signées. Mais la norme ANSI n'exige
pas que le type de données char soit signé ; c'est aux vendeurs de compilateurs de décider. Par conséquent, si
vous souhaitez utiliser une variable de caractère signée et assurez­vous que le compilateur la connaît, vous
pouvez déclarer la variable de caractère comme ceci :

signé char ch;

afin que le compilateur sache que la variable caractère ch est signée, ce qui signifie que la variable peut 9
contenir à la fois des valeurs négatives et positives. Si le type char a une longueur de 8 bits, alors un char signé
7 7
contiendra des valeurs de ­128 (c'est­à­dire 2 ) à 127 (2 ­1). En revanche, un
8
caractère non signé dans ce cas serait compris entre 0 et 255 (2 ­1).

Le modificateur non signé Le langage C vous

donne également le modificateur non signé , qui peut être utilisé pour indiquer au compilateur C que le type
de données spécifié ne peut contenir que des valeurs non négatives.

Comme le modificateur signé , le modificateur non signé n'a de sens que pour les types de
données entiers (char, int, short int et long int).

Par exemple, la déclaration

entier non signé x ;

indique au compilateur C que la variable entière x ne peut prendre que des valeurs positives de 0 à 65535
(c'est­à­dire 216­1), si le type de données int a une longueur de 16 bits ; un int (signé) contiendrait des
valeurs de ­32768 (­2 15­1) à 32767 (2 15).

En fait, unsigned int est équivalent à unsigned (par lui­même) selon la norme ANSI. En d'autres termes,
unsigned int x; est identique à x non signé;.

De plus, la norme ANSI vous permet d'indiquer qu'une constante est de type non signé en suffixant u ou U
à la constante. Par exemple,

entier non signé x, y ;


x = 12345U ; y =
0xABCDu ;

Ici, les constantes entières non signées 12345U et 0xABCDu sont respectivement affectées aux variables x et
y.

Le programme du Listing 9.1 est un exemple d'utilisation des modificateurs signés et non signés .
Machine Translated by Google

144 Heure 9

LISTE 9.1 Modification des données avec signé et non signé

1 : /* 09L01.c : Utilisation de modificateurs signés et non signés */


2 : #include <stdio.h> 3 : 4 : main() 5 : { 6 :

signé char ch; entier


7: x ; entier non signé y ;
8:
9:
10 : ch = 0xFF ;
11 : x = 0xFFFF ;
12 : y = 0xFFFFu ;
13 : printf("La décimale de 0xFF signé est %d.\n", ch); printf("La décimale
14 : de 0xFFFF signé est %d.\n", x); printf("La décimale de 0xFFFFu non
15 : signé est %u.\n", y); printf("L'hexadécimal de la décimale 12345 est 0x%X.
16 : \n", 12345); printf("L'hexadécimal de la décimale ­12345 est 0x%X.\n",
17 : ­12345); renvoie 0 ;
18 :
19 : }

Sur ma machine, le fichier exécutable du programme du Listing 9.1 s'appelle 09L01.exe.


(Notez que lorsque vous compilez le programme dans le Listing 9.1, vous pouvez voir un message
d'avertissement concernant l'instruction d'affectation ch = 0xFF ; à la ligne 10 en raison du fait que ch est
déclaré comme une variable char signée . Vous pouvez ignorer le message d'avertissement .)

Voici la sortie affichée à l'écran après avoir lancé l'exécutable sur mon ordinateur :

La décimale de 0xFF signé est ­1 La


SORTIR
décimale de 0xFFFF signé est ­1.
La décimale de 0xFFFFu non signé est 65535.
L'hexadécimal de la décimale 12345 est 0x3039.
L'hexadécimal de la décimale ­12345 est 0xCFC7.

Comme vous le voyez dans le Listing 9.1, la ligne 6 déclare une variable char signée, ch. La
UNE ANALYSE
variable int x et la variable int non signée y sont déclarées aux lignes 7 et 8, respectivement
activement. Les trois variables, ch, x et y, sont initialisées aux lignes 10–12. Notez qu'à la ligne 12, u
est suffixé à 0xFFFF pour indiquer que la constante est un entier non signé.

L'instruction de la ligne 13 affiche la valeur décimale de la variable char signée ch. La sortie à l'écran
montre que la valeur décimale correspondante de 0xFF est ­1 pour la variable char signée ch.

Les lignes 14 et 15 impriment les valeurs décimales de la variable int x (qui est signée par défaut) et de
la variable int non signée y, respectivement. Notez que pour la variable y, le spécificateur de format
entier non signé %u est utilisé dans la fonction printf() à la ligne 15.
Machine Translated by Google

Utilisation des modificateurs de données et des fonctions mathématiques 145

(En fait, vous vous souviendrez peut­être que %u a été utilisé pour spécifier le type de données int non signé
comme format d'affichage dans l'heure précédente.)

En fonction de la sortie, vous voyez que 0xFFFF est égal à ­1 pour le type de données int signé et 65535 pour le
type de données int non signé . Ici, le type de données entier a une longueur de 16 bits.

Les lignes 16 et 17 impriment 0x3039 et 0xCFC7, qui sont les formats hexadécimaux des valeurs décimales de
12345 et ­12345, respectivement. Selon la méthode mentionnée dans la dernière section, 0xCFC7 est obtenu en
ajoutant 1 à la valeur complémentée de 0x3039. 9
Vous pouvez obtenir des résultats différents à partir de cet exemple, selon la largeur des différents types
de données sur votre système. La chose importante à comprendre est la différence entre les types de données
signés et non signés .

Modification des tailles de données


Parfois, vous souhaitez réduire la mémoire occupée par les variables ou vous devez augmenter l'espace de
stockage de certains types de données. Heureusement, le langage C vous donne la flexibilité de modifier la taille
des types de données. Les deux modificateurs de données, court et long, sont présentés dans les deux sections
suivantes.

Le modificateur court
Un type de données peut être modifié pour utiliser moins de mémoire en utilisant le modificateur court .
Par exemple, vous pouvez appliquer le modificateur short à une variable entière longue de 32 bits, ce qui
peut réduire la mémoire utilisée par la variable à 16 bits seulement.

Vous pouvez utiliser le modificateur court comme ceci :

x court ;

ou alors

y court non signé ;

Par défaut, un type de données int court est un nombre signé. Par conséquent, dans le court x; , x est
une variable signée d'entier court.

Le modificateur long Si vous avez

besoin de plus de mémoire pour conserver les valeurs d'une plage plus large, vous pouvez utiliser le
modificateur long pour définir un type de données avec un espace de stockage accru.

Par exemple, étant donné une variable entière x longue de 16 bits, la déclaration

entier long x ;

augmente la taille de x à au moins 32 bits.


Machine Translated by Google

146 Heure 9

La norme ANSI permet d'indiquer qu'une constante est de type long en suffixant l ou
L à la constante :

entier long x, y ; x
= 123456789l ; y =
0xABCD1234L ;

Ici, les constantes du type de données int long , 123456789l et 0xABCD1234L, sont
respectivement affectées aux variables x et y.

De plus, vous pouvez déclarer une variable entière longue simplement comme ceci :

x long ;

qui équivaut à

entier long x ;

Le Listing 9.2 contient un programme qui peut imprimer le nombre d'octets fournis par le compilateur
C utilisé pour compiler le programme pour différents types de données modifiés.

LISTE 9.2 Modification des données avec court et long

1 : /* 09L02.c : Utilisation de modificateurs courts et longs */


2 : #include <stdio.h> 3 : 4 : main() 5 : { 6 : 7 :

printf("La taille de l'entier court est : %d.\n",


sizeof(entier court));
printf("La taille de l'entier long est : %d.\n",
sizeof(entier long));
printf("La taille de float est : %d.\n", sizeof(float));
8 : 9 : 10 : 11 : printf("La taille de double est : %d.\n",
12 : sizeof(double));
13:
14: printf("La taille du double long est : %d.\n",
15 : sizeof(long double)); renvoie
16 : 0;
17 : }

J'obtiens le résultat suivant après avoir exécuté l'exécutable 09L02.exe sur mon ordinateur :
La taille de l'entier court est : 2.
SORTIR La taille de l'entier long est : 4.
La taille du flotteur est : 4.
La taille du double est : 8.
La taille du double long est : 10.
Machine Translated by Google

Utilisation des modificateurs de données et des fonctions mathématiques 147

UNE ANALYSE
Dans le Listing 9.2, l' opérateur sizeof et la fonction printf() sont utilisés pour mesurer la taille des
types de données modifiés et afficher les résultats à l'écran.

Par exemple, les lignes 6 et 7 obtiennent la taille du type de données int court et impriment le nombre
d'octets, 2, à l'écran. D'après la sortie, vous savez que le type de données int court fait 2 octets sur ma
machine.

De même, les lignes 8 et 9 trouvent que la taille du type de données long int est de 4 octets, ce qui correspond
à la même longueur que le type de données float obtenu aux lignes 10 et 11. 9
Les lignes 12 et 13 obtiennent la taille du type de données double , qui est de 8 octets sur ma
machine. Ensuite, après avoir été modifié par le modificateur long , la taille du type de données double est
augmentée à 10 octets (c'est­à­dire 80 bits), ce qui est affiché par l' appel printf() aux lignes 14 et 15.

Comme dans l'exemple précédent, vos résultats seront probablement différents si votre système
prend en charge des largeurs de données différentes de celles de ma machine. En exécutant ce programme
sur votre propre ordinateur, vous pouvez déterminer les largeurs de ces types de données pour votre
système.

Ajout de h, l ou L aux spécificateurs de format printf et fprintf Les fonctions printf et fprintf doivent

connaître le type de données exact des arguments qui leur sont transmis afin d'évaluer

correctement ces arguments et d'imprimer leurs valeurs de manière significative. La chaîne de format des
fonctions printf et fprintf utilise les spécificateurs de conversion d, i, o, u, x ou X pour indiquer que l'argument
correspondant est un entier et est de type int ou unsigned int.

Vous pouvez ajouter h dans le spécificateur de format entier (comme ceci : %hd, %hi ou %hu) pour spécifier que
l'argument correspondant est un entier court ou un entier court non signé.

D'autre part, l'utilisation de %ld ou %Ld spécifie que l'argument correspondant est un entier long. %lu ou
%Lu est ensuite utilisé pour les données de type entier long non signé .

Le programme du Listing 9.3 montre l'utilisation de %hd, %lu et %ld.

LISTE 9.3 Utilisation de %hd, %ld et %lu

1 : /* 09L03.c : Utilisation des spécificateurs %hd, %ld et %lu */ 2 : #include


<stdio.h> 3 : 4 : main() 5 : { 6 :

entier court X;
continue
Machine Translated by Google

148 Heure 9

LISTE 9.3 suite

7: entier non signé y ; entier


8: long s ; entier long non
9: signé t ;
10 :
11 : x = 0xFFFF ;
12 : y = 0xFFFFU ;
13 : s = 0xFFFFFFFFl ; t
14 : = 0xFFFFFFFFL ;
15 : printf("L'entier court de 0xFFFF est %hd.\n", x); printf("L'entier
16 : non signé de 0xFFFF est %u.\n", y); printf("L'entier long de
17 : 0xFFFFFFFF est %ld.\n", s); printf("L'entier long non signé de
18 : 0xFFFFFFFF est %lu.\n", t); renvoie 0 ;
19 :
20 : }

Une fois le fichier exécutable 09L03.exe créé et exécuté sur ma machine, la sortie suivante s'affiche à
l'écran :
L'entier court de 0xFFFF est ­1.
SORTIR L'entier non signé de 0xFFFF est 65535.
L'entier long de 0xFFFFFFFF est ­1.
L'entier long non signé de 0xFFFFFFFF est 4294967295

Il y a quatre types de données déclarés dans le Listing 9.3 : la variable int courte x, la variable
UNE ANALYSE
int non signée y, la variable int longue s et la variable int longue non signée t. Les quatre
variables sont initialisées aux lignes 6–9.

Pour afficher les valeurs décimales de x, y, s et t, les spécificateurs de format %hd, %u, %ld et %lu sont
utilisés respectivement aux lignes 15 à 18 pour convertir les nombres hexadécimaux correspondants en
nombres décimaux. La sortie du programme du Listing 9.3 montre que les valeurs contenues par x, y, s
et t ont été correctement affichées à l'écran.

Fonctions mathématiques en C
Fondamentalement, les fonctions mathématiques fournies par le langage C peuvent être classées en trois
groupes:

• Fonctions trigonométriques et hyperboliques, telles que acos(), cos() et cosh().


• Fonctions exponentielles et logarithmiques, telles que exp(), pow() et log10().
• Diverses fonctions mathématiques, telles que ceil(), fabs() et floor().

Vous devez inclure le fichier d' en­tête math.h dans votre programme C avant de pouvoir utiliser les
fonctions mathématiques définies dans le fichier d'en­tête.

Les deux sections suivantes présentent plusieurs fonctions mathématiques et décrivent comment les
utiliser dans vos programmes.
Machine Translated by Google

Utilisation des modificateurs de données et des fonctions mathématiques 149

Appel de sin(), cos() et tan()


Vous pouvez ignorer les deux sections suivantes si vous n'êtes pas un fan de mathématiques, car elles ne sont
pas essentielles pour comprendre le langage C lui­même. Cependant, si vous avez besoin de faire des calculs
mathématiques, vous apprécierez peut­être que C vous donne cet ensemble de fonctions mathématiques.

Par exemple, étant donné un angle x en radians, l' expression sin renvoie le sinus de l'angle.

La formule suivante peut être utilisée pour convertir la valeur d'un angle en degrés en une valeur en radians :
9
radians = degré * (3,141593 / 180,0).

Ici, 3,141593 est la valeur approximative de pi. Si nécessaire, vous pouvez utiliser plus de chiffres
décimaux à partir de pi.

Examinons maintenant la syntaxe des fonctions sin(), cos() et tan() .

La syntaxe de la fonction sin() est

SYNTAXE
#include <math.h>
double sin(double x);

Ici, la variable double x contient la valeur d'un angle en radians. La fonction sin() renvoie le sinus de x dans le
type de données double .

La syntaxe de la fonction cos() est

#include <math.h>
SYNTAXE

double cos(double x);

Ici, la variable double x contient la valeur d'un angle en radians. La fonction cos() renvoie le cosinus de x dans
le type de données double .

La syntaxe de la fonction tan() est

#include <math.h>
double tan(double x);
SYNTAXE

Ici, la variable double x contient la valeur d'un angle en radians. La fonction tan() renvoie la tangente de x dans
le type de données double .

Le Listing 9.4 montre comment utiliser les fonctions sin(), cos() et tan() .

LISTE 9.4 Calcul des valeurs trigonométriques avec sin(), cos() et tan()

1 : /* 09L04.c : Utilisation des fonctions sin(), cos() et tan() */ 2 : #include


<stdio.h> 3 : #include <math.h>

4:

continue
Machine Translated by Google

150 Heure 9

LISTE 9.4 suite

5 : principal()
6:{7:
double X;

x = 45,0 ; /* 45 degrés */ x *= 3,141593 / 180,0 ; /* convertir


en radians */ printf("Le sinus de 45 est :cosinus
%f.\n", sin);
de 45printf("Le
est : %f.\n", cos);
8 : 9 : 10 : 11printf("La
: tangente de 45 est : %f.\n", tan); renvoie 0 ;
12 :
13:
14:
15 : }

La sortie suivante s'affiche à l'écran lorsque le fichier exécutable 09L04.exe est exécuté :

Le sinus de 45 est : 0,707107.


SORTIR Le cosinus de 45 est : 0,707107.
La tangente de 45 est : 1,000000.

Notez que le fichier d'en­tête math.h est inclus à la ligne 3, ce qui est requis par les fonctions
UNE ANALYSE
mathématiques C.

La variable double x du Listing 9.4 est initialisée avec 45,0 à la ligne 9. Ici, 45,0 est la valeur de l'angle
en degrés, qui est convertie en la valeur correspondante en radians à la ligne 10.

Ensuite, l'instruction de la ligne 11 calcule le sinus de x en appelant la fonction sin() et affiche le


résultat à l'écran. De même, la ligne 12 obtient le cosinus de x et l'affiche également à l'écran.
Parce que x contient la valeur d'un angle de 45 degrés, il n'est pas surprenant de voir que les valeurs du
sinus et du cosinus sont les mêmes, environ 0,707107.

La ligne 13 donne la valeur tangente de x en utilisant la fonction tan() . Comme vous le savez peut­être,
la tangente de x est égale au sinus de x divisé par le cosinus de x. Étant donné que le sinus d'un angle
de 45 degrés est le même que le cosinus d'un angle de 45 degrés, la tangente d'un angle de 45 degrés
est égale à 1. Le résultat (au format à virgule flottante) de 1,000000, dans le troisième ligne de la sortie
de la liste, le prouve.

Pour simplifier les choses, vous pouvez déclarer une variable PI initialisée à 3,141593 et une autre
variable initialisée à 180,0, et les utiliser dans vos calculs. Ou, déclarez simplement une seule
constante initialisée au résultat de 3.141593/180.0.

Appel de pow() et sqrt()


Les fonctions pow() et sqrt() sont deux autres fonctions mathématiques utiles en C. Contrairement à
d'autres langages, C n'a pas d'opérateur intrinsèque pour élever un nombre à une puissance.
Machine Translated by Google

Utilisation des modificateurs de données et des fonctions mathématiques 151

La syntaxe de la fonction pow() est

SYNTAXE
#include <math.h>
double pow(double x, double y);

Ici, la valeur de la variable double x est élevée à la puissance y. La fonction pow() renvoie le résultat
dans le type de données double .

La syntaxe de la fonction sqrt() est

SYNTAXE
#include <math.h> 9
double sqrt(double x);

Ici, la fonction sqrt() renvoie la racine carrée non négative de x dans le type de données double .
Une erreur se produit si x est négatif.

Si vous passez 0,5 à la fonction pow() comme second argument, et que x contient une valeur non
négative, les deux expressions, pow(x, 0,5) et sqrt, sont équivalentes.

Maintenant, regardez comment appeler les fonctions pow() et sqrt() dans le programme présenté dans
le Listing 9.5.

LISTE 9.5 Application des fonctions pow() et sqrt()

1 : /* 09L05.c : Utilisation des fonctions pow() et sqrt() */ 2 : #include


<stdio.h> 3 : #include <math.h> 4 :

5 : principal()
6:{7:
double x, y, z ;

x = 64,0 ; y
= 3,0 ; z =
8 : 9 : 10 : 110,5
: ;
12 : printf("pow(64.0, 3.0) renvoie : %7.0f\n", pow(x, y)); printf("sqrt(64.0)
13: renvoie : %2.0f\n", sqrt); printf("pow(64.0, 0.5)
z));renvoie
renvoie: %2.0f\n",
0; pow(x,
14:
15 :
16 : }

Ensuite, la sortie suivante s'affiche à l'écran après l'exécution du fichier exécutable 09L05.exe :

pow(64.0, 3.0) renvoie : 262144 sqrt(64.0)


SORTIR renvoie : 8 pow(64.0, 0.5) renvoie : 8

UNE ANALYSE Les trois variables doubles du Listing 9.5, x, y et z, sont initialisées avec 64.0, 3.0 et 0.5,
respectivement, aux lignes 9–11.
Machine Translated by Google

152 Heure 9

La fonction pow() de la ligne 12 prend x et y puis calcule la valeur de x élevée à la puissance y. Parce que le
résultat est un double, mais je sais que la partie fractionnaire sera composée uniquement de chiffres décimaux
de 0, le spécificateur de format %7.0f est utilisé dans la fonction printf() pour convertir uniquement la partie non
fractionnaire de la valeur. Le résultat s'affiche à l'écran sous la forme
262144.

À la ligne 13, la racine carrée non négative de x est calculée en appelant la fonction sqrt() .
Comme à la ligne 12, le spécificateur de format %2.0f est utilisé à la ligne 13 pour convertir la partie non
fractionnaire de la valeur renvoyée par la fonction sqrt() car la partie fractionnaire se compose uniquement de 0.
Comme vous le voyez dans la sortie, la racine carrée non négative de x est 8.

Comme je l'ai mentionné plus tôt, l'expression pow(x, 0.5) est équivalente à l'expression sqrt.
Ainsi, il n'est pas surprenant de voir que pow(x, z) dans l'instruction de la ligne 14 produit le même résultat que sqrt
dans la ligne 13.

Tous les calculs en virgule flottante, y compris les types de données float et double, sont
effectués en arithmétique à double précision. C'est­à­dire qu'une variable flottante doit être
convertie en un double pour poursuivre le calcul.
Après le calcul, le double doit être reconverti en flottant avant que le résultat puisse être
affecté à la variable flottante. Par conséquent, un calcul flottant peut prendre plus de temps.

La raison principale pour laquelle C prend en charge le type de données float est
d'économiser de l'espace mémoire car le type de données double prend deux fois plus
d'espace mémoire pour le stockage que le type de données float. Dans de nombreux cas,
une précision au­delà de ce qui est fourni par float est tout simplement inutile.

Résumé
Dans cette leçon, vous avez appris les modificateurs et fonctions mathématiques importants suivants :

• Le modificateur signé peut être utilisé pour déclarer des types de données char et int capables de
détenir des valeurs négatives et non négatives.

• Toutes les variables int en C sont signées par défaut. • Le

modificateur unsigned peut être utilisé pour déclarer des types de données char et int qui ne peuvent pas
contenir de valeurs négatives. Cela double effectivement la plage de valeurs positives que la variable peut
contenir.

• L'espace mémoire occupé par une variable de données peut être réduit ou augmenté en utilisant
le modificateur de données court ou long , respectivement.
Machine Translated by Google

Utilisation des modificateurs de données et des fonctions mathématiques 153

• Il existe un ensemble de fonctions de la bibliothèque C, telles que sin(), cos() et tan(), qui peuvent être
utilisé pour effectuer des calculs trigonométriques ou hyperboliques.

• Il existe un autre groupe de fonctions mathématiques en C—par exemple, pow()—qui peut


effectuer des calculs exponentiels et logarithmiques.

• La fonction sqrt() renvoie une racine carrée non négative. L'expression sqrt est équivalente à l'
expression pow(x, 0.5) , si x a une valeur non négative. Vous ne pouvez pas passer une valeur
négative à la fonction sqrt() , car cela provoquerait une erreur. • Le fichier d'en­tête math.h doit être
9
inclus dans votre programme C si vous appelez des fonctions mathématiques déclarées dans ce fichier
d'en­tête.

Dans la leçon suivante, vous apprendrez plusieurs instructions de flux de contrôle très importantes en C.

Questions et réponses

Q Quel bit peut être utilisé comme bit de signe dans un entier ?

A Le bit le plus à gauche peut être utilisé comme bit de signe pour un entier. Par exemple, supposons que le
type de données int ait une longueur de 16 bits. Si vous comptez la position du bit de droite à gauche et
que le premier bit compté est le bit 0, le bit 15 est le bit le plus à gauche qui peut être utilisé comme bit de
signe.

Q Que peut faire le spécificateur de format %lu ?

A Le spécificateur de format %lu peut être utilisé dans une chaîne printf() pour convertir le
argument répondant au type de données int long non signé . De plus, le spécificateur %lu pour mat est
équivalent à %Lu.

Q Quand dois­je utiliser court et long ?

A Si vous avez besoin d'économiser de l'espace mémoire et que vous savez que la valeur d'une variable de
données entière reste dans une plage plus petite, vous pouvez essayer d'utiliser le modificateur court
pour indiquer au compilateur C de réduire l'espace mémoire par défaut affecté à la variable, par exemple,
de 32 bits à 16 bits.

D'un autre côté, si une variable doit contenir un nombre qui dépasse la plage actuelle d'un type de
données, vous pouvez utiliser le modificateur long pour augmenter l'espace de stockage de la variable afin
de contenir le nombre.

Q La fonction sin() prend­elle une valeur en degrés ou en radians ?

A Comme les autres fonctions mathématiques trigonométriques en C, la fonction sin() prend une valeur en
radians. Si vous avez un angle en degrés, vous devez le convertir en radians. La formule est :

radians = degré * (3,141593 / 180,0).


Machine Translated by Google

154 Heure 9

Atelier
Pour aider à consolider votre compréhension de la leçon de cette heure, nous vous encourageons à répondre aux
questions du quiz et à terminer les exercices fournis dans l'atelier avant de passer à la leçon suivante. Les réponses
et les conseils aux questions et exercices sont donnés dans l'annexe D, « Réponses aux questions et exercices du
quiz ».

Questionnaire

1. Étant donné une variable int x et une variable int non signée y, ainsi que x = 0x8765 et y = 0x8765, et si le
bit le plus à gauche est utilisé comme bit de signe, x est­il égal à y ?

2. Que devez­vous faire si vous essayez d'attribuer une grande valeur à une variable int , mais que la valeur
que vous attribuez est trop grande et que vous vous retrouvez avec un nombre négatif auquel vous ne
vous attendiez pas ?

3. Quel spécificateur de format, %ld ou %lu, doit être utilisé pour spécifier un long non signé
variable entière ?

4. Quel est le nom du fichier d'en­tête que vous devez inclure si vous appelez des fonctions mathématiques C
depuis votre programme C ?

Des exercices

1. Étant donné les déclarations suivantes, int


x ; entier non signé y ; x = 0xAB78 ; y =
0xAB78 ;

écrire un programme pour afficher les valeurs décimales de x et y à l'écran.

2. Écrivez un programme pour mesurer les tailles d' entier court, d'entier long et de double long sur votre machine.

3. Écrivez un programme pour multiplier deux variables entières signées par des valeurs positives et affichez le
résultat sous la forme d'un entier long.

4. Écrivez un programme pour afficher les nombres entiers négatifs au format hexadécimal avec leur signe
équivalents entiers .

5. Étant donné un angle de 30 degrés, écrivez un programme pour calculer son sinus et sa tangente
valeurs.

6. Écrivez un programme pour calculer la racine carrée non négative de 0x19A1.


Machine Translated by Google

HEURE 10

Programme de contrôle
Flux
Il est plus difficile de commander que d'obéir.

­F. Nietzsche

Dans l'heure 7, "Travailler avec des boucles", vous avez appris à utiliser les instructions
while, do­while et for pour faire les mêmes choses encore et encore. Ces trois
instructions peuvent être regroupées dans la catégorie des instructions en boucle
utilisées pour le contrôle de flux en C.

Dans cette leçon, vous découvrirez les instructions appartenant à un autre groupe
d' instructions de flux de contrôle, le branchement conditionnel (ou le saut), comme

• L' instruction if
• L' instruction if­else
• L' instruction switch
• L' instruction break
• L' instruction continue

• L' instruction goto


Machine Translated by Google

156 Heure 10

Toujours dire « si… »


Si la vie était une ligne droite, ce serait très ennuyeux. La même chose est vraie pour la programmation. Ce
serait trop ennuyeux si les instructions de votre programme ne pouvaient être exécutées que dans l'ordre dans
lequel elles apparaissent.

En fait, une tâche importante d'un programme consiste à demander à l'ordinateur de se brancher (c'est­à­
dire de sauter) vers différentes parties du code et de travailler sur différentes tâches chaque fois que les conditions
spécifiées sont remplies.

Cependant, dans la plupart des cas, vous ne savez pas à l'avance ce qui va suivre. Ce que vous savez, c'est
que quelque chose doit arriver si certaines conditions sont remplies. Par conséquent, vous pouvez simplement
écrire les tâches et les conditions dans le programme. Les décisions concernant le moment d'exécution des
tâches sont prises par les instructions de branchement conditionnel.

En C, l' instruction if est l'instruction de branchement conditionnel la plus populaire ; il peut être utilisé pour
évaluer les conditions ainsi que pour décider si le bloc de code

contrôlé par l'instruction va être exécuté.

La forme générale de l' instruction if est

si (expression)
{ instruction1 ;
instruction2 ;
.
.
.
}

Ici , l' expression est le critère conditionnel. Si expression donne une valeur différente de zéro, les instructions
entre accolades ({ et }), telles que instruction1 et instruction2, sont exécutées. Si expression prend la valeur zéro,
les instructions sont ignorées.

Notez que les accolades ({ et }) forment un bloc d'instructions qui est sous le contrôle de l' instruction if . S'il n'y
a qu'une seule instruction à l'intérieur du bloc, les accolades peuvent être omises.
Les parenthèses (( et )), cependant, doivent toujours être utilisées pour délimiter l'expression conditionnelle.

Par exemple, l'expression suivante :

if (x > 0.0)
printf("La racine carrée de x est : %f\n", sqrt);

indique à l'ordinateur que si la valeur de la variable à virgule flottante x est supérieure à 0,0 (c'est­à­dire
positive), il doit calculer la racine carrée de x en appelant la fonction sqrt() , puis imprimer le résultat. Ici, le critère
conditionnel est l'expression relationnelle
Machine Translated by Google

Contrôle du déroulement du programme 157

x > 0,0, qui prend la valeur 1 (logiquement vrai) si x est supérieur à zéro, et prend la valeur 0
(logiquement faux) si x est inférieur ou égal à zéro.

Le Listing 10.1 vous donne un autre exemple d'utilisation de l' instruction if .

LISTE 10.1 Utilisation de l' instruction if dans la prise de décision

1 : /* 10L01.c Utilisation de l'instruction if */ 2 : #include <stdio.h>


3 : 4 : main() 5 : { 6 : 7 :

int je ;

printf("Entiers qui peuvent être divisés à la fois par 2 et 3\n"); printf("(entre 0 et 100):\n"); for
(i=0; i<=100; i++){ if ((i%2 == 0) && (i%3 == 0)) printf(“ %d\n”, i); dix
8 : 9 : 10 : 11 :
12 :
13 : } 14 :
renvoie 0 ; 15 : }

Après la création et l'exécution de 10L01.exe, l'exécutable du programme du Listing 10.1, la sortie


suivante s'affiche à l'écran :

Nombres entiers pouvant être divisés à la fois par 2 et 3 (dans la plage


SORTIR de 0 à 100) :
0
6
12
18
24
30
36
42
48
54
60
66
72
78
84
90
96

Comme vous le voyez dans le Listing 10.1, la ligne 6 déclare une variable entière, i. Les
UNE ANALYSE
lignes 8 et 9 impriment deux titres. À partir de la ligne 10, l' instruction for continue de boucler 101
fois.
Machine Translated by Google

158 Heure 10

Dans la boucle for , l'instruction if des lignes 11 et 12 évalue l'expression logique (i%2 == 0) && (i%3 ==
0). Si l'expression est évaluée à 1 (c'est­à­dire que la valeur de i peut être complètement divisée par 2
et 3 ), la valeur de i est affichée à l'écran en appelant la fonction printf() à la ligne 12. Sinon, l'instruction
dans la ligne 12 est sautée.

Notez que les accolades ({ et }) ne sont pas utilisées car il n'y a qu'une seule instruction sous le contrôle
de l' instruction if .

Le résultat affiché à l'écran donne tous les nombres entiers compris entre 0 et 100 qui peuvent être
divisés de manière égale par 2 et 3.

La déclaration if­else
Dans l' instruction if , lorsque l'expression conditionnelle prend une valeur différente de zéro,
l'ordinateur passe directement aux instructions contrôlées par l' instruction if et les exécute
immédiatement. Si l'expression prend la valeur zéro, l'ordinateur ignorera les instructions contrôlées
par l' instruction if .

Vous souhaiterez souvent que l'ordinateur exécute un autre ensemble d'instructions lorsque l'expression
conditionnelle de l' instruction if est évaluée comme logiquement fausse. Pour ce faire, vous pouvez
utiliser une autre instruction de branchement conditionnel en C : l' instruction if­else .

En tant qu'extension de l' instruction if , l'instruction if­else a la forme suivante :

si (expression)
{ instruction1 ;
instruction2 ;
.
.
.

} else
{ instruction_A ;
instruction_B ;
.
.
.
}

Si expression donne une valeur différente de zéro, les instructions contrôlées par if, y compris
instruction1 et instruction2, sont exécutées. Cependant, si expression prend la valeur zéro, instruction_A
et instruction_B suivant le mot­clé else sont exécutées à la place.

Le programme du Listing 10.2 montre comment utiliser l' instruction if­else .


Machine Translated by Google

Contrôle du déroulement du programme 159

LISTE 10.2 Utilisation de l' instruction if­else

1 : /* 10L02.c Utilisation de l'instruction if­else */ 2 : #include <stdio.h>


3 : 4 : main() 5 : { 6 :

int je ;
7:
8: printf("Nombre pair Nombre impair\n"); for (i=0; i<10; i++)
9: if (i%2 == 0) printf("%d", i); sinon printf("%14d\n", je);
10 :
11 :
12 :
13 :
14 :
15 : renvoie 0 ; dix
16 : }

Le résultat suivant est obtenu en lançant le fichier exécutable 10L02.exe :


Nombre pair Nombre impair 0 2
SORTIR
13

4 5
6 7
8 9

La ligne 6 du Listing 10.2 déclare une variable entière, i. La fonction printf() à la ligne 8
UNE ANALYSE
affiche un titre à l'écran.

La variable entière i est initialisée dans la première expression de l' instruction for de la ligne 9.
Contrôlée par l' instruction for , l'instruction if­else des lignes 10 à 13 est exécutée 10 fois. Selon
l' instruction if­else , l' appel printf() à la ligne 11 imprime les nombres pairs si l'expression
relationnelle i%2 == 0 à la ligne 10 est évaluée à 1 (logiquement vrai). Si l'expression relationnelle est
évaluée à 0 (logiquement faux), l' appel printf() contrôlé par le mot­clé else à la ligne 13 renvoie des
nombres impairs sur la sortie standard.

Étant donné que l' instruction if­else est traitée comme une instruction unique, les accolades { et } ne
sont pas nécessaires pour former un bloc d'instructions sous l' instruction for . De même, aucune
accolade n'est utilisée dans l' instruction if­else car les mots­clés if et else contrôlent chacun une seule
instruction aux lignes 11 et 13 respectivement.

Notez que la largeur minimale de 14 est spécifiée dans la fonction printf() à la ligne 13, de sorte
que la sortie des nombres impairs est répertoriée à droite des nombres pairs, comme vous pouvez
le voir dans la section de sortie. Le programme du Listing 10.2 vérifie les nombres compris entre 0
et 9 et montre que 0, 2, 4, 6 et 8 sont des nombres pairs et que 1, 3, 5, 7 et 9 sont des nombres impairs.
Machine Translated by Google

160 Heure 10

Instructions if imbriquées
Comme vous l'avez vu dans les sections précédentes, une instruction if permet à un programme de prendre
une décision. Dans de nombreux cas, un programme doit prendre une série de décisions connexes. À cette
fin, vous pouvez utiliser des instructions if imbriquées .

Le Listing 10.3 montre l'utilisation des instructions if imbriquées .

LISTE 10.3 Utilisation des instructions if imbriquées

1 : /* 10L03.c Utilisation d'instructions if imbriquées */


2 : #include <stdio.h> 3 : 4 : main() 5 : { 6 :

int je ;
7:
8: for (i=­5; i<=5; i++){ if (i > 0)
9: if (i%2 == 0) printf(“%d
10 : est un nombre pair.
11 : \n”, i); sinon printf("%d est un nombre impair.\n",
12 : i); sinon si (i == 0) printf("Le nombre est zéro.\n");
13 : sinon printf("Négatif : %d\n", i); renvoie 0 ;
14 :
15 :
16 :
17 :
18 : }19 :
20 : }

Après avoir lancé le fichier exécutable 10L03.exe, j'obtiens le résultat suivant :

Nombre négatif : ­5
SORTIR Nombre négatif : ­4
Nombre négatif : ­3
Nombre négatif : ­2
Nombre négatif : ­1 Le
nombre est zéro. 1 est
un nombre impair. 2 est
un nombre pair. 3 est un
nombre impair. 4 est un
nombre pair. 5 est un
nombre impair.

UNE ANALYSE Le Listing 10.3 contient une boucle for , commençant à la ligne 8 et se terminant à la ligne 18.
Selon les expressions de l' instruction for de la ligne 8, toutes les tâches contrôlées
par l' instruction for sont exécutées jusqu'à 11 fois.
Machine Translated by Google

Contrôle du déroulement du programme 161

Tout d'abord, une décision doit être prise sur la base de l'évaluation de l'expression relationnelle i > 0
dans l' instruction if de la ligne 9. L' expression i > 0 est utilisée pour tester si la valeur de i est positive
ou autre (nombres négatifs, y compris zéro.) Si l'expression est évaluée à 1, l'ordinateur saute à la
deuxième instruction if (c'est­à­dire imbriquée) de la ligne 11.

Notez que la ligne 11 contient une autre expression relationnelle, i%2 == 0, qui teste si la variable
entière i est paire ou impaire. Par conséquent, la deuxième décision d'afficher des nombres pairs ou
des nombres impairs doit être prise en fonction de l'évaluation de la deuxième expression relationnelle,
i%2 == 0. Si cette évaluation donne 1, l' appel printf() à la ligne 11 imprime un nombre pair. Sinon,
l'instruction de la ligne 13 est exécutée et un nombre impair s'affiche à l'écran.

L'ordinateur passe à la ligne 14 si l' expression i > 0 de la ligne 9 donne 0 ; c'est­à­dire si la valeur de i
n'est pas supérieure à 0. À la ligne 14, une autre instruction if est imbriquée dans une phrase else et
l'expression relationnelle i == 0 est évaluée. Si i == 0 est évalué comme logiquement vrai, ce qui signifie
dix
que i contient la valeur zéro, la chaîne Le nombre est zéro s'affiche à l'écran. Sinon, la valeur de i doit
être négative, selon l'évaluation précédente de l' expression i > 0 à la ligne 9. L'instruction de la ligne
17 affiche alors le nombre négatif sur la sortie standard.

Comme vous pouvez le voir dans l'exemple, la valeur de i est comprise entre 5 et ­5. Ainsi, ­5, ­4, ­3, ­2
et ­1 sont imprimés sous forme de nombres négatifs. Ensuite, un message est imprimé lorsque i vaut
zéro, puis les nombres impairs 1, 3 et 5, ainsi que les nombres pairs 2 et 4 sont imprimés.

La déclaration de commutateur
Dans la dernière section, vous avez vu que les instructions if imbriquées sont utilisées lorsqu'il y a des
décisions successives et liées à prendre. Cependant, les instructions if imbriquées peuvent devenir très
complexes si de nombreuses décisions doivent être prises. Parfois, un programmeur aura des
problèmes pour suivre une série d' instructions if imbriquées complexes .

Heureusement, il existe une autre instruction en C, l' instruction switch , que vous pouvez utiliser pour
prendre des décisions ou des choix illimités en fonction de la valeur d'une expression conditionnelle
et de cas spécifiés.

La forme générale de l' instruction switch est


switch (expression) { case
expression­constante1 :
instruction1 ;

case expression­constante2 :
Machine Translated by Google

162 Heure 10

instruction2 ;

.
.
.
par
défaut : instruction­default ;
}

Ici, l'expression conditionnelle, expression, est évaluée en premier. L'instruction switch passera alors à
l' étiquette de cas appropriée et exécutera, dans l'ordre, les instructions qui suivent. Si expression
donne une valeur égale à l'expression constante constante­expression1, l'instruction instruction1 est
exécutée, suivie de instruction2 et de tout jusqu'à instruction­default. Si la valeur renvoyée par
expression est la même que celle de expression­constante2, instruction2 est exécutée en premier. Si,
toutefois, la valeur de expression n'est égale à aucune des valeurs des expressions constantes étiquetées
par le mot­clé case , l' instruction (instruction­default) qui suit le mot­clé default est exécutée.

Vous devez utiliser le mot­clé case pour étiqueter chaque cas. Notez que chaque étiquette de cas se
termine par deux­ points et non par un point­virgule. Il s'agit de la syntaxe des étiquettes en C. Le mot
clé par défaut doit être utilisé pour le cas "par défaut", c'est­à­dire lorsqu'aucune étiquette de cas ne
correspond à l'expression conditionnelle. Notez qu'aucune des expressions constantes associées aux
étiquettes de cas ne peut être identique dans l' instruction switch .

En C, une étiquette est utilisée comme une sorte de signet dans votre code pour être utilisée par
l'instruction de branchement conditionnel. Une étiquette n'est pas, en elle­même, une déclaration ;
il indique plutôt un endroit où sauter lorsque vous souhaitez vous écarter du flux d'exécution
normal de haut en bas.

La syntaxe appropriée pour une étiquette est un identifiant unique suivi de deux­points — et
non d'un point­virgule . Dans ce chapitre, vous verrez plusieurs manières d'utiliser les étiquettes,
ainsi que les noms d'étiquette réservés case expression : et default :.

Le programme du Listing 10.4 vous donne un exemple d'utilisation de l' instruction switch . Le
programme démontre également une caractéristique importante de l' instruction switch .

LISTE 10.4 Utilisation de l' instruction switch

1 : /* 10L04.c Utilisation de l'instruction switch */ 2 :


#include <stdio.h> 3 : 4 : main() 5 : { 6 :

int jour ;
Machine Translated by Google

Contrôle du déroulement du programme 163

7:
8: printf("Veuillez saisir un seul chiffre pour un jour\n"); printf("(entre
9: 1 et 3):\n"); jour = getchar(); switch (jour){ case '1' :
10 :
11 :
12 :
13 : printf("Jour 1\n"); cas
14 : '2' :
15 : printf("Jour 2\n"); cas
16 : '3' :
17 : printf("Jour 3\n"); défaut:
18 :
19 : ;
20 :
21 : } renvoie 0 ;
22 : }

dix
Si je lance le fichier exécutable 10L04.exe et que j'entre 3, j'obtiens le résultat suivant :

Veuillez entrer un seul chiffre pour un jour (entre


SORTIR 1 et 3) : 3

Jour 3

Comme vous pouvez le voir à la ligne 6, une variable int , day, est déclarée ; on lui affecte l'entrée saisie par
UNE ANALYSE
l'utilisateur à la ligne 10.

À la ligne 11, la valeur de la variable entière day est évaluée dans l' instruction switch . Si la valeur est égale à l'une
des valeurs des expressions constantes, l'ordinateur commence à exécuter des instructions à partir de là. Les
expressions constantes sont étiquetées en préfixant la casse devant elles.

Par exemple, j'ai entré 3 , puis j'ai appuyé sur la touche Entrée. La valeur numérique de 3 est affectée au jour
à la ligne 10. Ensuite, après avoir trouvé un cas dans lequel la valeur de l'expression constante correspond à la
valeur contenue par jour, l'ordinateur saute à la ligne 17 pour exécuter la fonction printf() et afficher Jour 3 à l'écran.

Notez que sous l' étiquette par défaut du Listing 10.4, il y a une instruction vide (c'est­à­dire nulle) se terminant par
un point­virgule à la ligne 19. L'ordinateur ne fait rien avec l'instruction vide. Cela signifie que si aucune des
expressions constantes ne s'applique, l' instruction switch finit par ne rien faire du tout.

Cependant, si j'entre 1 sur mon clavier et que j'appuie sur la touche Entrée lors de l'exécution du fichier
exécutable 10L04.exe, j'obtiens le résultat suivant :

Veuillez entrer un seul chiffre pour un jour


Machine Translated by Google

164 Heure 10

(dans la plage de 1 à 3) : 1

Jour 1
Jour 2
Jour 3

À partir de la sortie, vous pouvez voir que l'instruction contrôlée par le cas sélectionné, le cas 1, et les
instructions contrôlées par le reste des cas, sont exécutées, car Jour 1, Jour 2 et Jour 3 sont affichés à
l'écran. De même, si j'entre 2 à partir de mon clavier, j'ai Jour 2 et Jour 3 affichés à l'écran.

Il s'agit d'une caractéristique importante de l' instruction switch : l'ordinateur continue d'exécuter les
instructions suivant le cas sélectionné jusqu'à la fin de l' instruction switch .

Vous allez apprendre comment quitter plus tôt l'exécution de l' instruction switch dans la section suivante.

La déclaration de rupture
Si vous souhaitez quitter complètement le commutateur après chaque étiquette de cas, vous pouvez
ajouter une instruction break à la fin de la liste d'instructions qui suit chaque étiquette de cas . L'
instruction break quitte simplement le commutateur et reprend l'exécution après la fin du bloc
d'instructions switch .

Le programme du Listing 10.5 ressemble à celui du Listing 10.4, mais cette fois, l' instruction break
est utilisée et les résultats sont différents.

LISTE 10.5 Ajout de l' instruction break

1 : /* 10L05.c Ajout de l'instruction break */ 2 : #include


<stdio.h> 3 : 4 : main() 5 : { 6 : 7 : 8 : 9 : 10 : 11 : 12 : 13 :
14 : 15h16h17h18h19h

int jour ;

printf("Veuillez saisir un seul chiffre pour un jour\n"); printf("(entre


1 et 7):\n"); jour = getchar(); switch (jour){ case '1' :

printf("Le jour 1 est dimanche.\n");


Pause; cas '2' :

printf("Le jour 2 est lundi.\n"); Pause;


cas '3' :

printf("Le jour 3 est mardi.\n");


Machine Translated by Google

Contrôle du déroulement du programme 165

20 : Pause;
21 : cas '4' :
22 : printf("Le jour 4 est mercredi.\n"); Pause;
23 : cas '5' :
24 :
25 : printf("Le jour 5 est jeudi.\n"); Pause;
26 : case '6' :
27 :
28 : printf("Le jour 6 est vendredi.\n");
29 : Pause; cas '7' :
30 :
31 : printf("Le jour 7 est samedi.\n"); Pause;
32 : défaut:
33 :
34 : printf("Le chiffre n'est pas compris entre 1 et 7.\n"); Pause;
35 :
36 :
37 : } renvoie 0 ;
dix
38 : }

Avec l'aide de l' instruction break , je peux exécuter le fichier exécutable 10L05.exe et obtenir uniquement la sortie du
cas sélectionné :

Veuillez entrer un seul chiffre pour un jour (entre


SORTIR 1 et 7) : 1 Le jour 1 est dimanche.

UNE ANALYSE
Ce programme a sept étiquettes de cas suivies des expressions constantes de
'1', '2', '3', '4', '5', '6' et '7', respectivement. (Voir les lignes 12, 15, 18, 21, 24, 27
et 30.)

Dans chaque cas, il y a une instruction suivie d'une instruction break . Comme mentionné, les instructions break
quitteront la construction switch avant que l'ordinateur n'atteigne l'étiquette de cas suivante et les instructions qui la
suivent.

Par exemple, une fois que la variable int day a reçu la valeur 1 et a été évaluée dans l' instruction switch , le cas
avec '1' est sélectionné et l'instruction de la ligne 13 est exécutée.
Ensuite, l' instruction break de la ligne 14 est exécutée, ce qui interrompt le contrôle de l' instruction switch et renvoie
le contrôle à l'instruction suivante en dehors de la construction switch . Dans

Listing 10.5, l'instruction suivante est l' instruction return de la ligne 37, qui termine la fonction main .

L' appel printf() de la ligne 13 génère une chaîne indiquant que le jour 1 est dimanche. sur l'écran.

Notez que dans une instruction switch , les accolades ne sont pas nécessaires pour regrouper les instructions dans un
cas individuel, car case n'est qu'une étiquette et ne contrôle pas les instructions qui la suivent. Ils sont simplement
exécutés dans l'ordre, en commençant par l'étiquette.
Machine Translated by Google

166 Heure 10

Briser une boucle infinie


Vous pouvez également utiliser l' instruction break pour rompre une boucle infinie. Une boucle
infinie est une boucle dans laquelle l'expression conditionnelle est entièrement omise ; c'est donc
au code à l'intérieur de la boucle de déterminer les conditions de fin de boucle. Voici des exemples
de boucles for et while infinies :
pour (;;)
{ instruction1 ;
instruction2 ;
.
.
.
}

tandis
que
{ instruction1 ; instruction2 ;
.
.
.
}

La boucle for ci­dessus omet les trois expressions. Ainsi, l' instruction for exécute toujours la
boucle. L' instruction while utilise 1 comme expression conditionnelle, et comme cela n'est bien
sûr jamais évalué à 0, l'instruction while continue toujours la boucle.

Le programme du Listing 10.6 montre un exemple d'utilisation de l' instruction break dans
une boucle while infinie .

LISTE 10.6 Casser une boucle infinie

1 : /* 10L06.c : Casser une boucle infinie */ 2 : #include


<stdio.h> 3 : 4 : main() 5 : { 6 :

entier c ;
7:
8: printf("Entrez un caractère :\n(entrez x pour quitter)\n"); tandis que
9: { c = getc(stdin); si (c == 'x') pause ;
10 :
11 :
12 :
13 :
14 : } printf("Brise la boucle while infinie. Au revoir !\n"); renvoie 0 ;
15 :
16 : }
Machine Translated by Google

Contrôle du déroulement du programme 167

Voici le résultat que j'ai obtenu après avoir exécuté le fichier exécutable (10L06.exe) sur ma
machine :

Entrez un caractère : (entrez


SORTIR x pour quitter)
H
je

X
Cassez la boucle while infinie. Au revoir!

Il existe une boucle while infinie dans le Listing 10.6, qui commence à la ligne 9 et se termine
UNE ANALYSE
à la ligne 13. Dans la boucle infinie, les caractères saisis par l'utilisateur sont affectés,
un à la fois, à la variable entière c (voir ligne 10.)

L'expression relationnelle c == 'x' dans l' instruction if (voir ligne 11) est évaluée à chaque fois
pendant la boucle. Si l'expression donne la valeur 0 (c'est­à­dire que l'utilisateur n'a pas saisi la lettre
x), la boucle se poursuit. Sinon, l' instruction break de la ligne 12 est exécutée, ce qui fait que l'ordinateur
dix
saute hors de la boucle infinie et commence à exécuter l'instruction suivante, qui est montrée à la ligne
14.

Vous pouvez voir dans l'exemple de sortie, la boucle while se poursuit jusqu'à ce que j'aie entré la lettre
x, ce qui provoque la rupture de la boucle infinie et un message, Break the Infinity while loop. Bye!, à
afficher à l'écran.

La déclaration continue
Au lieu de casser une boucle, il y a des moments où vous voulez rester dans une boucle mais ignorer
certaines instructions dans la boucle. Pour ce faire, vous pouvez utiliser l' instruction continue . L'
instruction continue fait sauter immédiatement l'exécution au bas de la boucle.

Par exemple, le Listing 10.7 montre comment utiliser l' instruction continue dans une boucle faisant
des sommes.

LISTE 10.7 Utilisation de l' instruction continue

1 : /* 10L07.c : Utilisation de l'instruction continue */ 2 : #include <stdio.h>


3 : 4 : main() 5 : { 6 : 7 :

int je, somme ;

somme =
0 ; for (i=1; i<8; i++){ if ((i==3) ||
(i==5)) continuer ;
8 : 9 : 10 : 11 :

continue
Machine Translated by Google

168 Heure 10

LISTE 10.7 suite

12 : somme += je ;
13 :
14 : } printf("La somme de 1, 2, 4, 6 et 7 est : %d\n", somme); renvoie 0 ;
15 :
16 : }

Une fois le fichier exécutable 10L07.exe exécuté sur mon ordinateur, la sortie suivante s'affiche
à l'écran :

La somme de 1, 2, 4, 6 et 7 est : 20
SORTIR

Dans le Listing 10.7, nous voulons calculer la somme des valeurs entières de 1, 2, 4, 6 et
UNE ANALYSE
7. Comme les entiers sont presque consécutifs, une boucle for est construite aux lignes 9–
13. L'instruction de la ligne 12 additionne tous les entiers consécutifs de 1 à 7 (à l'exception de 3 et
5, qui ne figurent pas dans la liste et sont ignorés dans la boucle for ).

Pour sauter ces deux nombres, l'expression (i==3) || (i==5) est évalué dans l' instruction if de la
ligne 10. Si l'expression est évaluée à 1 (c'est­à­dire que la valeur de i est égale à 3 ou 5), l'
instruction continue de la ligne 11 est exécutée, ce qui provoque l'opération de somme de la ligne 12
doit être ignorée et une autre itération doit être lancée à l' instruction for . De cette façon, vous
obtenez la somme des valeurs entières de 1, 2, 4, 6 et 7, mais sautez 3 et 5, automatiquement en
utilisant une boucle for .

Après la boucle for , la valeur de sum, 20, est affichée à l'écran par l' appel printf() dans l'instruction
de la ligne 14.

La déclaration goto
Ce livre ne serait pas complet sans mentionner l' instruction goto , bien que je ne vous recommande
pas d'utiliser l' instruction goto . La principale raison pour laquelle l' instruction goto est déconseillée
est que son utilisation risque de rendre le programme C peu fiable et difficile à déboguer.

Les programmeurs sont souvent tentés d'utiliser l' instruction goto , surtout s'ils ont utilisé d'autres
langages sans le riche ensemble d'instructions de branchement conditionnel structuré fournies par
C. Le fait est que toute utilisation de goto peut être entièrement évitée en utilisant les autres
instructions de branchement.

Si rien d'autre, vous devez savoir ce qu'est une instruction goto afin que vous puissiez correctement grincer des
dents lorsque vous en voyez une dans le code de quelqu'un d'autre.
Machine Translated by Google

Contrôle du déroulement du programme 169

Voici la forme générale de l' instruction goto :


nom de l'étiquette:

instruction1 ;
instruction2 ;
.
.
.
aller au nom de l'étiquette ;

Ici labelname est un nom d'étiquette qui indique à l' instruction goto où sauter. Vous devez
placer labelname à deux endroits : l'un est à l'endroit où l' instruction goto va sauter (notez
qu'un deux­points doit suivre le nom de l'étiquette), et l'autre est l'endroit suivant le mot­clé
goto .

L'étiquette de l' instruction goto vers laquelle sauter peut apparaître avant ou après l'instruction.
dix
L'une des meilleures choses à propos du C est qu'il encourage la programmation
structurée. Les programmes doivent agir de manière prévisible et leur comportement doit
être raisonnablement évident à la simple lecture du code source.
Bien sûr, l'un des autres avantages du C est que le langage lui­même n'applique pas
cet idéal. C'est à vous, le programmeur, d'utiliser les outils qui vous sont donnés pour
écrire un code propre, élégant, lisible et structuré.
Dans ce chapitre, nous avons vu les instructions break, continue et goto.
L'utilisation inappropriée de ces instructions de branchement peut conduire à ce que l'on
appelle le "code spaghetti". (Si vous imprimez le code source et dessinez des flèches sur
la page pour indiquer le flux d'exécution, vous vous retrouverez avec un dessin de
spaghetti.) Lorsque l'exécution d'un programme saute de manière imprévisible, cela le
rend très difficile (ou pour un grand projet complexe, souvent presque impossible) pour
déterminer le comportement prévu ou réel d'un pro
gramme.

L'utilisation de l'instruction goto peut facilement conduire à du code spaghetti, en particulier


si elle est utilisée pour revenir en arrière ou sortir d'instructions de contrôle de flux. Lorsque
vous voyez une étiquette aléatoire juste là dans le code, vous savez seulement qu'un autre
code va y sauter en utilisant goto ­ vous ne savez tout simplement pas quand ni pourquoi,
sans vous arrêter pour rechercher le reste de la fonction.
Les effets de l'instruction continue, au moins, sont limités à l'instruction de bouclage où
elle est utilisée. Cependant, les boucles complexes peuvent être difficiles à déchiffrer à
moins que vous ne sachiez exactement quand et pourquoi la boucle se terminera.
Il en va de même pour la pause. Outre les instructions switch, il peut être utilisé pour
sauter hors des boucles for, while ou do­while. Généralement, cela ne devrait être utilisé
que pour sortir d'une boucle infinie. Sinon, utilisez votre expression conditionnelle pour
terminer la boucle.
Machine Translated by Google

170 Heure 10

Résumé
Dans cette leçon, vous avez appris les déclarations et mots­clés importants suivants pour le branchement
conditionnel et le bouclage en C :

• Une tâche importante d'un programme est de demander à l'ordinateur de sauter à différents
parties du code selon les conditions de branche spécifiées.

• L' instruction if est une instruction très importante pour le branchement conditionnel en C. • L'

instruction if peut être imbriquée pour prendre une série de décisions liées dans votre
programme.

• L' instruction if­else est une extension de l' instruction if . • L' instruction

switch vous aide à rendre votre programme plus lisible lorsqu'il y a plus que quelques décisions liées à
prendre dans votre code. • Le mot­clé case , suivi de deux­points et d'une valeur constante intégrale,

est utilisé comme étiquette dans l' instruction switch . Par défaut : l' étiquette est utilisée à la fin d'un
commutateur

lorsqu'aucun cas ne s'applique à la condition.

• L' instruction break peut être utilisée pour quitter la construction switch ou une boucle (généralement, une
boucle infinie).

• L' instruction continue est utilisée pour vous permettre de rester dans une boucle tout en sautant
quelques déclarations.

• L' instruction goto permet à l'ordinateur de sauter à un autre endroit de votre


code. L'utilisation de cette instruction n'est pas recommandée car elle peut rendre votre programme peu
fiable et difficile à déboguer.

Dans la leçon suivante, vous découvrirez un concept très important : les pointeurs.

Questions et réponses

Q Combien d'expressions y a­t­il dans l' instruction if ?

R L' instruction if n'accepte qu'une seule expression pour contenir les critères conditionnels. Lorsque
l'expression donne une valeur différente de zéro (c'est­à­dire que les conditions sont remplies), les
instructions contrôlées par l' instruction if sont exécutées. Sinon, ces instructions sont ignorées et
l'instruction suivante suivant le bloc d'instructions if est exécutée.

Q Pourquoi l' instruction if­else est­elle une extension de l' instruction if ?

A Lorsque l'expression conditionnelle de l' instruction if donne la valeur zéro,


le flux de contrôle du programme revient à la piste d'origine. Cependant, lorsque l'expression
conditionnelle dans l' instruction if­else est évaluée à zéro, le flux de contrôle du programme se branche
sur le bloc d'instructions sous le mot­clé else et renvoie
Machine Translated by Google

Contrôle du déroulement du programme 171

à sa piste d'origine après l'exécution des instructions contrôlées par else . En d'autres termes, l'
instruction if permet d'exécuter ou d'ignorer entièrement un seul bloc d'instructions, tandis que l'
instruction if­else exécute l'un des deux blocs d'instructions sous le contrôle de l' instruction if­else .

Q Pourquoi avez­vous normalement besoin d'ajouter l' instruction break dans le commutateur
déclaration?

A Lorsque l'un des cas dans l' instruction switch est sélectionné, le contrôle du programme se branche sur
le cas et exécute toutes les instructions dans le cas sélectionné et le

reste des cas qui le suivent. Par conséquent, vous pourriez obtenir plus de résultats que prévu.
Pour indiquer à l'ordinateur d'exécuter uniquement les instructions à l'intérieur d'un cas
sélectionné, vous pouvez placer une instruction break à la fin du cas afin que le flux de contrôle
du programme quitte la construction switch après que les instructions dans le cas sont
réalisé. dix
Q Que peut faire l' instruction continue dans une boucle ?

A Lorsque l' instruction continue à l' intérieur d'une boucle est exécutée, le contrôle du programme est
branché à la fin de la boucle afin que l'instruction de contrôle while ou for puisse être exécutée et
qu'une autre itération puisse être lancée si l'expression conditionnelle est toujours valable. À l'intérieur
de la boucle, toutes les instructions suivant l' instruction continue seront ignorées à chaque exécution
de l'instruction continue .

Atelier
Pour aider à consolider votre compréhension de la leçon de cette heure, nous vous encourageons à répondre
aux questions du quiz et à terminer les exercices fournis dans l'atelier avant de passer à la leçon suivante.
Les réponses et les conseils aux questions et exercices sont donnés dans l'annexe B, « Réponses aux
questions et exercices du quiz ».

Questionnaire

1. Étant donné x = 0, les opérations arithmétiques à l'intérieur de l' instruction if suivante seront ­elles
effectué ? si
(x != 0) y =
123 / x + 456 ;

2. Étant donné x = 4, y = 2 et opérateur = '­', quelle est la valeur finale de x après le


l'instruction switch suivante est exécutée ?
commutateur (opérateur){
cas '+' : x += y ; cas
'­' : x ­= y ; cas '*' : x
*= y;
Machine Translated by Google

172 Heure 10

case '/' : x /= y ; par


défaut : pause ;
}

3. Semblable à la question 2, en utilisant x = 4, y = 2 et operator = '­', quelle est la valeur finale de x


après l' exécution de l'instruction switch suivante ? switch (opérateur){ case '+' : x += y ; Pause;
cas '­' : x ­= y ; Pause; cas '*' : x *= y; Pause; case '/' : x /= y ; Pause; par défaut : pause ;

4. Quelle est la valeur de la variable entière x après l'exécution du code suivant ?

x=1;
for (i=2; i<10; i++){ if (i%3
== 0) continue ; x +=
je ;

Des exercices
1. Réécrivez le programme du Listing 10.1. Cette fois, utilisez l'expression logique i%6 ==
0 dans l' instruction if .

2. Réécrivez le programme du Listing 10.1 en utilisant des instructions if imbriquées .

3. Écrivez un programme pour lire des caractères à partir des E/S standard. Si les caractères sont A, B
et C, affichez leurs valeurs numériques à l'écran. (L' instruction switch est obligatoire.)

4. Écrivez un programme qui continue à lire les caractères de l'entrée standard jusqu'à ce que le
caractère q soit entré.

5. Réécrivez le programme du Listing 10.7. Cette fois, au lieu de sauter 3 et 5, sautez


le nombre entier qui peut être divisé à la fois par 2 et 3.
Machine Translated by Google

PARTIE III

Pointeurs et tableaux
Heure
11 Comprendre les pointeurs

12 Comprendre les tableaux

13 Manipulation des chaînes

14 Présentation de la portée et des classes de stockage


Machine Translated by Google
Machine Translated by Google

HEURE 11
Comprendre les pointeurs
Les devoirs du pointeur étaient de désigner, en appelant leurs noms, ceux de la congrégation
qui devraient prendre note d'un point soulevé dans le sermon.

—HB Otis, Simple Vérité

Vous avez découvert de nombreux types de données, opérateurs, fonctions et boucles C importants
au cours des 10 dernières heures. Dans cette leçon, vous découvrirez l'une des fonctionnalités les
plus importantes et les plus puissantes des pointeurs C:. Les sujets abordés pendant cette heure
sont

• Variables de pointeur

• Les adresses mémoire •

Le concept d'indirection • La

déclaration d'un pointeur • L'opérateur

d'adresse de • L'opérateur de

déréférencement

Plus d'exemples d'application de pointeurs seront démontrés dans les prochaines heures du livre,
en particulier dans l'heure 16, "Applying Pointers".
Machine Translated by Google

176 Heure 11

Qu'est­ce qu'un pointeur ?


Comprendre les pointeurs est essentiel pour être un programmeur C efficace. Jusqu'à présent, vous ne traitiez
directement que les variables, en leur attribuant des valeurs. Cette heure introduit un nouveau concept, connu
sous le nom d' indirection.

Au lieu d'attribuer des valeurs directement aux variables, vous pouvez manipuler indirectement une variable
en créant une variable appelée pointeur, qui contient l'adresse mémoire d'une autre variable.

Alors, pourquoi est­ce si important ? Pour commencer, utiliser l'adresse mémoire de vos données est souvent
le moyen le plus rapide et le plus simple d'y accéder. Il y a beaucoup de choses qui sont difficiles, voire
carrément impossibles, à faire sans pointeurs, comme l'allocation dynamique de mémoire, la transmission de
grandes structures de données entre les fonctions, voire la communication avec le matériel de votre ordinateur.

En fait, vous avez déjà utilisé un pointeur — dans l'heure 1, de ce livre « Faire le premier pas » ! Vous
souvenez­vous de la chaîne « Salut, voisin ! C'est mon premier programme C.\n" ? Une chaîne est en
fait un tableau, qui est lui­même une sorte de pointeur.

Il y a beaucoup plus de discussions plus loin dans ce livre sur les tableaux, l'allocation de mémoire et les
merveilleuses choses que vous pouvez faire avec les pointeurs. Pour l'instant, la première étape consiste à
comprendre ce qu'est un pointeur et comment l'utiliser dans vos programmes.

D'après la définition d'un pointeur, vous savez deux choses : premièrement, qu'un pointeur est une variable,
vous pouvez donc affecter différentes valeurs à une variable de pointeur, et deuxièmement, que la valeur
contenue par un pointeur doit être une adresse qui indique la emplacement d'une autre variable dans la
mémoire. C'est pourquoi un pointeur est aussi appelé une variable d'adresse.

Adresse (valeur de gauche) versus contenu (droite


Évaluer)
Comme vous le savez peut­être, la mémoire de votre ordinateur est utilisée pour contenir le code binaire de
votre programme, composé d'instructions et de données, ainsi que le code binaire du système d'exploitation
de votre machine.

Chaque emplacement mémoire doit avoir une adresse unique afin que l'ordinateur puisse lire ou écrire dans
l'emplacement mémoire sans aucune confusion. Ceci est similaire au concept selon lequel chaque maison
dans une ville doit avoir une adresse unique.

Lorsqu'une variable est déclarée, un morceau de mémoire inutilisé sera réservé pour la variable, et
l'adresse unique de la mémoire sera associée au nom de la variable. L'adresse associée au nom de la
variable est généralement appelée la valeur de gauche de la variable.
Machine Translated by Google

Comprendre les pointeurs 177

Ensuite, lorsqu'une valeur est affectée à la variable, la valeur est stockée dans l'emplacement de mémoire réservé
en tant que contenu. Le contenu est aussi appelé la bonne valeur de la variable.

Par exemple, une fois que la variable entière x est déclarée et affectée à une valeur comme celle­ci :

entier
x;x=7;

la variable x a maintenant deux valeurs :

Valeur de gauche : 1000

Valeur correcte : 7

Ici, la valeur de gauche, 1000, est l'adresse de l'emplacement mémoire réservé pour x. La bonne valeur, 7, est le
contenu stocké dans l'emplacement mémoire. Notez que selon les ordinateurs et les systèmes d'exploitation, la
valeur de gauche de x peut être différente d'une machine à l'autre.

Vous pouvez imaginer que la variable x est la boîte aux lettres devant votre maison, qui a l'adresse (normalement
le numéro de la rue) 1000. La bonne valeur, 7, peut être considérée comme une lettre livrée à la boîte aux lettres.

Notez que lorsque votre programme C est compilé et qu'une valeur est affectée à une variable, le compilateur
C doit vérifier la valeur de gauche de la variable. Si le compilateur ne trouve pas la valeur de gauche, il émettra un
11
message d'erreur indiquant que la variable n'est pas définie dans votre programme. C'est pourquoi, en C, vous devez
déclarer une variable avant de pouvoir l'utiliser.
(Imaginez un facteur se plaignant de ne pas pouvoir déposer les lettres qui vous sont adressées parce que vous
n'avez pas encore construit de boîte aux lettres.)

En utilisant la valeur de gauche d'une variable, le compilateur C peut facilement localiser le stockage de mémoire
approprié réservé à une variable, puis lire ou écrire la valeur de droite de la variable.

L'adresse de l'opérateur (&)


Le langage C vous fournit même un opérateur, &, au cas où vous voudriez connaître la valeur de gauche d'une
variable. Cet opérateur est appelé opérateur d'adresse de car il donne l'adresse (c'est­à­dire la valeur de gauche)
d'une variable.

Le code suivant, par exemple,

entier long x ;
entier long *y ;
y = &x;

affecte l'adresse de la variable entière longue x à une variable pointeur, y. (Plus d'informations à ce sujet et sur la
signification de *y seront discutées plus loin dans ce chapitre.)
Machine Translated by Google

178 Heure 11

Le Listing 11.1 montre un autre exemple d'obtention d'adresses (c'est­à­dire de valeurs de gauche)
de variables.

TAPER
LISTE 11.1 Obtention des valeurs de gauche des variables

1 : /* 11L01.c : Obtention d'adresses */ 2 : #include


<stdio.h> 3 : 4 : main() 5 : { 6 : 7 :

caractère
c ; entier
x ; flotter y ;

printf("c : adresse=%p, contenu=%c\n", &c, c); printf("x :


8 : 9 : 10 : 11adresse=%p,
: contenu=%d\n", &x, x); printf("y : adresse=%p,
12 : contenu=%5.2f\n", &y, y); c = 'A' ; x = 7 ; y = 123,45 ; printf("c :
13: adresse=%p, contenu=%c\n", &c, c); printf("x : adresse=%p,
14: contenu=%d\n", &x, x); printf("y : adresse=%p, contenu=%5.2f\n",
&y, y); renvoie 0 ;

15 : 16 : 17 :
18 :
19 :
20 : }

Une fois le fichier exécutable (11L01.exe) de ce programme créé et exécuté sur mon ordinateur, la sortie
suivante s'affiche à l'écran :

Vous pouvez obtenir des résultats différents, en fonction de votre ordinateur et de votre
système d'exploitation, et en particulier en fonction de la situation de la mémoire de votre
ordinateur lorsque vous exécutez le programme.

c : adresse=0x1AF4, contenu=@ x :
SORTIR
adresse=0x1AF2, contenu=­32557 y :
adresse=0x1AF6, contenu=0.00 c :
adresse=0x1AF4, contenu=A x :
adresse=0x1AF2, contenu=7 y : adresse=
0x1AF6, contenu=123,45

UNE ANALYSE
Comme vous pouvez le voir dans le Listing 11.1, il y a trois variables, c, x et y, déclarées
respectivement aux lignes 6 à 8.
Machine Translated by Google

Comprendre les pointeurs 179

L'instruction de la ligne 10 affiche l'adresse (c'est­à­dire la valeur de gauche) et le contenu (c'est­à­dire


la valeur de droite) de la variable de caractère c à l'écran. Ici, l' expression &c produit l'adresse de c.

Notez que le spécificateur de format %p est utilisé dans la fonction printf() de la ligne 10 pour afficher
l'adresse produite par &c.

De même, les lignes 11 et 12 impriment les adresses de x et y, ainsi que le contenu de x et y. Dans la
première partie de la sortie, vous voyez que les adresses de c, x et y sont 0x1AF4, 0x1AF2 et 0x1AF6.
Mon ordinateur a imprimé ces adresses au format hexadécimal.
Cependant, le spécificateur de format %p ne garantit pas l'impression des adresses au format
hexadécimal, juste pour convertir les adresses en une séquence de caractères imprimables. Vous
devriez consulter le manuel de votre compilateur C pour savoir à quel format vous attendre. Comme ces
trois variables n'ont pas encore été initialisées, le contenu contenu dans leurs emplacements mémoire
y est laissé depuis la dernière écriture en mémoire.

Cependant, après les initialisations effectuées aux lignes 13 à 15, les emplacements mémoire
réservés aux trois variables ont le contenu des valeurs initiales. Lignes 16 à 18 dis
lire les adresses et le contenu de c, x et y après l'initialisation.

Vous pouvez voir dans la deuxième partie de la sortie, le contenu de c, x et y sont maintenant 'A', 7 11
et 123.45, respectivement, avec les mêmes adresses mémoire.

Le spécificateur de format %p utilisé dans la fonction printf() est pris en charge par la norme
ANSI. Si, d'une manière ou d'une autre, votre compilateur ne prend pas en charge %p, vous
pouvez essayer d'utiliser %u ou %lu dans la fonction printf() pour convertir et imprimer une valeur
de gauche (c'est­à­dire une adresse).

De plus, les adresses imprimées par les exemples de cette leçon sont obtenues en exécutant les
exemples sur ma machine. Les valeurs peuvent être différentes de ce que vous pouvez obtenir
en exécutant les exemples sur votre machine. En effet, l'adresse d'une variable peut varier d'un
type d'ordinateur à l'autre.

Déclarer des pointeurs


Comme mentionné au début de cette leçon, un pointeur est une variable, ce qui signifie qu'un pointeur
a une valeur gauche et une valeur droite également. Cependant, les valeurs de gauche et de droite sont
des adresses. La valeur de gauche d'un pointeur est utilisée pour faire référence au pointeur lui­même,
tandis que la valeur de droite d'un pointeur, qui est le contenu du pointeur, est l'adresse d'une autre
variable.
Machine Translated by Google

180 Heure 11

La forme générale d'une déclaration de pointeur est

type de données *nom­pointeur ;

Ici data­type spécifie le type de données vers lequel pointe le pointeur. nom­pointeur est le nom de la
variable pointeur, qui peut être n'importe quel nom de variable valide en C.

Notez que juste avant le nom du pointeur se trouve un astérisque *, qui indique que la variable est un
pointeur. Lorsque le compilateur voit l'astérisque dans la déclaration, il note que la variable peut être
utilisée comme pointeur.

Voici différents types de pointeurs :


char *ptr_c; /* déclare un pointeur sur un caractère */

entier *ptr_int; /* déclarer un pointeur sur un entier */

flottant *ptr_flt ; /* déclare un pointeur sur un flottant */

Le programme du Listing 11.2 montre comment déclarer des pointeurs et leur affecter des valeurs.

TAPER
LISTE 11.2 Déclarer et attribuer des valeurs aux pointeurs

1 : /* 11L02.c : déclarer et affecter des valeurs aux pointeurs */ 2 : #include <stdio.h>


3 : 4 : main() 5 : { 6 : 7 :

char c, *ptr_c; entier x,


*ptr_x ; float y, *ptr_y ;

c = 'A' ; x
8 : 9 : 10 : 11=: 7
;y=
12 : 123,45 ;
13: printf("c : adresse=%p, contenu=%c\n", &c, c); printf("x :
14: adresse=%p, contenu=%d\n", &x, x); printf("y : adresse=%p,
contenu=%5.2f\n", &y, y); ptr_c = &c; printf(“ptr_c : adresse=%p,
contenu=%p\n", &ptr_c, ptr_c); printf("*ptr_c => %c\n", *ptr_c); ptr_x =
15 : 16 : 17 : &x; printf("ptr_x : adresse=%p, contenu=%p\n", &ptr_x, ptr_x); printf("*ptr_x =>
%d\n", *ptr_x); ptr_y = &y; printf("ptr_y : adresse=%p, contenu=%p\n", &ptr_y, ptr_y);
printf("*ptr_y => %5.2f\n", *ptr_y); renvoie 0 ;

18h19h20h21h
22:
23:
24:
25 :
26 : }
Machine Translated by Google

Comprendre les pointeurs 181

J'obtiens la sortie suivante affichée à l'écran après avoir exécuté le fichier exécutable
11L02.exe depuis ma machine :
c : adresse=0x1B38, contenu=A
SORTIR x : adresse=0x1B36, contenu=7 y :
adresse=0x1B32, contenu=123,45 ptr_c :
adresse=0x1B30, contenu=0x1B38 *ptr_c =>
A ptr_x : adresse=0x1B2E, contenu=0x1B36
*ptr_x => 7 ptr_y : adresse=0x1B2C,
contenu=0x1B32 *ptr_y => 123,45

UNE ANALYSE
Dans le Listing 11.2, il y a trois variables, c, x et y, et trois variables de pointeur, ptr_c, ptr_x
et ptr_y, déclarées respectivement aux lignes 6 à 8.

Les instructions des lignes 10 à 12 initialisent les trois variables c, x et y. Ensuite, les lignes 13 à 15
impriment les adresses ainsi que le contenu des trois variables.

A la ligne 16, la valeur de gauche de la variable caractère c est affectée à la variable pointeur
ptr_c. La sortie faite par l'instruction de la ligne 17 montre que la variable de pointeur ptr_c contient
l'adresse de c. En d'autres termes, le contenu (c'est­à­dire la valeur de droite) de ptr_c est l'adresse
(c'est­à­dire la valeur de gauche) de c. 11
Ensuite, à la ligne 18, la valeur référencée par le pointeur *ptr_c est imprimée. La sortie prouve
que le pointeur *ptr_c pointe vers l'emplacement mémoire de c.

La ligne 19 affecte la valeur de gauche de l'entier x à la variable de pointeur d'entier ptr_x. Les
instructions des lignes 20 et 21 impriment la valeur gauche et la valeur droite de la variable de
pointeur ptr_x, ainsi que la valeur référencée par le pointeur *ptr_x.

De même, la valeur de gauche de la variable flottante y est affectée à la variable de pointeur


flottant ptr_y à la ligne 22. Pour prouver que ptr_y contient l'adresse de y, et que *ptr_y donne le
contenu contenu par y, les lignes 23 et 24 impriment le les bonnes valeurs de ptr_y et *ptr_y, respectivement.

Les instructions des lignes 16, 19 et 22 vous montrent comment affecter la valeur d'une variable à
une autre, de manière indirecte. En d'autres termes, la valeur gauche d'une variable peut être
affectée à une autre variable afin que cette dernière puisse être utilisée comme variable pointeur
pour obtenir la valeur droite de la première. Dans ce cas, le nom de la variable et le pointeur font
référence au même emplacement mémoire. Par conséquent, si le nom de la variable ou le pointeur
est utilisé dans une expression pour modifier le contenu de l'emplacement mémoire, le contenu de
l'emplacement mémoire a également changé pour l'autre.

Pour vous aider à comprendre l'indirection de l'attribution de valeurs, la figure 11.1 montre l'image
mémoire des relations entre c et ptr_c, x et ptr_x, et y et ptr_y, sur la base de la sortie obtenue sur
ma machine.
Machine Translated by Google

182 Heure 11

FIGURE 11.1 .
.
L'image mémoire des
.
variables et leur ptr_y 0x1B2C
pointeurs. 0x1B32
ptr_x 0x1B2E

0x1B36
ptr_c 0x1B30 *ptr_y

0x1B38
Oui 0x1B32
*ptr_x
123,45
X
0x1B36

7 *ptr_c
c 0x1B38
'UN'

.
.
.

L'opérateur de déréférencement (*)


Vous avez vu l'astérisque (*) dans la déclaration d'un pointeur. En C, l'astérisque est appelé
opérateur de déréférencement lorsqu'il est utilisé comme opérateur unaire. (Parfois, on l'appelle
aussi l' opérateur d'indirection.) La valeur d'une variable peut être référencée par la combinaison
de l' opérateur * et de son opérande, qui contient l'adresse de la variable.

Par exemple, dans le programme présenté dans le Listing 11.2, après que l'adresse de la
variable caractère c est assignée à la variable pointeur ptr_c, l'expression *ptr_c fait référence à
la valeur contenue par c. Par conséquent, vous pouvez utiliser l' expression *ptr_c , au lieu d'utiliser
directement la variable c , pour obtenir la valeur de c.

De même, étant donné une variable entière x et x = 1234, vous pouvez déclarer une variable de
pointeur entier, ptr_x, par exemple, et affecter la valeur gauche (adresse) de x à ptr_x, c'est­à­
dire ptr_x = &x. Ensuite, l'expression *ptr_x produit 1234, qui est la bonne valeur (contenu) de x.

Ne confondez pas l'opérateur de déréférencement avec l'opérateur de multiplication,


bien qu'ils partagent le même symbole, *.
L' opérateur de déréférencement est un opérateur unaire, qui ne prend qu'un
seul opérande. L'opérande contient l'adresse (c'est­à­dire la valeur de gauche) d'une variable.
D'autre part, l' opérateur de multiplication est un opérateur binaire qui nécessite deux
opérandes pour effectuer l'opération de multiplication.
La signification du symbole * est déterminée par le contexte dans lequel vous l'utilisez.
Machine Translated by Google

Comprendre les pointeurs 183

Pointeurs nuls
Un pointeur est dit pointeur nul lorsque sa valeur droite est 0. N'oubliez pas qu'un pointeur nul ne peut jamais pointer
vers des données valides. Pour cette raison, vous pouvez tester un pointeur pour voir s'il est affecté à 0 ; si c'est le cas,
vous savez qu'il s'agit d'un pointeur nul et qu'il n'est pas valide.

Pour définir un pointeur nul, affectez simplement 0 à la variable de pointeur. Par example:

char *ptr_c;
entier *ptr_int;

ptr_c = ptr_int = 0 ;

Ici , ptr_c et ptr_int deviennent des pointeurs nuls après que la valeur entière de 0 leur ait été affectée.

Vous verrez les applications des pointeurs nuls utilisés dans les instructions et les tableaux de flux de contrôle plus loin
dans ce livre.

Mise à jour des variables via des pointeurs


Comme vous l'avez appris dans la section précédente, tant que vous liez une variable à une variable pointeur, vous
pouvez obtenir la valeur de la variable en utilisant la variable pointeur. En d'autres termes, vous pouvez lire la valeur
11
en pointant sur l'emplacement mémoire de la variable et en utilisant l'opérateur de déréférencement.

Cette section vous montre que vous pouvez écrire une nouvelle valeur dans l'emplacement mémoire d'une variable à
l'aide d'un pointeur contenant la valeur gauche de la variable. Le Listing 11.3 montre un exemple.

TAPER LISTE 11.3 Modification des valeurs de variables via des pointeurs

1 : /* 11L03.c : Modification des valeurs via des pointeurs */


2 : #include <stdio.h> 3 : 4 : main() 5 : { 6 :

char c, *ptr_c;

c = 'A' ;
printf("c : adresse=%p, contenu=%c\n", &c, c); ptr_c = &c;
printf(“ptr_c : adresse=%p, contenu=%p\n", &ptr_c, ptr_c);
printf("*ptr_c => %c\n", *ptr_c); *ptr_c = 'B'; printf(“ptr_c : adresse=%p,
contenu=%p\n", &ptr_c, ptr_c);

7 : 8 : 9 : 10 : 11 : 12 : 13 : 14 :

continue
Machine Translated by Google

184 Heure 11

LISTE 11.3 suite

15 : printf("*ptr_c => %c\n", *ptr_c); printf("c :


16 : adresse=%p, contenu=%c\n", &c, c); renvoie 0 ;
17 :
18 : }

Après avoir exécuté le fichier exécutable 11L03.exe sur ma machine, j'obtiens la sortie suivante
affichée à l'écran :
c : adresse=0x1828, contenu=A
SORTIR ptr_c : adresse=0x1826, contenu=0x1828
*ptr_c => A ptr_c : adresse=0x1826,
contenu=0x1828 *ptr_c => B c :
adresse=0x1828, contenu=B

Une variable char , c, et une variable pointeur char , ptr_c, sont déclarées à la ligne 6 du
UNE ANALYSE
Listing 11.3.

La variable c est initialisée avec 'A' à la ligne 8, qui est imprimée, avec l'adresse de la variable,
par la fonction printf() à la ligne 9.

À la ligne 10, la variable de pointeur ptr_c reçoit la valeur de gauche (adresse) de c. Il n'est pas
surprenant de voir la sortie imprimée par les instructions des lignes 11 et 12, où la valeur droite de ptr_c
est la valeur gauche de c, et le pointeur *ptr_c pointe sur la valeur droite de c.

À la ligne 13, l'expression *ptr_c = 'B' demande à l'ordinateur d'écrire 'B' à l'emplacement pointé par
le pointeur ptr_c. La sortie imprimée par l'instruction à la ligne 15 prouve que le contenu de
l'emplacement mémoire pointé par ptr_c est mis à jour. L'instruction de la ligne 14 imprime les valeurs
gauche et droite de la variable de pointeur ptr_c et montre que ces valeurs restent les mêmes. Comme
vous le savez, l'emplacement pointé par ptr_c est celui où réside la variable caractère c . Par
conséquent, l'expression *ptr_c = 'B' met à jour le contenu (c'est­à­dire la bonne valeur) de la variable c
en 'B'. Pour le prouver, l'instruction de la ligne 16 affiche les valeurs gauche et droite de c à l'écran.
Effectivement, la sortie montre que la bonne valeur de c a été modifiée.

Pointant vers le même emplacement mémoire


Un emplacement mémoire peut être pointé par plus d'un pointeur. Par exemple, étant donné que
c = 'A' et que ptr_c1 et ptr_c2 sont deux variables de pointeur de caractère, ptr_c1 = &c et ptr_c2
= &c définissent les deux variables de pointeur pour qu'elles pointent vers le même emplacement
dans la mémoire.
Machine Translated by Google

Comprendre les pointeurs 185

Le programme du Listing 11.4 montre un autre exemple de pointage vers la même chose avec
plusieurs pointeurs.

LISTE 11.4 Pointer vers le même emplacement mémoire avec plusieurs pointeurs
TAPER

1 : /* 11L04.c : pointant vers la même chose */ 2 : #include


<stdio.h> 3 : 4 : main() 5 : { 6 : 7 :

entier
x ; entier *ptr_1, *ptr_2, *ptr_3 ;

x = 1234 ;
printf("x : adresse=%p, contenu=%d\n", &x, x); ptr_1 = &x;
8 : 9 : 10 : 11printf("ptr_1
: : adresse=%p, contenu=%p\n", &ptr_1, ptr_1);
12 :
13: printf("*ptr_1 => %d\n", *ptr_1); ptr_2 = &x;
14: printf("ptr_2 : adresse=%p, contenu=%p\n",
&ptr_2, ptr_2);
printf("*ptr_2 => %d\n", *ptr_2); ptr_3 =
15 : 16 : 17 ptr_1
: ; printf("ptr_3 : adresse=%p, contenu=%p\n",
&ptr_3, ptr_3);
11
printf("*ptr_3 => %d\n", *ptr_3); renvoie 0 ;

18h19h20h21h}

La sortie suivante s'affiche à l'écran en exécutant le fichier exécutable 11L04.exe sur ma machine
(notez que vous pouvez obtenir différentes valeurs d'adresse en fonction de votre système) :

x : adresse=0x1838, contenu=1234 ptr_1 :


SORTIR
adresse=0x1834, contenu=0x1838 *ptr_1 => 1234
ptr_2 : adresse=0x1836, contenu=0x1838 *ptr_2
=> 1234 ptr_3 : adresse=0x1832, contenu=0x1838
*ptr_3 => 1234

Comme indiqué dans le Listing 11.4, la ligne 6 déclare une variable entière, x, et
UNE ANALYSE
la ligne 7 déclare trois variables de pointeur entier, ptr_1, ptr_2 et ptr_3.

L'instruction de la ligne 10 imprime les valeurs gauche et droite de x. Sur ma machine, la valeur
gauche (adresse) de x est 0x1838. La bonne valeur (contenu) de x est 1234, qui est la valeur
initiale attribuée à x à la ligne 9
Machine Translated by Google

186 Heure 11

La ligne 11 affecte la valeur gauche de x à la variable de pointeur ptr_1 afin que ptr_1 puisse être utilisé pour faire
référence à la valeur droite de x. Pour vous assurer que la variable de pointeur ptr_1 contient maintenant l'adresse
de x, la ligne 12 imprime la valeur droite de ptr_1, ainsi que sa valeur gauche. La sortie montre que ptr_1 contient
l'adresse de x, 0x1838. Ensuite, la ligne 13 imprime la valeur 1234, qui est référencée par l' expression *ptr_1 .
Notez que l'astérisque * dans l'expression est l'opérateur de déréférencement

À la ligne 14, l' expression *ptr_2 = &x affecte la valeur gauche de x à une autre variable de pointeur, ptr_2 ; c'est­
à­dire que la variable de pointeur ptr_2 est maintenant liée à l'adresse de x. L'instruction de la ligne 16 affiche
l'entier 1234 à l'écran en utilisant l'opérateur de déréférencement * et son opérande, ptr_2. En d'autres termes,
l'emplacement mémoire de x est désigné par le second pointeur *ptr_2.

À la ligne 17, la variable de pointeur ptr_3 reçoit la bonne valeur de ptr_1. Comme ptr_1 contient maintenant
l'adresse de x, l'expression ptr_3 = ptr_1 est équivalente à ptr_3 = &x.
Ensuite, à partir de la sortie faite par les instructions des lignes 18 et 19, vous voyez à nouveau l'entier 1234
à l'écran. Cette fois, l'entier est référencé par le troisième pointeur, ptr_3.

Résumé
Dans cette leçon, vous avez appris les concepts très importants suivants sur les pointeurs en C :

• Un pointeur est une variable dont la valeur pointe vers une autre variable. • Une

variable déclarée en C a deux valeurs : la valeur de gauche et la valeur de droite. • La valeur de

gauche d'une variable est l'adresse ; la bonne valeur est le contenu de


la variable.

• L'opérateur d'adresse de (&) peut être utilisé pour obtenir la valeur gauche (adresse) de
une variable.

• L'astérisque (*) dans une déclaration de pointeur indique au compilateur que la variable est un
variable de pointeur.

• L'opérateur de déréférencement (*) est un opérateur unaire ; en tant que tel, il ne nécessite que
un opérande.

• L' expression *ptr_name est évaluée à la valeur pointée par la variable de pointeur
ptr_name, où ptr_name peut être n'importe quel nom de variable valide en C.

• Si la valeur droite de la variable de pointeur a reçu la valeur 0, le pointeur est un pointeur nul. Un pointeur
nul ne peut pas pointer vers des données valides.

• Vous pouvez mettre à jour la valeur d'une variable référencée par une variable pointeur.

• Plusieurs pointeurs peuvent pointer sur le même emplacement d'une variable dans la mémoire.
Machine Translated by Google

Comprendre les pointeurs 187

Vous verrez plus d'exemples d'utilisation des pointeurs dans le reste du livre.

Dans la leçon suivante, vous découvrirez un type d'agrégat, un tableau, qui est étroitement lié aux pointeurs en C.

Questions et réponses

Q Quelles sont les valeurs gauche et droite ?

A La valeur de gauche est l'adresse d'une variable et la valeur de droite est le contenu stocké
dans l'emplacement mémoire d'une variable. Il existe deux façons d'obtenir la bonne valeur d'une variable :
utiliser directement le nom de la variable ou utiliser la valeur de gauche de la variable et l'opérateur de
déréférencement pour faire référence à l'emplacement de la bonne valeur. La deuxième voie est aussi appelée
voie indirecte.

Q Comment obtenir l'adresse d'une variable ?

A En utilisant l'opérateur d'adresse, &. Par exemple, étant donné une variable entière x, l' expression &x s'évalue
à l'adresse de x. Pour imprimer l'adresse de x, vous pouvez utiliser le spécificateur de format %p dans la
fonction printf() .

Q Quel est le concept d'indirection en termes d'utilisation de pointeurs ?

R Avant cette heure, le seul moyen que vous connaissiez pour lire ou écrire dans une variable était d'invoquer
11
directement la variable. Par exemple, si vous vouliez écrire un nombre décimal, 16, dans une variable entière
x, vous pourriez utiliser l'instruction x = 16;.

Comme vous l'avez appris au cours de cette heure, C vous permet d'accéder à une variable d'une autre
manière, en utilisant des pointeurs. Par conséquent, pour écrire 16 dans x, vous pouvez d'abord déclarer un
pointeur entier (ptr) et affecter la valeur gauche (adresse) de x à ptr, c'est­à­dire ptr = &x;. Ensuite, au lieu
d'exécuter l'instruction x = 16;, vous pouvez utiliser une autre instruction :

*ptr = 16 ;
Ici, le pointeur *ptr fait référence à l'emplacement mémoire réservé par x, et le contenu stocké dans l'emplacement
mémoire est mis à jour à 16 après l'exécution de l'instruction. Donc, vous voyez, utiliser des pointeurs pour
accéder aux emplacements mémoire des variables est un moyen d'indirection.

Q Un pointeur nul peut­il pointer vers des données valides ?

R Non. Un pointeur nul ne peut pas pointer vers des données valides. Cela est dû au fait que la valeur contenue
par un pointeur nul a été définie sur 0. Vous verrez des exemples d'utilisation de pointeurs nuls dans des
tableaux, des chaînes et une allocation de mémoire plus loin dans le livre.
Machine Translated by Google

188 Heure 11

Atelier
Pour aider à consolider votre compréhension de la leçon de cette heure, nous vous encourageons à
répondre aux questions du quiz et à terminer les exercices fournis dans l'atelier avant de passer à la leçon
suivante. Les réponses et les conseils aux questions et exercices sont donnés dans l'annexe B, « Réponses
aux questions et exercices du quiz ».

Questionnaire

1. Comment obtenir la valeur de gauche d'une variable caractère ch ?

2. Dans les expressions suivantes, quel astérisque (*) est un opérateur de déréférencement, et
lequel est un opérateur de multiplication ?

• *ptr
•x * Oui

• Oui
*= x + 5

• *y *= *x + 5

3. Étant donné que x = 10, l'adresse de x est 0x1A38, et ptr_int = &x, qu'est­ce qui
ptr_int et *ptr_int produisent respectivement ?

4. Étant donné que x = 123, et ptr_int = &x après l'exécution de *ptr_int = 456,
que contient x ?

Des exercices

1. Étant donné trois variables entières, x = 512, y = 1024 et z = 2048, écrivez un programme
pour imprimer leurs valeurs de gauche ainsi que leurs valeurs de droite.

2. Écrivez un programme pour mettre à jour la valeur de la variable double flt_num de 123,45 à 543,21
en utilisant un double pointeur.

3. Étant donné une variable de caractère ch et ch = 'A', écrivez un programme pour mettre à jour la valeur
de ch à la décimale 66 en utilisant un pointeur.

4. Étant donné que x=5 et y=6, écrivez un programme pour calculer la multiplication des deux entiers et
imprimez le résultat, qui est enregistré dans x, le tout dans le sens de l'indirection (c'est­à­dire en
utilisant des pointeurs).
Machine Translated by Google

HEURE 12
Comprendre les tableaux
Rassemblez les fragments qui restent, que rien ne soit perdu.

—Jean 6:12

Dans la leçon de la dernière heure, vous avez appris les pointeurs et le concept d'indirection.
Dans cette leçon, vous découvrirez les tableaux, qui sont des collections d'éléments de données
similaires et sont étroitement liés aux pointeurs. Les principaux sujets abordés dans cette leçon
sont

• Tableaux à une dimension •

Tableaux d'indexation • Pointeurs

et tableaux • Tableaux de

caractères • Tableaux

multidimensionnels • Tableaux

non dimensionnés
Machine Translated by Google

190 Heure 12

Qu'est­ce qu'un tableau ?


Vous savez maintenant comment déclarer une variable avec un type de données spécifié, tel que char, int,
float ou double. Dans de nombreux cas, vous devez déclarer un ensemble de variables qui ont le même
type de données. Au lieu de les déclarer individuellement, C vous permet de déclarer collectivement un
ensemble de variables du même type de données sous forme de tableau.

Un tableau est une collection de variables qui sont du même type de données. Chaque élément d'un tableau est
appelé un élément. Tous les éléments d'un tableau sont référencés par le nom du tableau et sont stockés dans un
ensemble d'emplacements de mémoire consécutifs et adjacents.

Déclarer des tableaux


Voici la forme générale pour déclarer un tableau :

type de données Array­Name[Array­Size] ;

Ici data­type est le spécificateur de type qui indique le type de données du tableau déclaré. Array­Name est le nom
du tableau déclaré. Array­Size définit le nombre d'éléments que le tableau peut contenir. Notez que les crochets
([ et ]) sont nécessaires pour déclarer un tableau. La paire de parenthèses ([ et ]) est également appelée opérateur
d'indice de tableau.

Par exemple, un tableau d'entiers est déclaré dans l'instruction suivante,

int tableau_int[8] ;

où int spécifie le type de données du tableau dont le nom est array_int. La taille du tableau est 8, ce qui signifie
que le tableau peut stocker huit éléments (c'est­à­dire des entiers dans ce cas).

En C, vous devez déclarer explicitement un tableau, comme vous le faites pour d'autres variables, avant de
pouvoir l'utiliser.

Tableaux d'indexation
Après avoir déclaré un tableau, vous pouvez accéder à chacun des éléments du tableau séparément.

Par exemple, la déclaration suivante déclare un tableau de caractères :

jour de l'omble[7] ;

Vous pouvez accéder aux éléments du tableau de jour les uns après les autres. Pour ce faire, vous utilisez le nom
du tableau dans une expression suivi d'un nombre, appelé index, entre crochets.

La chose importante à retenir est que tous les tableaux en C sont indexés à partir de 0. En d'autres termes, l'index
du premier élément d'un tableau est 0, et non 1. Par conséquent, le premier élément du tableau de jour est jour[0 ].
Comme il y a 7 éléments dans le tableau day , le dernier élément est day[6], pas day[7].
Machine Translated by Google

Comprendre les tableaux 191

Les sept éléments du tableau ont les expressions suivantes : jour[0], jour[1], jour[2], jour[3],
jour[4], jour[5] et jour[6].

Étant donné que ces expressions font référence aux éléments du tableau, elles sont parfois appelées
références d'éléments de tableau.

Initialisation des tableaux


À l'aide des références d'éléments de tableau, vous pouvez initialiser chaque élément d'un tableau.

Par exemple, vous pouvez initialiser le premier élément du tableau de jour, qui a été déclaré dans la
dernière section, comme ceci :

jour[0] = 'S' ;

Ici, la valeur numérique de S est affectée au premier élément de jour, jour[0].

De même, l'instruction day[1] = 'M'; affecte 'M' au deuxième élément, jour[1], dans le tableau.

La deuxième façon d'initialiser un tableau consiste à initialiser tous les éléments du tableau ensemble. Par
exemple, l'instruction suivante initialise un tableau d'entiers, arInteger :

int arInteger[5] = {100, 8, 3, 365, 16} ;

Ici, les entiers à l'intérieur des accolades ({ et }) sont affectés de manière correspondante aux
éléments du tableau arInteger. Autrement dit, 100 est attribué au premier élément (arInteger[0]), 8 au
deuxième élément (arInteger[1]), 3 au troisième (arInteger[2]), etc.

Le Listing 12.1 donne un autre exemple d'initialisation de tableaux.


12
TAPER LISTE 12.1 Initialisation d'un tableau

1 : /* 12L01.c : Initialisation d'un tableau */ 2 : #include


<stdio.h> 3 : 4 : main() 5 : { 6 : 7 :

int je ;
int liste_int[10] ;

pour (i=0 ; i<10 ; i++){


list_int[je] = je + 1 ;
8 : 9 : 10 : 11 : printf( "list_int[%d] est initialisé avec %d.\n", i, list_int[i]);
12 :
13 : } renvoie 0 ;
14 : }
Machine Translated by Google

192 Heure 12

La sortie suivante s'affiche à l'écran après la création et l'exécution de l'exécutable (12L01.exe) du


programme du Listing 12.1 sur mon ordinateur :

list_int[0] est initialisé avec 1. list_int[1] est


SORTIR initialisé avec 2. list_int[2] est initialisé avec
3. list_int[3] est initialisé avec 4. list_int[4]
est initialisé avec 5. list_int[5] est initialisé
avec 6. list_int[6] est initialisé avec 7.
list_int[7] est initialisé avec 8. list_int[8] est
initialisé avec 9. list_int[9] est initialisé avec
10.

Comme vous pouvez le voir dans le Listing 12.1, il existe un tableau d'entiers, appelé list_int,
UNE ANALYSE
qui est déclaré à la ligne 7. Le tableau list_int contient 10 éléments.

Les lignes 9 à 12 constituent une boucle for qui itère 10 fois. L'instruction de la ligne 10 initialise
list_int[i], le ième élément du tableau list_int, avec le résultat de l'expression i + 1.

La ligne 11 imprime ensuite le nom de l'élément, list_int[i], et la valeur affectée à l'élément.

La taille d'un tableau


Comme mentionné précédemment dans cette leçon, un tableau se compose d'emplacements de mémoire consécutifs.
Étant donné un tableau, comme celui­ci :

type de données Array­Name[Array­Size] ;

vous pouvez ensuite calculer le nombre total d'octets du tableau par l'expression suivante :

sizeof(type de données) * Taille­tableau

Ici data­type est le type de données du tableau ; Array­Size spécifie le nombre total d'éléments que le
tableau peut prendre. Cette expression évalue le nombre total d'octets pris par le tableau.

Une autre façon de calculer le nombre total d'octets d'un tableau est plus simple ; il utilise
l'expression suivante :

sizeof(nom­tableau)

Ici Array­Name est le nom du tableau.

Le programme du Listing 12.2 montre comment calculer l'espace mémoire occupé par un tableau.
Machine Translated by Google

Comprendre les tableaux 193

TAPER
LISTE 12.2 Calcul de la taille d'un tableau

1 : /* 12L02.c : nombre total d'octets d'un tableau */


2 : #include <stdio.h> 3 : 4 : main() 5 : { 6 :

int total_byte ; int


7: liste_int[10] ;
8:
9: total_byte = sizeof (entier) * 10 ;
10 : printf( "La taille de int est longue de %d octets.\n", sizeof (int)); printf( "Le
11 : tableau de 10 entiers a un total de %d octets.\n", total_byte); printf( "L'adresse du
12 : premier élément : %p\n", &list_int[0]); printf( "L'adresse du dernier élément : %p\n",
13 : &list_int[9]); renvoie 0 ;
14 :
15 : }

Après avoir exécuté l'exécutable 12L02.exe, j'ai la sortie suivante affichée sur l'écran de mon
ordinateur :
La taille de int est longue de 2 octets.
SORTIR
Le tableau de 10 entiers a un total de 20 octets
L'adresse du premier élément : 0x1806 L'adresse
du dernier élément : 0x1818

UNE ANALYSE Notez que vous pouvez obtenir des valeurs d'adresse différentes lorsque vous exécutez
le programme du Listing 12.2 sur votre machine. Cependant, la différence entre l'adresse de
le premier élément et l'adresse du dernier élément doivent être égaux au nombre total d'octets du
tableau.
12
Dans le Listing 12.2, il y a un tableau d'entiers, list_int, qui est déclaré à la ligne 7. L'espace mémoire
total occupé par le tableau est le résultat de la multiplication de la taille de int et du nombre total
d'éléments dans le tableau. Comme déclaré dans cet exemple, il y a un total de 10 éléments dans le
tableau list_int.

La déclaration de la ligne 10 imprime la taille de int sur ma machine. Vous pouvez voir à partir de la
sortie que chaque élément entier du tableau prend 2 octets. Par conséquent, l'espace mémoire total
(en octets) pris par le tableau est de 10 * 2. En d'autres termes, l'instruction de la ligne 9 attribue la
valeur de 20, produite par l'expression sizeof (int) * 10, à la variable entière total_byte . La ligne 11
affiche alors la valeur contenue par la variable total_byte à l'écran.

Pour prouver que le tableau prend l'espace mémoire consécutif de 20 octets, l'adresse du premier
élément du tableau est imprimée par l'instruction de la ligne 12. Notez que l'esperluette (&), qui a été
introduite comme adresse de l'opérateur de l'heure 11, "Comprendre les pointeurs", est utilisé à la
ligne 12 pour obtenir l'adresse du premier élément,
Machine Translated by Google

194 Heure 12

list_int[0], dans le tableau. Ici, l'adresse du premier élément est l'adresse de début du tableau. À partir de la
sortie, vous pouvez voir que l'adresse de l' élément list_int[0] est 0x1806 sur ma machine.

Ensuite, l' expression &list_int[9] de la ligne 13 donne l'adresse de l'élément final du tableau, qui est 0x1818
sur ma machine. Ainsi, la distance entre le dernier élément et le premier élément est de 0x1818–0x1806, soit
18 octets.

Comme mentionné précédemment dans le livre, l'hexadécimal est un système de numérotation à base de
16. Nous savons que 0x1818 moins 0x1806 produit 0x0012 (c'est­à­dire 0x12). Alors 0x12 en hexadécimal est
égal à 1*16 + 2 ce qui donne 18 en décimal.

Étant donné que chaque élément prend 2 octets et que l'adresse de l'élément final est le début de cet élément
de 2 octets, le nombre total d'octets pris par le tableau list_int est en effet de 20 octets. Vous pouvez le calculer
d'une autre manière : la distance entre le dernier élément et le premier élément est de 18 octets. Le nombre total
d'octets pris par le tableau doit être compté du tout premier octet du premier élément au dernier octet du dernier
élément. Par conséquent, le nombre total d'octets pris par le tableau est égal à 18 plus 2, soit 20 octets.

La figure 12.1 vous montre l'espace mémoire occupé par le tableau list_int

FIGURE 12.1
L'espace mémoire
occupé par le tableau &list_int[0] 0x1806 1 octet
list_int. 2 octets
1 octet

1 octet
2 octets
1 octet

&list_int[9] 0x1818 1 octet


} }2 }octets
1 octet

Tableaux et pointeurs
Comme je l'ai mentionné plus tôt dans cette heure, les pointeurs et les tableaux ont une relation étroite en C.
En fait, vous pouvez créer un pointeur qui fait référence au premier élément d'un tableau en affectant simplement
Machine Translated by Google

Comprendre les tableaux 195

insérant le nom du tableau à la variable de pointeur. Si un tableau est référencé par un pointeur,
les éléments du tableau sont accessibles à l'aide du pointeur.

Par exemple, les instructions suivantes déclarent un pointeur et un tableau, et affectent


l'adresse du premier élément à la variable pointeur :

char *ptr_c; liste de


caractères_c[10] ; ptr_c =
liste_c ;

Comme l'adresse du premier élément du tableau list_c est l'adresse de début du tableau, la
variable de pointeur ptr_c référence en fait maintenant le tableau via l'adresse de début.

Le Listing 12.3 montre comment référencer un tableau avec un pointeur.

TAPER LISTE 12.3 Référencer un tableau avec un pointeur

1 : /* 12L03.c : référencer un tableau avec un pointeur */ 2 : #include <stdio.h>


3 : 4 : main() 5 : { 6 : 7 :

entier *ptr_int; int


liste_int[10] ; int je ;

pour (i=0; i<10; i++)


8 : 9 : 10 : 11 : list_int[je] = je + 1 ; ptr_int =
12 :
13:
list_int ; printf( "L'adresse de début
du tableau : %p\n", ptr_int); printf( "La valeur du premier élément : %d\n", *ptr_int); ptr_int
12
14: = &list_int[0]; printf( "L'adresse du premier élément : %p\n", ptr_int); printf( "La valeur du
premier élément : %d\n", *ptr_int); renvoie 0 ;

15 : 16 : 17 :
18 :
19 : }

Après l'exécution de l'exécutable 12L03.exe sur mon ordinateur, la sortie suivante s'affiche à
l'écran :

L'adresse de début du tableau : 0x1802


SORTIR
La valeur du premier élément : 1
L'adresse du premier élément : 0x1802
La valeur du premier élément : 1

Dans le Listing 12.3, une variable de pointeur entier, ptr_int, est déclarée à la ligne 6.
UNE ANALYSE
Ensuite, un tableau d'entiers, list_int, qui est déclaré à la ligne 7, est initialisé par le
list_int[i] = i + 1 expression dans une boucle for . (Voir les lignes 10 et 11.)
Machine Translated by Google

196 Heure 12

L'instruction de la ligne 12 affecte l'adresse du premier élément du tableau à la variable de pointeur


ptr_int. Pour ce faire, le nom du tableau list_int est simplement placé à droite de l'opérateur d'affectation (=) à
la ligne 12.

La ligne 13 affiche l'adresse affectée à la variable de pointeur ptr_int. La sortie montre que 0x1802 est l'adresse
de début du tableau. (Vous pourriez obtenir une adresse différente sur votre machine.) L' expression *ptr_int
de la ligne 14 est évaluée à la valeur référencée par le pointeur. Cette valeur est la même valeur contenue par
le premier élément du tableau, qui est la valeur initiale, 1, assignée dans la boucle for . Vous pouvez voir que la
sortie de l'instruction de la ligne 14 affiche correctement la valeur.

L'instruction de la ligne 15 est équivalente à celle de la ligne 12, qui affecte l'adresse du premier élément à la
variable de pointeur. Les lignes 16 et 17 impriment alors l'adresse et la valeur conservées par le premier
élément, 0x1802 et 1, respectivement.

Dans l'heure 16, « Application des pointeurs », vous apprendrez à accéder à un élément d'un tableau en
incrémentant ou en décrémentant un pointeur.

Affichage de tableaux de caractères


Cette sous­section se concentre sur les tableaux de caractères. Le type de données char prend un octet.
Par conséquent, chaque élément d'un tableau de caractères a une longueur d'un octet. Le nombre total
d'éléments dans un tableau de caractères est le nombre total d'octets que le tableau prend en mémoire.

Plus important encore en C, une chaîne de caractères est définie comme une séquence contiguë de caractères
terminée par et incluant le premier caractère nul ('\0'). L'heure 13, "Manipulation des chaînes", présente plus de
détails sur les chaînes.

Dans le Listing 12.4, vous voyez différentes manières d'afficher un tableau de caractères à l'écran.

TAPER LISTE 12.4 Impression d'un tableau de caractères

1 : /* 12L04.c : Impression d'un tableau de caractères */ 2 : #include


<stdio.h> 3 : 4 : main() 5 : { 6 : 7 :

char array_ch[7] = {'H', 'e', 'l', 'l', 'o', '!', '\0'} ; int je ;

pour (i=0; i<7; i++)


printf("array_ch[%d] contient : %c\n", i, array_ch[i]); /*­­­ method I ­­­*/
8 : 9 : 10 : 11printf(
: "Mettre tous les éléments ensemble(Method I):\n"); for (i=0; array_ch[i] !
12 : = '\0' && i<7; i++) printf(“%c”, array_ch[i]);
13:
14:
Machine Translated by Google

Comprendre les tableaux 197

15 : /*­­­ méthode II ­­­*/


16 : printf( "\nMettre tous les éléments ensemble (Méthode II):\n");
17 : printf( "%s\n", array_ch);
18 :
19 : renvoie 0 ;
20 : }

Lorsque j'exécute l'exécutable 12L04.exe, la sortie suivante s'affiche :

array_ch[0] contient : H
SORTIR array_ch[1] contient : e
array_ch[2] contient : l
array_ch[3] contient : l
array_ch[4] contient : o
array_ch[5] contient : !
array_ch[6] contient :
Assemblez tous les éléments (Méthode I) :
Bonjour !
Rassemblez tous les éléments (Méthode II) :
Bonjour !

Comme vous pouvez le voir dans le Listing 12.4, un tableau de caractères, array_ch, est
UNE ANALYSE
déclaré et initialisé à la ligne 6. Chaque élément du tableau de caractères est imprimé par le
appel printf() dans une boucle for illustrée aux lignes 9 et 10. Il y a un total de sept éléments
dans le tableau ; ils contiennent les constantes de caractère suivantes : 'H', 'e', 'l', 'l', 'o', '!'
et '\0'.

Il existe deux manières d'afficher ce tableau : afficher tous les caractères individuellement ou les traiter
comme une chaîne de caractères.
12
Les lignes 12 à 14 montrent la première manière, qui récupère chaque élément individuel, array_ch[i],
consécutivement dans une boucle, et imprime un caractère à côté d'un autre en utilisant le spécificateur
de format de caractère %c dans l' appel printf() en ligne 14.

Chaque fois que vous avez affaire à un tableau de caractères, comme mentionné précédemment, le
caractère nul '\0' signale la fin de la chaîne (même s'il ne s'agit pas encore de la fin du tableau). C'est une
bonne idée de surveiller le caractère nul afin de savoir quand arrêter l'impression, ainsi l'expression
conditionnelle de la ligne 13 terminera la boucle for si l'élément courant est un caractère nul.

La deuxième façon est plus simple. Vous indiquez simplement à la fonction printf() où trouver le premier
élément du tableau (l'adresse de son premier élément). De plus, vous devez utiliser la chaîne pour le
spécificateur mat %s dans l' appel printf() comme indiqué à la ligne 17. Notez que l' expression array_ch à
la ligne 17 contient l'adresse du premier élément du tableau, c'est­à­dire l'adresse de départ. adresse du
tableau. Le nom du tableau, en lui­même, est une manière abrégée de dire array_ch[0] ; ils signifient la
même chose.
Machine Translated by Google

198 Heure 12

Vous vous demandez peut­être comment la fonction printf() sait où se trouve la fin du tableau de caractères.
Vous souvenez­vous que le dernier élément du tableau de caractères array_ch est un caractère '\0' ? C'est
ce caractère nul qui marque la fin de la chaîne. Comme je l'ai mentionné précédemment, une séquence
contiguë de caractères se terminant par un caractère nul est appelée une chaîne de caractères en C. Nous
ne disons pas à printf() combien d'éléments sont dans le tableau, donc le spécificateur de format %s indique
à printf() de continuez à imprimer des caractères jusqu'à ce qu'il trouve un caractère nul, comme nous l'avons
fait nous­mêmes dans la première méthode.

Le caractère nul ('\0')


Le caractère nul ('\0') est traité comme un caractère en C ; c'est un caractère spécial qui marque la fin
d'une chaîne. Par conséquent, lorsque des fonctions comme printf() agissent sur une chaîne de
caractères, elles traitent un caractère après l'autre jusqu'à ce qu'elles rencontrent le caractère nul.
(Vous en apprendrez plus sur les cordes à l'heure 13.)

Le caractère nul ('\0'), qui est toujours évalué comme une valeur de zéro, peut également être utilisé pour
un test logique dans une instruction de flux de contrôle. Le Listing 12.5 montre un exemple d'utilisation du
caractère nul dans une boucle for .

TAPER LISTE 12.5 Fin de la sortie au caractère nul

1 : /* 12L05.c : Arrêt au caractère nul */ 2 : #include <stdio.h>


3 : 4 : main() 5 : { 6 : 7 :

char array_ch[15] = {'C', ' ', 'i', 's', ' ', 'p',
'o', 'w', 'e', 'r', 'f', '
u', 'l', '!', '\0'} ;

int je ; /
8 : 9 : 10 : 11*: array_ch[i]
dans le test logique */ for (i=0;
12 : array_ch[i]; i++)
13: printf("%c", array_ch[i]);
14:
15 : printf("\n");
16 : renvoie 0 ;
17 : }

En lançant l'exécutable 12L05.exe, j'obtiens le résultat suivant :

C'est puissant !
SORTIR
Machine Translated by Google

Comprendre les tableaux 199

Dans le Listing 12.5, un tableau de caractères, array_ch, est déclaré et initialisé, avec les caractères
UNE ANALYSE
(y compris les espaces) de la chaîne C est puissant !, dans
lignes 6 à 9.

Notez que le dernier élément du tableau contient le caractère nul ('\0'), qui est nécessaire pour terminer la chaîne.

La boucle for des lignes 12 et 13 imprime chaque élément du tableau array_ch pour montrer que la chaîne C
est puissante ! sur l'écran. Ainsi, dans la première expression de l' instruction for , la variable entière i, qui est
utilisée comme index du tableau, est initialisée à 0.

Ensuite, l'expression conditionnelle, array_ch[i], est évaluée. Si l'expression donne une valeur différente de
zéro, la boucle for itère ; sinon, la boucle s'arrête. À partir du premier élément du tableau, l' expression
array_ch[i] continue de produire une valeur différente de zéro jusqu'à ce que le caractère nul soit rencontré. Par
conséquent, la boucle for peut mettre tous les caractères du tableau à l'écran et arrêter l'impression juste après
que l' expression array_ch[i] ait produit une valeur de zéro, lorsqu'elle trouve le caractère nul

Tableaux multidimensionnels
Jusqu'à présent, tous les tableaux que vous avez vus étaient des tableaux unidimensionnels, dans lesquels les
tailles des dimensions sont placées entre parenthèses ([ et ]).

En plus des tableaux unidimensionnels, le langage C prend également en charge les tableaux
multidimensionnels. Vous pouvez déclarer des tableaux avec autant de dimensions que votre compilateur le permet.

La forme générale de déclaration d'un tableau à N dimensions est


12
type de données Array­Name[Array­Size1][Array­Size2]. . . [Tableau­TailleN] ;

où N peut être n'importe quel entier positif.

Parce que le tableau à deux dimensions, qui est largement utilisé, est la forme la plus simple du tableau
multidimensionnel, concentrons­nous sur les tableaux à deux dimensions dans cette section. Cependant, tout
ce que vous apprenez dans cette section peut être appliqué à des tableaux de plus de deux dimensions.

Par exemple, l'instruction suivante déclare un tableau d'entiers à deux dimensions :

int array_int[2][3] ;

Ici, il y a deux paires de crochets qui représentent deux dimensions avec une taille de 2 et 3 éléments entiers,
respectivement.

Vous pouvez initialiser le tableau à deux dimensions array_int de la manière suivante :

array_int[0][0] = 1 ;
array_int[0][1] = 2 ;
Machine Translated by Google

200 Heure 12

array_int[0][2] = 3 ;
array_int[1][0] = 4 ;
array_int[1][1] = 5 ;
array_int[1][2] = 6 ;

ce qui équivaut à l'énoncé

int array_int[2][3] = {1, 2, 3, 4, 5, 6} ;

De plus, vous pouvez initialiser le tableau array_int de la manière suivante :

int array_int[2][3] = {{1, 2, 3}, {4, 5, 6}} ;

Notez que array_int[0][0] est le premier élément du tableau à deux dimensions array_int ; array_int[0]
[1] est le deuxième élément du tableau ; array_int[0][2] est le troisième élément ; array_int[1][0] est le
quatrième élément ; array_int[1][1] est le cinquième élément ; et array_int[1][2] est le sixième élément
du tableau.

Le programme du Listing 12.6 montre un tableau d'entiers à deux dimensions qui est initialisé et
affiché à l'écran.

TAPER
LISTE 12.6 Impression d'un tableau à deux dimensions

1 : /* 12L06.c : Impression d'un tableau 2D */ 2 :


#include <stdio.h> 3 : 4 : main() 5 : { 6 : 7 : 8 : 9 : 10 :
11 : 12 : 13 : 14 : 15 : 16 : 17 : 18 : }

int two_dim[3][5] = {1, 2, 3, 4, 5, 10, 20, 30,


40, 50, 100, 200, 300,
400, 500} ;
int je, j ;

for (i=0; i<3; i++)


{ printf("\n"); for (j=0;
j<5; j++) printf("%6d",
two_dim[i][j]);

} printf("\n");
renvoie 0 ;

La sortie suivante est obtenue en exécutant l'exécutable 12L06.exe :


2 3 4
SORTIR 1 10 5 20 30 40 50 100 200
300 400 500
Machine Translated by Google

Comprendre les tableaux 201

Comme vous pouvez le voir dans le Listing 12.6, il existe un tableau d'entiers à deux dimensions, two_dim,
UNE ANALYSE
déclaré et initialisé aux lignes 6–8.

Aux lignes 11 à 15, deux boucles for sont imbriquées. La boucle for externe incrémente la variable entière i et
imprime le caractère de retour à la ligne '\n' à chaque itération. Ici, la variable entière i est utilisée comme index
de la première dimension du tableau, two_dim.

La boucle for interne des lignes 13 et 14 imprime chaque élément, représenté par l'expression two_dim[i][j], en
incrémentant l'indice à la deuxième dimension du tableau.
J'obtiens donc la sortie suivante :

1 2 3 4
dix 5 20 30 40 50 100 200 300
400 500

une fois que les deux boucles for imbriquées ont été exécutées avec succès.

Tableaux non dimensionnés


Comme vous l'avez vu, la taille d'une dimension est normalement donnée lors de la déclaration d'un tableau.
Cela signifie que vous devez compter chaque élément d'un tableau pour déterminer la taille. Cependant, cela peut
être fastidieux, surtout s'il y a beaucoup d'éléments dans un tableau.

La bonne nouvelle est que le compilateur C peut en fait calculer automatiquement la taille d'une dimension d'un
tableau si un tableau est déclaré comme un tableau non dimensionné. Par exemple, lorsque le compilateur voit le
tableau non dimensionné suivant :

int list_int[] = { 10, 20, 30, 40, 50, 60, 70, 80, 90} ;
12
cela créera un tableau assez grand pour stocker tous les éléments.

De même, vous pouvez déclarer un tableau multidimensionnel non dimensionné. Cependant, vous devez spécifier
toutes les tailles de dimension sauf la plus à gauche (c'est­à­dire la première). Par exemple, le compilateur peut
réserver suffisamment d'espace mémoire pour contenir tous les éléments du tableau non dimensionné à deux
dimensions suivant :

char list_ch[][2] = { 'a', 'A',


'b', 'B', 'c', 'C',
'd', 'D', 'e', 'E', '
f', 'F', 'g', 'G'} ;

Le programme du Listing 12.7 initialise un tableau unidimensionnel de caractères non dimensionnés et un tableau
bidimensionnel d'entiers non dimensionnés, puis mesure les espaces mémoire utilisés pour stocker les deux
tableaux.
Machine Translated by Google

202 Heure 12

TAPER LISTE 12.7 Initialisation de tableaux non dimensionnés

1 : /* 12L07.c : Initialisation de tableaux non dimensionnés


*/ 2 : #include <stdio.h> 3 : 4 : main() 5 : { 6 :

char array_ch[] = {'C', ' ', 'i', 's', ' ',


7: 'p', 'o', 'w', 'e', 'r',
8: 'f', 'u ', 'l', '!', '\0'} ; int list_int[]
9: [3] = { 1, 1, 1, 2, 2, 8, 3, 9, 27, 4,
10 : 16, 64, 5, 25, 125, 6, 36, 216, 7, 49, 343 } ;
11 :
12 :
13 :
14 :
15 :
16 :
17 :
18 :
19 : printf("La taille de array_ch[] est de %d octets.\n", sizeof (array_ch)); printf("La taille de
20 : list_int[][3] est %d octets.\n", sizeof (list_int)); renvoie 0 ;
21 :
22 : }

La sortie suivante est obtenue lorsque l'exécutable 12L07.exe est exécuté sur mon ordinateur :

La taille de array_ch[] est de 15 octets.


SORTIR
La taille de list_int[][3] est de 42 octets.

Un tableau non dimensionné de caractères, array_ch, est déclaré et initialisé aux lignes 6–9.
UNE ANALYSE
Aux lignes 10 à 17, un tableau d'entiers non dimensionné à deux dimensions, list_int, est déclaré et
initialisé aussi.

L'instruction de la ligne 19 mesure et imprime l'espace mémoire total (en octets) occupé par le tableau
array_ch. Le résultat montre que le tableau de caractères non dimensionné se voit attribuer 15 octets en
mémoire pour contenir tous ses éléments après la compilation. Lorsque vous calculez manuellement le
nombre total d'éléments dans le tableau de caractères, vous constatez qu'il y a bien 15 éléments. Parce
que chaque caractère prend un octet dans la mémoire, le tableau de caractères array_ch prend un total de
15 octets en conséquence.

De même, l'instruction de la ligne 20 donne le nombre total d'octets réservés en mémoire pour le tableau
d'entiers à deux dimensions non dimensionné list_int. Parce qu'il y a un total de 21 éléments entiers dans
le tableau, et qu'un entier prend 2 octets sur ma machine, le compilateur doit allouer 42 octets pour le
tableau d'entiers list_int. Le résultat imprimé par la fonction printf() à la ligne 20 prouve qu'il y a 42 octets
réservés dans la mémoire
Machine Translated by Google

Comprendre les tableaux 203

pour le tableau d'entiers à deux dimensions. (Si la taille de int est différente sur votre machine, vous pouvez obtenir
des valeurs différentes pour la taille du tableau list_int dans le programme Listing 12.7.)

Résumé
Dans cette leçon, vous avez appris les concepts très importants suivants sur les tableaux en C :

• Un tableau est une collection de variables qui sont du même type de données. • En C,

l'index d'un tableau commence à 0. • Vous pouvez initialiser chaque élément individuel d'un

tableau après la déclaration du tableau, ou vous pouvez placer toutes les valeurs initiales dans un bloc de
données entouré de { et } lors de la déclaration de un tableau.

• Le stockage en mémoire occupé par un tableau est déterminé en multipliant la taille du type de données et les
dimensions du tableau.

• On dit qu'un pointeur fait référence à un tableau lorsque l'adresse du premier élément du
tableau est assigné au pointeur. L'adresse du premier élément d'un tableau est également appelée adresse
de début du tableau.

• Pour affecter l'adresse de départ d'un tableau à un pointeur, vous pouvez soit mettre la combinaison de
l'opérateur d'adresse de (&) et du premier nom d'élément du tableau, soit simplement utiliser le nom du
tableau à droite de un opérateur d'affectation (=).

• Le caractère nul ('\0') marque la fin d'une chaîne. Fonctions C, telles que printf(),
arrêtera de traiter la chaîne lorsque le caractère nul est rencontré.

• C prend également en charge les tableaux multidimensionnels. Une paire de parenthèses vide (le sous­tableau
opérateur de script—[ et ]) indique une dimension.
12
• Le compilateur peut calculer automatiquement l'espace mémoire nécessaire à un fichier non dimensionné.
déployer.

Dans la prochaine leçon, vous en apprendrez plus sur les chaînes en C.

Questions et réponses

Q Pourquoi avez­vous besoin d'utiliser des tableaux ?

A Dans de nombreux cas, vous devez déclarer un ensemble de variables qui sont du même type de données.
Au lieu de déclarer chaque variable séparément, vous pouvez déclarer toutes les variables collectivement
sous la forme d'un tableau. Chaque variable, en tant qu'élément du tableau, est accessible via la référence
d'élément de tableau ou via un pointeur qui référence le tableau.
Machine Translated by Google

204 Heure 12

Q Quel est l'index minimum dans un tableau ?

A En C, l'indice minimum d'un tableau à une dimension est 0, ce qui marque le premier
élément du tableau. Par exemple, étant donné un tableau d'entiers,
int tableau_int[8] ;

le premier élément du tableau est array_int[0].

De même, pour un tableau multidimensionnel, l'indice minimum de chaque dimension


commence à 0.

Q Comment référencez­vous un tableau à l'aide d'un pointeur ?

A Vous pouvez utiliser un pointeur pour référencer un tableau en attribuant l'adresse de début d'un
tableau au pointeur. Par exemple, étant donné une variable de pointeur ptr_ch et un tableau de
caractères array_ch, vous pouvez utiliser l'une des instructions suivantes pour référencer le tableau
par le pointeur :
ptr_ch = array_ch ;
ou alors

ptr_ch = &array_ch[0];
Q Que peut faire le caractère nul ?

A Le caractère nul ('\0') en C peut être utilisé pour marquer la fin d'une chaîne. Pour
Par exemple, la fonction printf() continue de placer le caractère suivant à l'écran jusqu'à ce que le
caractère nul soit rencontré. En outre, le caractère nul prend toujours la valeur zéro.

Atelier
Pour aider à consolider votre compréhension de la leçon de cette heure, nous vous encourageons à
répondre aux questions du quiz et à terminer les exercices fournis dans l'atelier avant de passer à la leçon
suivante. Les réponses et les conseils aux questions et exercices sont donnés dans l'annexe B,
« Réponses aux questions et exercices du quiz ».

Questionnaire

1. Que fait l'énoncé suivant ?


int array_int[4] = {12, 23, 9, 56} ;

2. Étant donné un tableau, int data[3], quel est le problème avec l'initialisation suivante ?
données[1] = 1 ;
données[2] = 2 ;
données[3] = 3 ;
Machine Translated by Google

Comprendre les tableaux 205

3. Combien de dimensions ont les tableaux suivants ?

• tableau de caractères1[3][19] ;

• int tableau2[] ;

• tableau flottant3[][8][16] ;

• tableau de caractères4[][80] ;

4. Quel est le problème avec la déclaration suivante ?


char list_ch[][] = {
'A', 'a',
'B', 'b',
'C', 'c',
'D', 'd',

Des exercices

1. Étant donné ce tableau de caractères :

char array_ch[5] = {'A', 'B', 'C', 'D', 'E'} ;

écrire un programme pour afficher chaque élément du tableau à l'écran.

2. Réécrivez le programme dans l'exercice 1, mais cette fois utilisez une boucle for pour
initialiser le tableau de caractères avec 'a', 'b', 'c', 'd' et 'e', puis imprimez la valeur de
chaque élément du tableau.

3. Étant donné ce tableau non dimensionné à deux dimensions :


char list_ch[][2] = { '1', 'a',
'2', 'b', '3', 'c',
'4', 'd', '5', 'e', '
6', 'f'} ; 12

écrivez un programme pour mesurer le nombre total d'octets pris par le tableau, puis imprimez tous les
éléments du tableau.

4. Réécrivez le programme du Listing 12.5. Cette fois, mettez une chaîne de caractères, J'aime C !, sur
l'écran.

5. Soit le tableau suivant : double


list_data[6] = { 1.12345, 2.12345,
3.12345, 4.12345,
5.12345} ;

utilisez les deux méthodes équivalentes enseignées dans cette leçon pour mesurer l'espace mémoire
total occupé par la matrice, puis affichez les résultats à l'écran.
Machine Translated by Google
Machine Translated by Google

HEURE 13

Manipulation de chaînes
J'ai fait cette lettre plus longue que d'habitude, parce que je n'ai pas le temps de la faire courte.

—B. Pascal

Dans la leçon de la dernière heure, vous avez appris à utiliser des tableaux pour collecter des
variables du même type. Vous avez également appris qu'une chaîne de caractères est en fait
un tableau de caractères, avec un caractère nul \0 marquant la fin de la chaîne. Dans cette
leçon, vous en apprendrez plus sur les chaînes et les fonctions C qui peuvent être utilisées pour
manipuler les chaînes. Les sujets suivants sont couverts :

• Déclarer une chaîne •

La longueur d'une chaîne •

Copier des chaînes • Lire des

chaînes avec scanf() • Les fonctions

gets() et puts()
Machine Translated by Google

208 Heure 13

Déclarer des chaînes


Cette section vous apprend comment déclarer et initialiser des chaînes, ainsi que la différence entre les
constantes de chaîne et les constantes de caractère. Examinons d'abord la définition d'une chaîne.

Qu'est­ce qu'une chaîne ?


Comme présenté dans l'Heure 12, « Comprendre les tableaux », une chaîne est un tableau de caractères, avec
un caractère nul (\0) utilisé pour marquer la fin de la chaîne. (La longueur d'une chaîne peut être plus courte que
son tableau de caractères.)

Par exemple, un tableau de caractères, array_ch, déclaré dans l'instruction suivante, est considéré comme une
chaîne de caractères :

char array_ch[7] = {'H', 'e', 'l', 'l', 'o', '!', '\0'} ;

En C, le caractère nul est utilisé pour marquer la fin d'une chaîne, et il est toujours évalué à 0. C traite \0 comme un
seul caractère. Chaque caractère d'une chaîne ne prend que 1 octet.

Une série de caractères entre guillemets ("") est appelée une constante de chaîne. Le compilateur C ajoutera
automatiquement un caractère nul (\0) à la fin d'une constante de chaîne pour indiquer la fin de la chaîne.

Par exemple, la chaîne de caractères "Une chaîne de caractères". est considéré comme une constante de
chaîne ; tout comme "Bonjour!".

Initialisation des chaînes


Comme enseigné dans la dernière leçon, un tableau de caractères peut être déclaré et initialisé comme ceci :

char arr_str[6] = {'H', 'e', 'l', 'l', 'o', '!'} ;

Ici, le tableau arr_str est traité comme un tableau de caractères. Cependant, si vous ajoutez un caractère nul (\0)
dans le tableau, vous pouvez obtenir l'instruction suivante :

char arr_str[7] = {'H', 'e', 'l', 'l', 'o', '!', '\0'} ;

Ici, le tableau arr_str est étendu pour contenir sept éléments ; le dernier élément contient un caractère nul.
Désormais, le tableau de caractères arr_str est considéré comme une chaîne de caractères en raison du caractère
nul qui est ajouté (ajouté à la fin) des données de caractères.

Vous pouvez également initialiser un tableau de caractères avec une constante de chaîne, au lieu d'une liste de
constantes de caractères. Par exemple, l'instruction suivante initialise un tableau de caractères, str, avec une
constante de chaîne, « Bonjour ! » :

char str[7] = "Bonjour !" ;


Machine Translated by Google

Manipulation de chaînes 209

Le compilateur ajoutera automatiquement un caractère nul (\0) à la fin de "Hello!", et traitera le tableau de
caractères comme une chaîne de caractères. Notez que la taille du tableau est spécifiée pour contenir jusqu'à
sept éléments, bien que la constante de chaîne ne comporte que six caractères entre guillemets doubles.
L'espace supplémentaire est réservé au caractère nul qui sera ajouté ultérieurement par le compilateur.

Vous pouvez déclarer un tableau de caractères non dimensionné si vous voulez que le compilateur calcule le
nombre total d'éléments dans le tableau. Par exemple, la déclaration suivante :

char str[] = "J'aime C.";

initialise un tableau de caractères non dimensionné : , str, avec une constante de chaîne. Plus tard, lorsque
le compilateur verra l'instruction, il déterminera l'espace mémoire total nécessaire pour maintenir la chaîne
constante plus un caractère nul supplémentaire ajouté par le compilateur lui­même.

Si vous le souhaitez, vous pouvez également déclarer un pointeur de caractère , puis initialiser le pointeur
avec une constante de chaîne. L'instruction suivante est un exemple :

char *ptr_str = "J'apprends moi­même C.";

Ne spécifiez pas la taille d'un tableau de caractères comme étant trop petite. Sinon, il ne peut pas
contenir une chaîne constante plus un caractère nul supplémentaire. Par exemple, la déclaration
suivante est considérée comme illégale :

char str[4] = "texte" ;


Notez que de nombreux compilateurs C n'émettront pas d'avertissement ou de message d'erreur sur
cette déclaration incorrecte. Les erreurs d'exécution qui pourraient éventuellement survenir en
conséquence pourraient être très difficiles à déboguer. Par conséquent, il est de votre responsabilité
de vous assurer de spécifier suffisamment d'espace pour une chaîne.

L'instruction suivante est correcte, car elle spécifie la taille du tableau de caractères str suffisamment
grand pour contenir la chaîne constante plus un caractère nul supplémentaire :

char str[5] = "texte" ;


13

Constantes de chaîne contre constantes de caractère


Comme vous le savez déjà, une constante de chaîne est une série de caractères entre guillemets (" "). D'autre
part, une constante de caractère est un caractère entouré de guillemets simples (' ').

Lorsqu'une variable de caractère ch et un tableau de caractères str sont initialisés avec le même caractère,
x, comme suit :
Machine Translated by Google

210 Heure 13

char ch = 'x'; char


str[] = "x" ;

1 octet est réservé à la variable de caractère ch et deux octets sont alloués au tableau de caractères str. La raison pour
laquelle un octet supplémentaire est nécessaire pour str est que le compilateur doit ajouter un caractère nul au tableau.

Une autre chose importante est qu'une chaîne, puisqu'il s'agit d'un tableau, est en réalité un pointeur de caractère .
Ainsi, vous pouvez affecter directement une chaîne de caractères à une variable pointeur, comme ceci :

caractère
*ptr_str ; ptr_str = "Une chaîne de caractères.";

Cependant, vous ne pouvez pas affecter une constante de caractère à la variable de pointeur, comme illustré ci­dessous :

ptr_str = 'x' ; /* C'est faux. */

En d'autres termes, la constante de caractère 'x' contient une valeur de droite et la variable de pointeur ptr_str attend une
valeur de gauche. Mais C nécessite les mêmes types de valeurs des deux côtés d'un opérateur d'affectation =.

Il est légal d'assigner une constante de caractère à un pointeur char déréférencé comme ceci :

caractère *ptr_str ;
*ptr_str = 'x' ;

Maintenant, les valeurs des deux côtés de l' opérateur = sont du même type.

Le programme du Listing 13.1 montre comment initialiser ou affecter des tableaux de caractères avec des constantes
de chaîne.

LISTE 13.1 Initialisation des chaînes

1 : /* 13L01.c : Initialisation des chaînes */


2 : #include <stdio.h> 3 : 4 : main()
5 : { 6 : 7 : 8 : 9 : 10 : 11 : 12 : 13 : 14 : 15 :

char str1[] = {'A', ' ', 's', 't', 'r',


'i', 'n', 'g', ' ', 'c', 'o', 'n ', 's', 't', 'a', 'n', 't', '\0'} ;

char str2[] = "Une autre constante de chaîne" ;


caractère *ptr_str ; int je ;

/* affiche str1 */ for (i=0;


str1[i]; i++)
printf("%c", str1[i]);
Machine Translated by Google

Manipulation de chaînes 211

16 : printf("\n"); /*
17 : affiche str2 */ for (i=0;
18 : str2[i]; i++)
19 : printf("%c", str2[i]);
20 : printf("\n"); /* assigne une
21 : chaîne à un pointeur */ ptr_str = "Assigne
22 : une chaîne à un pointeur."; pour (i=0; *ptr_str; i++)
23 :
24 : printf("%c", *ptr_str++); renvoie
25 : 0;
26 : }

La sortie suivante s'affiche après la création et l'exécution de l'exécutable 13L01.exe du


programme du Listing 13.1.
Une constante chaîne
SORTIR Une autre constante chaîne
Affecte une chaîne à un pointeur.

Comme vous pouvez le voir dans le Listing 13.1, il y a deux tableaux de caractères, str1 et
UNE ANALYSE
str2, qui sont déclarés et initialisés aux lignes 6–9. Dans la déclaration de str1, un ensemble
de constantes de caractères, y compris un caractère nul, est utilisé pour initialiser le tableau. Pour
str2, une constante de chaîne est affectée au tableau de la ligne 9. Le compilateur ajoutera un
caractère nul à str2. Notez que str1 et str2 sont déclarés comme des tableaux non dimensionnés pour
lesquels le compilateur déterminera automatiquement la quantité de mémoire nécessaire. L'instruction
de la ligne 10 déclare une variable de pointeur char , ptr_str.

La boucle for des lignes 14 et 15 affiche ensuite tous les éléments de str1. Comme le dernier élément
contient un caractère nul (\0) évalué comme 0, str1[i] est utilisé comme expression conditionnelle de l'
instruction for . L'expression str1[i] prend une valeur différente de zéro pour chaque élément de str1
sauf celui contenant le caractère nul. Après l'exécution de la boucle for , la chaîne Une constante de
chaîne s'affiche à l'écran.

De même, une autre boucle for dans les lignes 18 et 19 affiche la constante de chaîne affectée à
13
str2 en plaçant chaque élément du tableau à l'écran. Étant donné que le compilateur ajoute un
caractère nul au tableau, l'expression str2[i] est évaluée dans l' instruction for .
La boucle for arrête d'itérer lorsque str2[i] est évalué à 0. À ce moment­là, le contenu de la constante
de chaîne, Une autre constante de chaîne, a déjà été affiché sur le
écran.

L'instruction de la ligne 22 affecte une constante de chaîne, « Attribuer une chaîne à un pointeur. », :
à la variable de pointeur char ptr_str. De plus, une boucle for est utilisée pour afficher la constante de
la chaîne en plaçant chaque caractère de la chaîne à l'écran (voir lignes 23 et 24). Notez que le
pointeur déréférencé *ptr_str est utilisé pour faire référence à l'un des caractères de la chaîne
Machine Translated by Google

212 Heure 13

constante. Lorsque le caractère nul ajouté à la chaîne est rencontré, *ptr_str prend la valeur 0, ce qui
provoque l'arrêt de l'itération de la boucle for . À la ligne 24, l'expression *ptr_str++ déplace le pointeur
vers le caractère suivant de la chaîne après la récupération du caractère actuel auquel le pointeur fait
référence. Dans l'heure 16, "Appliquer des pointeurs", vous en apprendrez plus sur l'arithmétique des
pointeurs.

Quelle est la longueur d'une chaîne ?


Parfois, vous devez savoir combien d'octets sont pris par une chaîne, car sa longueur peut être inférieure
à la longueur de son tableau de caractères . En C, vous pouvez utiliser une fonction appelée strlen() pour
mesurer la longueur d'une chaîne.

La fonction strlen() Examinons la syntaxe

de la fonction strlen() .

La syntaxe de la fonction strlen() est

#include <string.h> size_t


,SYNTAXE
strlen(const char *s);

Ici s est une variable de pointeur char . La valeur de retour de la fonction est le nombre d'octets dans
la chaîne, sans compter le caractère nul '\0'. size_t est un type de données défini dans le fichier d'en­
tête string.h . La taille du type de données dépend du système informatique particulier. Notez que
string.h doit être inclus dans votre programme avant de pouvoir appeler la fonction strlen() .
,
Le Listing 13.2 donne un exemple d'utilisation de la fonction strlen() pour mesurer la longueur des chaînes.

LISTE 13.2 Mesurer la longueur des cordes

1 : /* 13L02.c : mesure de la longueur de la chaîne */


2 : #include <stdio.h> 3 : #include <string.h> 4 :

5 : principal()
6:{7:
char str1[] = {'A', ' ', 's', 't', 'r', 'i',
'n', 'g', ' ', 'c', 'o', 'n ', 's', 't', 'a', 'n', 't', '\0'} ;

char str2[] = "Une autre constante de chaîne" ; char


8 : 9 : 10 : 11*ptr_str
: = "Attribuer une chaîne à un pointeur." ;
12 :
13: printf("La longueur de str1 est : %d octets\n", strlen(str1)); printf("La longueur
14: de str2 est : %d octets\n", strlen(str2)); printf("La longueur de la chaîne assignée
à ptr_str est : %d octets\n",
15h16: strlen(ptr_str));
Machine Translated by Google

Manipulation de chaînes 213

renvoie 0 ;
17 : 18 : }

J'obtiens la sortie suivante en exécutant l'exécutable, 13L02.exe, du programme du Listing 13.2.

La longueur de str1 est : 17 octets


SORTIR La longueur de str2 est : 23 octets
La longueur de la chaîne affectée à ptr_str est : 29 octets

Dans le Listing 13.2, deux tableaux de caractères , str1 et str2, et une variable de
UNE ANALYSE
pointeur, ptr_str, sont déclarés et initialisés aux lignes 7 à 11, respectivement.

Ensuite, l'instruction de la ligne 13 obtient la longueur de la constante de chaîne détenue par str1 et
imprime le résultat. D'après le résultat, vous pouvez voir que le caractère nul (\0) à la fin de str1 n'est pas
compté par la fonction strlen() .

Aux lignes 14 à 16, les longueurs des constantes de chaîne référencées par str2 et ptr_str sont
mesurées et affichées à l'écran. Les résultats indiquent que la fonction strlen() ne compte pas non plus les
caractères nuls ajoutés aux deux constantes de chaîne par le compilateur.

Copier des chaînes avec strcpy()


Si vous souhaitez copier une chaîne d'un tableau à un autre, vous pouvez copier chaque élément du
premier tableau dans l'élément correspondant du second tableau, ou vous pouvez simplement appeler la
fonction C strcpy() pour faire le travail à votre place.

La syntaxe de la fonction strcpy() est

#include <string.h> char


,SYNTAXE *strcpy(char *dest, const char *src);

Ici, le contenu de la chaîne src est copié dans le tableau référencé par dest. La fonction strcpy()
renvoie la valeur de src si elle réussit. Le fichier d'en­tête string.h doit être inclus dans votre
, programme avant que la fonction strcpy() ne soit appelée.
13
Le programme du Listing 13.3 montre comment copier une chaîne d'un tableau à un autre en appelant la
fonction strcpy() ou en le faisant vous­même.

LISTE 13.3 Copier des chaînes

1 : /* 13L03.c : Copie de chaînes */ 2 :


#include <stdio.h> 3 : #include <string.h> 4 :
5 : main()

continue
Machine Translated by Google

214 Heure 13

LISTE 13.3 suite

6:{7:
char str1[] = "Copier une chaîne."; char
str2[15] ; caractère str3[15] ; int je ;

8 : 9 : 10 : 11 :
12 : /* avec strcpy() */ strcpy(str2,
13: str1); /* sans strcpy() */ for
14: (i=0; str1[i]; i++) str3[i] = str1[i];
str3[i] = '\0' ; /* affiche str2 et str3
*/ printf("Le contenu de str2
15 : 16 : 17 en
: utilisant strcpy : %s\n", str2);
printf("Le contenu de str3 sans utiliser
strcpy : %s\n", str3); renvoie 0 ;

18h19h20h21h
22 : }

Une fois l'exécutable 13L03.exe créé et exécuté, la sortie suivante s'affiche :

Le contenu de str2 à l'aide de strcpy : copiez une chaîne.


SORTIR
Le contenu de str3 sans utiliser strcpy : copiez une chaîne.

UNE ANALYSE Trois tableaux de caractères, str1 , str2 et str3, sont déclarés dans le Listing 13.3. De
plus, str1 est initialisé avec une constante de chaîne, "Copier une chaîne.", à la ligne 7.

L'instruction de la ligne 13 appelle la fonction strcpy() pour copier le contenu de str1 (y compris le
caractère nul ajouté par le compilateur) dans le tableau référencé par str2.

Les lignes 15 à 17 montrent une autre façon de copier le contenu de str1 dans un tableau référencé
par str3. Pour ce faire, la boucle for des lignes 15 et 16 continue de copier les caractères de str1
dans les éléments correspondants de str3 les uns après les autres, jusqu'à ce que le caractère nul
(\0) ajouté par le compilateur soit rencontré. Lorsque le caractère nul est rencontré, l' expression
str1[i] utilisée comme condition de l' instruction for à la ligne 15 est évaluée à 0, ce qui termine la
boucle.

Étant donné que la boucle for ne copie pas le caractère nul de str1 vers str3, l'instruction de la ligne
17 ajoute un caractère nul au tableau référencé par str3. En C, il est très important de s'assurer que
tout tableau utilisé pour stocker une chaîne a un caractère nul à la fin de la chaîne.

Pour prouver que la constante de chaîne référencée par str1 a été copiée avec succès dans str2
et str3 , le contenu détenu par str2 et str3 s'affiche à l'écran. Noter que
Machine Translated by Google

Manipulation de chaînes 215

le spécificateur de format de chaîne %s et les adresses de début de str2 et str3 sont transmis à l' appel
printf() aux lignes 19 et 20 pour imprimer tous les caractères, à l'exception du caractère nul, stockés
dans str2 et str3. Les résultats affichés à l'écran montrent que str2 et str3 ont exactement le même
contenu que str1.

Lecture et écriture de chaînes


Concentrons­nous maintenant sur la façon de lire ou d'écrire des chaînes avec les flux d'entrée et
de sortie standard, c'est­à­dire stdin et stdout. En C, il existe plusieurs fonctions que vous pouvez utiliser
pour gérer la lecture ou l'écriture de chaînes. Les sous­sections suivantes présentent certaines de ces
fonctions.

Les fonctions gets() et puts() La fonction gets()


peut être utilisée pour lire des caractères à partir du flux d'entrée standard.
La syntaxe de la fonction gets() est
#include <stdio.h> char
,SYNTAXE *gets(char *s);

Ici, les caractères lus à partir du flux d'entrée standard sont stockés dans le tableau de caractères
identifié par s. La fonction gets() arrête la lecture et ajoute un caractère nul \0 au tableau lorsqu'un
caractère de nouvelle ligne ou de fin de fichier (EOF) est rencontré.
La fonction renvoie s si elle se termine avec succès. Sinon, un pointeur nul est renvoyé.
,
La fonction puts() peut être utilisée pour écrire des caractères dans le flux de sortie standard (c'est­à­dire
stdout) .

La syntaxe de la fonction met est


#include <stdio.h> int
,SYNTAXE met(const char *s);

Ici s fait référence au tableau de caractères qui contient une chaîne. La fonction puts() écrit la 13
chaîne dans stdout. Si la fonction réussit, elle renvoie 0. Sinon, une valeur différente de zéro est
renvoyée.

La fonction puts() ajoute un caractère de saut de ligne pour remplacer le caractère nul à la fin d'un
, tableau de caractères.

Les fonctions gets() et puts() nécessitent toutes deux le fichier d'en­tête stdio.h. Dans le Listing 13.4,
vous pouvez voir l'application des deux fonctions.
Machine Translated by Google

216 Heure 13

LISTE 13.4 Utilisation des fonctions gets() et puts()

1 : /* 13L04.c : Utilisation de gets() et puts() */


2 : #include <stdio.h> 3 : 4 : main() 5 : { 6 :

char str[80] ; int


7: je, delt = 'a' ­ 'A';
8:
9: printf("Entrez une chaîne de moins de 80 caractères :\n");
10 : obtient( str ); je = 0 ; tandis que (str[i]){ si ((str[i] >= 'a') && (str[i] <=
11 : 'z'))
12 :
13 :
14 : str[i] ­= delt ; /* convertir en majuscule */ ++i; } printf("La
15 : chaîne saisie est (en majuscule) :\n"); met( str ); renvoie 0 ;
16 :
17 :
18 :
19 :
20 : }

Lors de l'exécution de l'exécutable 13L04.exe, j'entre une ligne de caractères (en gras ci­dessous)
à partir du clavier et les caractères (tous en majuscules) s'affichent à l'écran.
Entrez une chaîne de moins de 80 caractères :
SORTIR Ceci est un test.
La chaîne saisie est (en majuscule) : CECI EST
UN TEST.

Le programme du Listing 13.4 accepte une chaîne de caractères saisie à partir du clavier
UNE ANALYSE
(c'est­à­dire stdin), puis convertit tous les caractères minuscules en majuscules
ceux. Enfin, la chaîne modifiée est remise à l'écran.

À la ligne 6, un tableau de caractères (str) est déclaré et peut contenir jusqu'à 80 caractères.
La fonction gets() de la ligne 10 lit tous les caractères entrés par l'utilisateur à partir du clavier
jusqu'à ce que l'utilisateur appuie sur la touche Entrée, qui est interprétée comme un caractère de
saut de ligne. Les caractères lus par la fonction gets() sont stockés dans le tableau de caractères indiqué par str.
Le caractère de nouvelle ligne n'est pas enregistré dans str. Au lieu de cela, un caractère nul est ajouté au
tableau en tant que terminateur.

La boucle while des lignes 12 à 15 a une expression conditionnelle, str[i]. La boucle while continue
d'itérer tant que str[i] donne une valeur différente de zéro. Dans la boucle, la valeur de chaque
caractère représenté par str[i] est évaluée à la ligne 13, pour savoir si le
Machine Translated by Google

Manipulation de chaînes 217

caractère est un caractère minuscule dans la plage de a à z. Si le caractère est l'un des caractères minuscules, il est
converti en majuscule en soustrayant la valeur d'une variable int , delt, de sa valeur courante à la ligne 14. La variable
delt est initialisée à la ligne 7 par la valeur de l'expression 'a ' ­ 'A', qui est la différence entre la valeur numérique d'un

caractère minuscule et son équivalent majuscule. En d'autres termes, en soustrayant la différence de 'a' et 'A' de la
valeur entière minuscule, nous obtenons la valeur entière majuscule.

Ensuite, la fonction puts() de la ligne 18 renvoie la chaîne avec tous les caractères majuscules vers stdout, qui va
à l'écran par défaut. Un caractère de saut de ligne est ajouté par la fonction puts() lorsqu'elle rencontre le caractère
nul à la fin de la chaîne.

Utilisation de %s avec la fonction printf()


Nous avons utilisé la fonction printf() dans de nombreux exemples de programme dans ce livre. Comme vous
le savez, de nombreux spécificateurs de format peuvent être utilisés avec la fonction printf() pour spécifier différents
formats d'affichage pour des données de différents types.

Par exemple, vous pouvez utiliser le spécificateur de format de chaîne, %s, avec la fonction printf() pour afficher
une chaîne de caractères enregistrée dans un tableau. (Reportez­vous à l'exemple du Listing 13.3.)

Dans la section suivante, la fonction scanf() est présentée comme un moyen de lire les valeurs de divers types de
données avec différents spécificateurs de format, y compris le spécificateur de format %s.

La fonction scanf() La fonction scanf() fournit

un autre moyen de lire des chaînes à partir du flux d'entrée standard. De plus, cette fonction peut en fait être
utilisée pour lire différents types de données d'entrée.
Les formats des arguments de la fonction scanf() sont assez similaires à ceux utilisés dans la fonction printf() .

La syntaxe de la fonction scanf() est

#include <stdio.h> int


,SYNTAXE
scanf(const char *format,...); 13
Ici, divers spécificateurs de format peuvent être inclus dans la chaîne de format référencée par le format de
variable de pointeur char . Si la fonction scanf() se termine avec succès, elle renvoie le nombre d'éléments de
données lus à partir de stdin. Si une erreur se produit, la fonction scanf() renvoie EOF (end­of­file).
,
L'utilisation du spécificateur de format de chaîne %s indique à la fonction scanf() de continuer à lire les caractères
jusqu'à ce qu'un espace, une nouvelle ligne, une tabulation, une tabulation verticale ou un saut de page soit rencontré.
Les caractères lus par la fonction scanf() sont stockés dans un tableau référencé par l'argument correspondant. Le
tableau doit être suffisamment grand pour stocker les caractères d'entrée.
Machine Translated by Google

218 Heure 13

Un caractère nul est automatiquement ajouté au tableau après la lecture de la chaîne.

Notez qu'avec scanf(), contrairement à printf(), vous devez passer des pointeurs vers vos arguments
pour que la fonction scanf() puisse modifier leurs valeurs.

Le programme du Listing 13.5 montre comment utiliser divers spécificateurs de format avec
la fonction scanf() .

LISTE 13.5 Utilisation de la fonction scanf() avec divers spécificateurs de format

1 : /* 13L05.c : Utilisation de scanf() */


2 : #include <stdio.h> 3 : 4 : main() 5 :
{6:7:

char str[80] ; int


x, y ; flottant z ;

printf("Entrez deux entiers séparés par un espace :\n"); scanf("%d %d",


8 : 9 : 10 : 11&x,
:&y); printf("Entrez un nombre à virgule flottante :\n"); scanf("%f", &z);
12 : printf("Entrez une chaîne :\n"); scanf("%s", str); printf("Voici ce que vous
13: avez saisi :\n"); printf("%d %d\n%f\n%s\n", x, y, z, str); renvoie 0 ;
14:

15 : 16 : 17 :
18 :
19 : }

La sortie suivante s'affiche à l'écran après avoir exécuté l'exécutable 13L05.exe et saisi les données
(qui apparaissent en gras) à partir de mon clavier :

Saisissez deux nombres entiers séparés par un


SORTIR espace : 10 12345 Saisissez un nombre à virgule
flottante : 1,234567 Saisissez une chaîne : Test Voici
ce que vous avez saisi : 10 12345 1,234567 Test

Dans le Listing 13.5, il y a un tableau de caractères (str), deux variables int (x et y) et une
UNE ANALYSE
variable flottante déclarée aux lignes 6–8.
Machine Translated by Google

Manipulation de chaînes 219

Ensuite, la fonction scanf() de la ligne 11 lit deux entiers entrés par l'utilisateur et les enregistre dans les
emplacements mémoire réservés aux variables entières x et y. L'opérateur adresse de permet d'obtenir les
adresses mémoire des variables. L'instruction de la ligne 13 lit et stocke un nombre à virgule flottante dans z.
Notez que les spécificateurs de format, %d et %f, sont utilisés pour spécifier les formats appropriés pour les
nombres entrés dans les lignes 11 et 13.

La ligne 15 utilise la fonction scanf() et le spécificateur de format %s pour lire une série de caractères saisis
par l'utilisateur, puis enregistre les caractères (plus un caractère nul comme terminateur) dans le tableau
pointé par str. L'opérateur d'adresse de n'est pas utilisé ici, car str lui­même pointe vers l'adresse de début
du tableau.

Pour prouver que la fonction scanf() lit tous les nombres et caractères saisis par l'utilisateur, la fonction
printf() à la ligne 17 affiche le contenu enregistré dans x, y, z et str à l'écran. Effectivement, le résultat
montre que le scanf() a fait son travail.

Une chose dont vous devez être conscient est que la fonction scanf() ne commence pas à lire l'entrée
tant que la touche Entrée n'est pas enfoncée. Les données saisies à partir du clavier sont placées dans un
tampon d'entrée. Lorsque la touche Entrée est enfoncée, la fonction scanf() recherche son entrée dans le
tampon. Vous en apprendrez plus sur l'entrée et la sortie mises en mémoire tampon dans l'heure 21, « Lecture
et écriture avec des fichiers ».

Résumé
Dans cette leçon, vous avez appris les fonctions et concepts importants suivants concernant les chaînes
en C :

• Une chaîne est un tableau de caractères avec un caractère nul marquant la fin de la chaîne. • Une

constante chaîne est une série de caractères entourés de guillemets doubles. • Le compilateur C

ajoute automatiquement un caractère nul à une constante de chaîne qui a


été utilisé pour initialiser un tableau.

• Vous ne pouvez pas affecter une constante de chaîne à un pointeur de caractère

déréférencé. • La fonction strlen() peut être utilisée pour mesurer la longueur d'une chaîne. Cette fonction
13
ne compte pas le caractère nul.

• Vous pouvez copier une chaîne d'un tableau à un autre en appelant la fonction C
strcpy().

• La fonction gets() peut être utilisée pour lire une série de caractères. Cette fonction arrête la lecture
lorsque le caractère de nouvelle ligne ou de fin de fichier (EOF) est rencontré. La fonction ajoute un
caractère nul à la fin de la chaîne.
Machine Translated by Google

220 Heure 13

• La fonction puts() envoie tous les caractères, à l'exception du caractère nul, d'une chaîne à la
sortie standard et ajoute un caractère de saut de ligne à la sortie.

• Vous pouvez lire différents éléments de données avec la fonction scanf() en utilisant divers for
spécificateurs de tapis.

Dans la leçon suivante, vous découvrirez les concepts de portée et de stockage en C.

Questions et réponses

Q Qu'est­ce qu'une chaîne ? Comment connaître sa longueur ?

A En C, une chaîne est stockée dans un tableau de caractères et se termine par un caractère nul
('\0'). Le caractère nul indique aux fonctions de chaîne (telles que puts() et strcpy qu'elles ont
atteint la fin de la chaîne.

La fonction C strlen() peut être utilisée pour mesurer la longueur d'une chaîne. Si elle réussit,
la fonction strlen() renvoie le nombre total d'octets pris par la chaîne ; cependant, le caractère
nul dans la chaîne n'est pas compté.

Q Quelles sont les principales différences entre une constante de chaîne et un caractère
constante?

Une constante de chaîne est une série de caractères entourés de guillemets doubles, tandis qu'une
constante de caractère est un caractère unique entouré de guillemets simples. Le compilateur
ajoutera un caractère nul à la chaîne lorsqu'il est utilisé pour initialiser un tableau.
Par conséquent, un octet supplémentaire doit être réservé pour le caractère nul. Par contre,
une constante caractère ne prend qu'1 octet en mémoire et n'est pas stockée dans un
déployer.

Q La fonction gets() enregistre­t­elle le caractère de nouvelle ligne de l'entrée standard


flux?

R Non. La fonction gets() continue de lire les caractères du flux d'entrée standard jusqu'à ce qu'un
caractère de saut de ligne ou de fin de fichier soit rencontré. Au lieu d'enregistrer le caractère de
nouvelle ligne, la fonction gets() ajoute un caractère nul à la chaîne et le stocke dans le tableau
référencé par l'argument de la fonction gets() .

Q Quels types de données la fonction scanf() peut­ elle lire ?

R Selon les spécificateurs de format de style printf() que vous transmettez à la fonction, scanf() peut
lire divers types de données, comme une série de caractères, des entiers ou des nombres à
virgule flottante. Contrairement à gets(), scanf() arrête de lire l'élément d'entrée actuel (et passe
à l'élément d'entrée suivant s'il y en a un) lorsqu'il rencontre un espace, une nouvelle ligne, une
tabulation, une tabulation verticale ou un saut de page.
Machine Translated by Google

Manipulation de chaînes 221

Atelier
Pour aider à consolider votre compréhension de la leçon de cette heure, nous vous encourageons à
répondre aux questions du quiz et à terminer les exercices fournis dans l'atelier avant de passer à la
leçon suivante. Les réponses et les conseils aux questions et exercices sont donnés dans l'annexe B,
« Réponses aux questions et exercices du quiz ».

Questionnaire

1. Dans la liste suivante, quelles déclarations sont légales ?

• char str1[5] = « Texas » ;

• char str2[] = "Une chaîne de caractères" ;

• car str3[2] = "A" ;

• car str4[2] = « TX » ;

2. Étant donné une variable de pointeur char ptr_ch, les déclarations suivantes sont­elles légales ?

• *ptr_ch = 'a';

• ptr_ch = "Une chaîne de caractères" ;

• ptr_ch = 'x';

• *ptr_ch = "C'est le quiz 2." ;

3. La fonction puts() peut­elle imprimer le caractère nul dans un tableau de caractères ?

4. Quel spécificateur de format utilisez­vous avec la fonction scanf() pour lire une chaîne, et lequel
utilisez­vous pour lire un nombre à virgule flottante ?

Des exercices

1. Étant donné un tableau de caractères dans l'instruction suivante,


char str1[] = "Ceci est l'exercice 1.";

écrivez un programme pour copier la chaîne de str1 dans un autre tableau, appelé str2.

2. Écrivez un programme pour mesurer la longueur d'une chaîne en évaluant les éléments d'un tableau
13
de caractères un par un jusqu'à ce que vous atteigniez le caractère nul. Pour prouver que vous
obtenez le bon résultat, vous pouvez utiliser la fonction strlen() pour mesurer à nouveau la même chaîne.

3. Réécrivez le programme du Listing 13.4. Cette fois, convertissez tous les caractères majuscules en
leurs homologues minuscules.

4. Écrivez un programme qui utilise la fonction scanf() pour lire deux nombres entiers saisis par
l'utilisateur, additionne les deux nombres entiers, puis affiche la somme à l'écran.
Machine Translated by Google
Machine Translated by Google

HEURE 14
Présentation de l'étendue
et des classes de stockage
Personne ne possède rien et tout ce que chacun a est l'usage de ses biens présumés.

—P. Wylie

Au cours des heures précédentes, vous avez appris à déclarer des variables de différents
types de données, ainsi qu'à initialiser et à utiliser ces variables. Il a été supposé que vous
pouvez accéder aux variables de n'importe où. Maintenant, la question est : pouvez­vous
déclarer des variables qui ne sont accessibles qu'à certaines parties d'un programme ? Dans
cette leçon, vous découvrirez la portée et les classes de stockage des données en C. Les
principaux sujets abordés dans cette leçon sont

• Étendue du bloc •

Étendue de la fonction •

Étendue du fichier •

Étendue du programme
Machine Translated by Google

224 Heure 14

• Le spécificateur

automatique • Le

spécificateur statique • Le

spécificateur de registre • Le spécificateur externe


• Le modificateur const

• Le modificateur volatil

Masquer des données


Pour résoudre un problème complexe dans la pratique, le programmeur divise normalement le problème
en plus petits morceaux et traite chaque morceau du problème en écrivant une ou deux fonctions (ou
routines). Ensuite, toutes les fonctions sont rassemblées pour former un programme complet qui peut être
utilisé pour résoudre le problème complexe.

Dans le programme complet, il peut y avoir des variables qui doivent être partagées par toutes les
fonctions. D'autre part, l'utilisation de certaines autres variables peut être limitée à certaines fonctions
uniquement. Autrement dit, la visibilité de ces variables est limitée et les valeurs affectées à ces variables
sont masquées pour de nombreuses fonctions.

Limiter la portée des variables est très utile lorsque plusieurs programmeurs travaillent sur différentes
parties du même programme. S'ils limitent la portée de leurs variables à leurs morceaux de code, ils n'ont
pas à se soucier des conflits avec des variables du même nom utilisées par d'autres dans d'autres parties
du programme.

En C, vous pouvez déclarer une variable et indiquer son niveau de visibilité en désignant sa portée.
Ainsi, les variables à portée locale ne sont accessibles qu'à l'intérieur du bloc dans lequel elles sont
déclarées.

Les sections suivantes vous apprennent à déclarer des variables avec différentes portées.

Portée du bloc Dans

cette section, un bloc fait référence à tout ensemble d'instructions entre accolades ({ et }). Une variable
déclarée dans un bloc a une portée de bloc. Ainsi, la variable est active et accessible depuis son point de
déclaration jusqu'à la fin du bloc. Parfois, la portée de bloc est également appelée portée locale.

Par exemple, la variable i déclarée dans le bloc de la fonction principale suivante a une portée de bloc :

int main() {

int je ; /* bloquer la portée */


Machine Translated by Google

Présentation de l'étendue et des classes de stockage 225

.
.
.
renvoie 0 ;
}

Habituellement, une variable avec une portée de bloc est appelée une variable locale. Notez que les variables
locales doivent être déclarées au début du bloc, avant les autres instructions.

Portée du bloc imbriqué


Vous pouvez également déclarer des variables dans un bloc imbriqué. Si une variable déclarée à l'extérieur
bloc partage le même nom avec l'une des variables du bloc interne, la variable du bloc externe est masquée
par celle du bloc interne. Ceci est vrai pour la portée du bloc interne.

Le Listing 14.1 montre un exemple de portées de variables dans des blocs imbriqués.

TAPER LISTE 14.1 Impression de variables avec différents niveaux de portée

1 : /* 14L01.c : étendues dans un bloc imbriqué */


2 : #include <stdio.h> 3 : 4 : main()
5 : { 6 : 7 : 8 : 9 : 10 : 11 : 12 : 13 : 14 : 15 : 16 : 17 :
18 : 19 : }

entier je = 32 ; /* bloquer la portée 1*/

printf("Dans le bloc externe : i=%d\n", i);

{ /* le début du bloc intérieur */ int i, j; /* bloc scope


2, int i cache l'int extérieur i*/

printf("Dans le bloc interne :\n"); pour (i=0,


j=10; i<=10; i++, j­­)
printf("je=%2d, j=%2d\n", je, j); } /* la fin
du bloc
i=%d\n”,
intérieur
i); */
renvoie
printf(“Dans
0; le bloc extérieur :

La sortie suivante s'affiche à l'écran après la création et l'exécution de l'exécutable (14L01.exe) du programme
du Listing 14.1 :

Dans le bloc extérieur : i=32


14
SORTIR Dans le bloc intérieur : i= 0,
j=10 i= 1, j= 9 i= 2, j= 8
Machine Translated by Google

226 Heure 14

je= 3, j= 7
je= 4, j= 6
je= 5, j= 5
je= 6, j= 4
je= 7, j= 3
je= 8, j= 2
je= 9, j= 1 je
=10, j= 0
Dans le bloc extérieur : i=32

Le but du programme du Listing 14.1 est de vous montrer les différentes portées des variables
UNE ANALYSE
dans les blocs imbriqués. Comme vous pouvez le voir, il y a deux blocs imbriqués dans le
Listing 14.1. La variable entière i déclarée à la ligne 6 est visible dans le bloc extérieur délimité par les
accolades ({ et }) aux lignes 5 et 19. Deux autres variables entières, i et j, sont déclarées à la ligne 11
et ne sont visibles qu'à l'intérieur du bloc bloc de la ligne 10 à la ligne 16.

Bien que la variable entière i dans le bloc externe ait le même nom que l'une des variables entières
dans le bloc interne, les deux variables entières ne sont pas accessibles en même temps en raison de
leurs portées différentes.

Pour le prouver, la ligne 8 imprime la valeur, 32, contenue par i dans le bloc externe pour la première
fois. Ensuite, la boucle for des lignes 14 et 15 affiche 10 paires de valeurs affectées à i et j dans le bloc
interne. À ce stade, il n'y a aucun signe que la variable entière i dans le bloc externe ait des effets sur
celle du bloc interne. Lorsque le bloc interne est fermé, les variables du bloc interne ne sont plus
accessibles. En d'autres termes, toute tentative d'accès à j depuis le bloc externe serait illégale.

Enfin, l'instruction de la ligne 17 imprime à nouveau la valeur de i dans le bloc externe pour savoir si la
valeur a été modifiée en raison de la variable entière i dans le bloc interne. Le résultat montre que ces
deux variables entières se cachent l'une de l'autre et qu'aucun conflit ne se produit.

Portée de la fonction La
portée de la fonction indique qu'une variable est active et visible du début à la fin d'une fonction.

En C, seule une étiquette goto a une portée de fonction. Par exemple, l' étiquette goto , start, illustrée
dans la portion de code suivante a une portée de fonction :

int main() {

int je ; /* bloquer la portée */


.
.
.
start : /* Une étiquette goto a une portée de fonction */
Machine Translated by Google

Présentation de l'étendue et des classes de stockage 227

.
.
.
aller commencer ; /* l'instruction goto */
.
.
.
renvoie 0 ;
}

Ici, le label start est visible du début à la fin de la fonction main() .


Par conséquent, il ne devrait pas y avoir plus d'une étiquette portant le même nom dans la fonction
main() .

Portée du programme Une


variable est dite avoir une portée de programme lorsqu'elle est déclarée en dehors d'une fonction.
Par exemple, regardez le code suivant :

int x = 0 ; /* portée du programme


flottant y = 0,0 ; */ /* portée du programme */
int main() {

int je ; /* bloquer la portée */


.
.
.
renvoie 0 ;
}

Ici, la variable int x et la variable flottante y ont une portée de programme.

Les variables avec portée de programme sont également appelées variables globales, qui sont visibles
parmi tous les fichiers source qui composent un programme exécutable. Notez qu'une variable globale
est déclarée avec un initialiseur en dehors d'une fonction.

Le programme du Listing 14.2 démontre la relation entre les variables avec la portée du programme et
les variables avec la portée du bloc.

LISTE 14.2 Relation entre la portée du programme et la portée du bloc


TAPER

1 : /* 14L02.c : portée du programme vs portée du bloc */


2 : #include <stdio.h> 3 : 4 : int x = 1234 ; /* portée du
programme */ 5 : double y = 1,234567 ; /* portée du
14
programme */

continue
Machine Translated by Google

228 Heure 14

LISTE 14.2 suite

6 : 7 : void function_1() 8 : { 9 :
10 : } 11 : 12 : main() 13 :
{ 14 : 15 : 16 : 17 : 18function_1
printf("De : 19 : :\nx=%d, y=%f\n", x, y);
20 : 21 : 22 : 23 : 24 : 25 : }

int x = 4321 ; /* bloquer la portée 1*/

fonction_1();
printf("Dans le bloc principal :\nx=%d, y=%f\n", x, y); /* un bloc imbriqué */ {

y double = 7,654321 ; /* étendue du bloc 2 */ function_1();


printf("Dans le bloc imbriqué :\nx=%d, y=%f\n", x, y);

} renvoie 0 ;

J'ai la sortie suivante affichée à l'écran après la création et l'exécution de l'exécutable 14L02.exe
sur ma machine :
À partir de function_1 :
SORTIR x=1234, y=1.234567 Dans
le bloc principal : x=4321,
y=1.234567 À partir de
function_1 : x=1234, y=1.234567
Dans le bloc imbriqué :

x=4321, y=7.654321

UNE ANALYSE
Comme vous pouvez le voir dans le Listing 14.2, il y a deux variables globales, x et y, avec la
portée du programme ; ils sont déclarés aux lignes 4 et 5.

Aux lignes 7 à 10, une fonction, appelée function_1(), est déclarée. (Plus de détails sur les
déclarations de fonction et les prototypes seront enseignés dans l'heure suivante.) La fonction
function_1() ne contient qu'une seule instruction ; il imprime les valeurs détenues par x et y. Étant
donné qu'aucune déclaration de variable n'est faite pour x ou y dans le bloc fonction, les valeurs des
variables globales x et y sont utilisées pour l'instruction à l'intérieur de la fonction. Pour prouver cela,
function_1() est appelée deux fois aux lignes 16 et 21, respectivement, à partir de deux blocs imbriqués.
La sortie montre que les valeurs des deux variables globales x et y sont transmises à printf()
dans le corps de la fonction function_1() .

Ensuite, la ligne 14 déclare une autre variable entière, x, avec une portée de bloc, qui peut
remplacer la variable globale x dans le bloc de la fonction main() . Le résultat réalisé par le
Machine Translated by Google

Présentation de l'étendue et des classes de stockage 229

l'instruction à la ligne 17 montre que la valeur de x est la valeur de la variable locale x avec

portée du bloc, alors que la valeur de y est toujours celle de la variable globale y.

Il y a un bloc imbriqué dans les lignes 19 et 23, dans lequel une autre variable double y, avec une portée
de bloc, est déclarée et initialisée. Comme la variable x dans le bloc main() , cette variable, y, dans le bloc
imbriqué remplace la variable globale y. L'instruction de la ligne 22 affiche les valeurs des variables
locales x et y à l'écran

Parce qu'une variable globale est visible parmi les différents fichiers source d'un
programme, l'utilisation de variables globales augmente la complexité de votre programme,
ce qui rend votre programme difficile à maintenir ou à déboguer. Généralement, il n'est pas
recommandé de déclarer et d'utiliser des variables globales, sauf si cela est absolument
nécessaire. Par exemple, vous pouvez déclarer une variable globale dont la valeur est utilisée
(mais jamais modifiée) par plusieurs sous­programmes de votre programme. (Dans l'heure
23, « Compilation de programmes : le préprocesseur C », vous apprendrez à utiliser la
directive #define pour définir des constantes qui sont utilisées à de nombreux endroits dans
un programme.)

Avant d'introduire la portée du fichier, permettez­moi d'abord de parler des spécificateurs de classe de stockage.

Les spécificateurs de classe de stockage


En C, la classe de stockage d'une variable fait référence à la combinaison de ses régions spatiales et
temporelles.

Vous avez appris la portée, qui spécifie la région spatiale d'une variable. Maintenant, concentrons­nous
sur la durée, qui indique la région temporelle d'une variable.

Il existe quatre spécificateurs et deux modificateurs qui peuvent être utilisés pour indiquer la durée d'une
variable. Ces spécificateurs et modificateurs sont présentés dans les sections suivantes.

Le spécificateur automatique

Le spécificateur automatique est utilisé pour indiquer que l'emplacement mémoire d'une
variable est temporaire. En d'autres termes, l'espace réservé d'une variable dans la mémoire peut être
effacé ou déplacé lorsque la variable est hors de sa portée.

Seules les variables avec une portée de bloc peuvent être déclarées avec le spécificateur automatique . 14
Le mot­clé auto est cependant rarement utilisé en pratique, car la durée d'une variable avec une portée
de bloc est temporaire par défaut.
Machine Translated by Google

230 Heure 14

Le spécificateur statique
Le spécificateur statique , d'autre part, peut être appliqué à des variables avec une portée de
bloc ou une portée de programme. Lorsqu'une variable dans une fonction est déclarée avec le
spécificateur statique , la variable a une durée permanente. En d'autres termes, la mémoire
allouée à la variable n'est pas détruite lorsque l'on sort de la portée de la variable, la valeur de la
variable est maintenue hors de la portée. Si l'exécution revient à la portée de la variable, la
dernière valeur stockée dans la variable est toujours là.

Par exemple, dans la portion de code suivante :


int main() {

int je ; /* portée du bloc et durée temporaire */ static int j; /* portée du


bloc et durée permanente */
.
.
renvoie 0 ;
}

la variable entière i a une durée temporaire (auto) par défaut. Mais l'autre variable entière, j, a
une durée permanente en raison du spécificateur de classe de stockage static.

Le programme du Listing 14.3 montre l'effet du spécificateur statique sur les variables.

TAPER LISTE 14.3 Utilisation du spécificateur statique

1 : /* 14L03.c : Utilisation du spécificateur statique */ 2 :


#include <stdio.h> 3 : /* la fonction add_two */ 4 : int
add_two(int x, int y) 5 : { 6 :

compteur int statique = 1 ;

printf("Ceci est l'appel de fonction de %d,\n", compteur++); retour (x + y);

7:8:
9 : 10 : } 11 : /* la fonction principale
*/ 12 : main() 13 : { 14 : 15 : 16 : 17 :
18 : 19 : 20 : }
int je, j ;

for (i=0, j=5 ; i<5 ; i++, j­­)


printf("l'addition de %d et %d est %d.\n\n", i, j, add_two(i,
j ));
renvoie 0 ;
Machine Translated by Google

Présentation de l'étendue et des classes de stockage 231

La sortie suivante s'affiche à l'écran après l'exécution de l'exécutable (14L03.exe) :


C'est l'appel de fonction de 1, l'addition
SORTIR de 0 et 5 donne 5.

C'est l'appel de fonction de 2, l'addition


de 1 et 4 donne 5.

C'est l'appel de fonction de 3, l'addition


de 2 et 3 donne 5.

C'est l'appel de fonction de 4, l'addition


de 3 et 2 donne 5.

C'est l'appel de fonction de 5, l'addition


de 4 et 1 donne 5.

UNE ANALYSE Le but du programme du Listing 14.3 est d'appeler une fonction pour additionner deux
entiers, puis d'afficher le résultat renvoyé par la fonction à l'écran. La fonction est appelée
plusieurs fois. Un compteur est défini pour garder une trace du nombre de fois que la fonction a été
appelée.

Cette fonction, appelée add_two(), est déclarée aux lignes 4–10. Il y a deux arguments int , x et y,
qui sont passés à la fonction, et l'addition des deux arguments est retournée à la ligne 9. Notez qu'il y
a une variable entière, counter, qui est déclarée avec le spécificateur statique à la ligne 6 Les valeurs
stockées par compteur sont conservées car la durée de la variable est permanente. En d'autres
termes, bien que la portée du compteur soit dans le bloc de la fonction add_two() , l'emplacement
mémoire du compteur et la valeur enregistrée dans l'emplacement ne sont pas modifiés après l' appel
de la fonction add_two() et le contrôle d'exécution est renvoyé à la fonction principale() . Notez que
l'initialisation du compteur à 1 n'a lieu que la première fois que add_two() est appelée ; après cela, il
conserve sa valeur précédente chaque fois que la fonction est appelée.

Par conséquent, la variable compteur est utilisée comme compteur pour suivre le nombre d'appels
reçus par la fonction add_two() . En fait, la fonction printf() de la ligne 8 imprime la valeur enregistrée
par la variable compteur chaque fois que la fonction add_two() est appelée. De plus, le compteur est
incrémenté de un à chaque fois que la fonction printf() est exécutée.

La boucle for , déclarée aux lignes 16 à 18 dans la fonction main() , appelle cinq fois la fonction
add_two() . Les valeurs des deux variables entières, i et j, sont transmises à la fonction add_two()
où elles sont ajoutées. Ensuite, la valeur de retour de la fonction add_two() est affichée à l'écran
par l' appel printf() aux lignes 17 et 18.
14
À partir de la sortie, vous pouvez voir que la valeur enregistrée par counter est en effet incrémentée
de un à chaque fois que la fonction add_two() est appelée, et est conservée après la sortie de la
fonction car la variable entière counter est déclarée avec static. Vous pouvez voir que le compteur
n'est initialisé qu'une seule fois à 1, lorsque la fonction add_two() est appelée pour la première fois.
Machine Translated by Google

232 Heure 14

Portée du fichier et hiérarchie des portées


Dans la première partie de cette heure, j'ai mentionné trois des quatre types de portées : portée de bloc, portée
de fonction et portée de programme. Il est temps maintenant d'introduire la quatrième portée ­ le fichier
portée.

En C, une variable globale déclarée avec le spécificateur statique est dite avoir une portée de fichier. Une
variable avec une portée de fichier est visible depuis son point de déclaration jusqu'à la fin du fichier. Ici, le
fichier fait référence au fichier programme qui contient le code source. La plupart des grands programmes sont
constitués de plusieurs fichiers de programme.

La partie suivante du code source montre des variables avec une portée de fichier :

int x = 0 ; /* portée du programme */ static int y = 0; /*


portée du fichier */ static float zfichier
= 0.0;*//*int
portée
main()
du{

int je ; /* bloquer la portée */


.
.
.
renvoie 0 ;
}

Ici, la variable int y et la variable flottante z ont toutes deux une portée de fichier.

La figure 14.1 montre la hiérarchie des quatre portées. Comme vous pouvez le voir, une variable avec une portée
de bloc est la plus limitée et n'est pas visible en dehors du bloc dans lequel la variable est déclarée. D'autre part,
une variable avec une portée de programme est visible dans tous les fichiers, fonctions et autres blocs qui
composent le programme.

FIGURE 14.1 Portée du programme

La hiérarchie des
quatre portées. Portée du fichier

Portée de la fonction

Bloc
Portée
Machine Translated by Google

Présentation de l'étendue et des classes de stockage 233

Le Prescripteur de registre
Le mot registre est emprunté à la terminologie du matériel informatique. Chaque ordinateur possède un certain
nombre de registres pour stocker des données et effectuer des calculs arithmétiques ou logiques.
Étant donné que les registres sont situés dans la puce CPU (unité centrale de traitement), il est beaucoup
plus rapide d'accéder à un registre qu'à un emplacement mémoire situé à l'extérieur de la puce.
Par conséquent, stocker des variables dans des registres peut aider à accélérer votre programme.

Le langage C vous fournit le spécificateur de registre . Vous pouvez appliquer ce spécificateur aux variables
lorsque vous pensez qu'il est nécessaire de placer les variables dans les registres de l'ordinateur.

Cependant, le spécificateur de registre ne donne qu'une suggestion au compilateur. En d'autres termes, une
variable spécifiée par le mot­clé register n'est pas garantie d'être stockée dans un registre.
Le compilateur peut ignorer la suggestion s'il n'y a pas de registre disponible ou si d'autres restrictions s'appliquent.

Il est illégal de prendre l'adresse d'une variable déclarée avec le spécificateur de registre car la variable est
destinée à être stockée dans un registre et non en mémoire. Un registre CPU n'a pas d'adresse mémoire à laquelle
vous pouvez accéder.

Dans la partie de code suivante, la variable entière i est déclarée avec le spécificateur de registre :

int main() {

/* portée de bloc avec le spécificateur de registre */


register int i;
. . .
for (i=0; i<MAX_NUM; i++){ /*
quelques instructions */
}
. . .
renvoie 0 ;
}

La déclaration de i suggère que le compilateur stocke la variable dans un registre. Étant donné que i est utilisé de
manière intensive dans la boucle for , le stockage de i dans un registre peut augmenter la vitesse du code présenté
ici.

Le Prescripteur externe
Comme introduit dans la section intitulée "Portée du programme", plus tôt dans cette heure, une variable avec la
portée du programme est visible dans tous les fichiers source qui composent un programme exécutable. Une 14
variable avec une portée de programme est également appelée variable globale.

Voici une question : Comment une variable globale déclarée dans le fichier A peut­elle être vue dans le
fichier B ? En d'autres termes, comment le compilateur sait­il que la variable utilisée dans le fichier B est en fait
la même variable déclarée dans le fichier A ?
Machine Translated by Google

234 Heure 14

La solution est d'utiliser le spécificateur extern fourni par le langage C pour faire allusion à une
variable globale définie ailleurs. Dans ce cas, vous déclarez une variable globale dans le fichier A,
puis déclarez à nouveau la variable en utilisant le spécificateur extern dans le fichier B. Ce n'est pas une
déclaration séparée, mais spécifie la déclaration d'origine dans le fichier A.

Par exemple, supposons que vous ayez deux variables int globales, y et z, qui sont définies dans un
fichier, puis, dans un autre fichier, vous pourriez avoir les déclarations suivantes :

int x = 0 ; /* une variable globale */ /*


externe int y ; une allusion à une variable globale y */
int main() {

entier externe z ; /* une allusion à une variable globale z */ int i;


/* une variable locale */
.
.
.
renvoie 0 ;
}

Comme vous pouvez le voir, il y a deux variables entières, y et z, qui sont déclarées avec le
spécificateur extern , respectivement à l'extérieur et à l'intérieur de la fonction main() . Lorsque le
compilateur voit les deux déclarations, il sait que les déclarations sont en fait des allusions aux variables
globales y et z qui sont définies ailleurs.

Pour rendre votre programme portable sur différentes plates­formes informatiques, vous
pouvez appliquer les règles suivantes dans votre programme lorsque vous déclarez ou faites
allusion à des variables globales : • Vous pouvez ignorer le spécificateur extern, mais inclure un

initialiseur, lorsque vous déclarez une variable globale.

• Vous devez utiliser le spécificateur extern (sans initialiseur) lorsque vous faites allusion à
une variable globale définie ailleurs.

Les modificateurs de classe de stockage


Outre les quatre spécificateurs de classe de stockage présentés dans les sections précédentes, C vous
fournit également deux modificateurs de classe de stockage (ou qualificatifs, comme on les appelle
parfois) que vous pouvez utiliser pour indiquer au compilateur C comment accéder aux variables.

Le modificateur const
Si vous déclarez une variable avec le modificateur const , le contenu de la variable ne peut pas être
modifié après son initialisation.
Machine Translated by Google

Présentation de l'étendue et des classes de stockage 235

Par exemple, l'expression suivante indique au compilateur que circle_ratio est une variable dont la
valeur ne doit pas être modifiée :

const double circle_ratio = 3,141593 ;

De même, la valeur du tableau de caractères str déclaré dans l'instruction suivante ne peut pas non
plus être modifiée :

const char str[] = "Une constante de chaîne" ;

Par conséquent, il est illégal de faire quelque chose comme ceci :

chaîne[0] = 'a' ; /* Ce n'est pas autorisé ici. */

De plus, vous pouvez déclarer une variable de pointeur avec le modificateur const afin qu'un objet
pointé par le pointeur ne puisse pas être modifié. Par exemple, considérez la déclaration de pointeur
suivante avec le modificateur const :

char const *ptr_str = "Une constante de chaîne" ;

Après l'initialisation, vous ne pouvez pas modifier le contenu de la chaîne pointée par le pointeur ptr_str.
Par exemple, l'instruction suivante n'est pas autorisée :

*ptr_str = 'a' ; /* Ce n'est pas autorisé ici. */

Cependant, le pointeur ptr_str lui­même peut se voir attribuer une adresse différente d'une chaîne
déclarée avec char const.

Le modificateur volatil
Parfois, vous souhaitez déclarer une variable dont la valeur peut être modifiée sans aucune
instruction d'affectation explicite dans votre programme. Cela est particulièrement vrai lorsque vous
traitez directement avec du matériel. Par exemple, vous pouvez déclarer une variable globale qui
contient des caractères entrés par l'utilisateur. L'adresse de la variable est transmise à un registre de
périphérique qui accepte les caractères du clavier. Cependant, lorsque le compilateur C optimise
automatiquement votre programme, il a l'intention de ne pas mettre à jour la valeur détenue par la
variable à moins que la variable ne se trouve du côté gauche d'un opérateur d'affectation (=). En
d'autres termes, la valeur de la variable n'est probablement pas modifiée même si l'utilisateur tape
des caractères à partir du clavier.

Pour demander au compilateur de désactiver certaines optimisations sur une variable, vous pouvez
déclarer la variable avec le spécificateur volatile . Par exemple, dans la portion de code suivante,
une variable, keyboard_ch, déclarée avec le spécificateur volatil , indique au compilateur de ne pas 14
optimiser les expressions de la variable car la valeur enregistrée par la variable peut être modifiée
sans l'exécution d'une instruction d'affectation explicite. :

annuler read_keyboard() {
Machine Translated by Google

236 Heure 14

caractère volatile keyboard_ch ; /* une variable volatile */


.
.
.
}

Résumé
Dans cette leçon, vous avez appris les concepts importants suivants sur les portées et les classes de
stockage en C :

• Une variable déclarée dans un bloc a une portée de bloc. Une telle variable est aussi appelée
variable locale et n'est visible que dans le bloc.

• Une étiquette goto a une portée de fonction, ce qui signifie qu'elle est visible à travers tout le bloc de la
fonction dans laquelle l'étiquette est placée. Il n'y a pas deux étiquettes goto qui partagent le même
nom dans un bloc fonction.

• Une variable déclarée avec le spécificateur statique en dehors d'une fonction a une portée de fichier,
ce qui signifie qu'elle est visible dans tout le fichier source dans lequel la variable est déclarée.

• Une variable déclarée en dehors d'une fonction est dite avoir une portée programme. Une telle variable
est également appelée variable globale. Une variable globale est visible dans tous les fichiers source
qui composent un programme exécutable. • Une variable avec une portée de bloc a la visibilité la plus

limitée. D'autre part, une variable avec une portée de programme est la plus visible et peut être vue à
travers tous les fichiers, fonctions et autres blocs qui composent le programme. • La classe de stockage
d'une variable fait référence à la combinaison de ses régions spatiales et temporelles (c'est­à­dire, sa

portée et sa durée.) • Par défaut, une variable avec une portée de bloc a une durée automatique et son
stockage en mémoire

l'âge est temporaire.

• Une variable déclarée avec le spécificateur statique a un stockage permanent en mémoire, même après
que la fonction dans laquelle la variable est déclarée a été appelée et que la fonction

la portée est sortie.

• Une variable déclarée avec le spécificateur de registre peut être stockée dans un registre pour
accélérer les performances d'un programme ; cependant, le compilateur peut ignorer le spécificateur
s'il n'y a pas de registre disponible ou si d'autres restrictions s'appliquent.

• Vous pouvez également faire allusion à une variable globale définie ailleurs en utilisant le
spécificateur extern du fichier source actuel.
Machine Translated by Google

Présentation de l'étendue et des classes de stockage 237

• Pour vous assurer que la valeur enregistrée par une variable ne peut pas être modifiée, vous pouvez déclarer
variable avec le modificateur const .

• Si vous voulez faire savoir au compilateur que la valeur d'une variable peut être modifiée sans instruction
d'affectation explicite, déclarez la variable avec le modificateur volatile afin que le compilateur désactive
les optimisations sur les expressions impliquant la variable.

Dans la prochaine leçon, vous découvrirez les déclarations de fonctions et les prototypes en C.

Questions et réponses

Q Une variable globale peut­elle être masquée par une variable locale avec une portée de bloc ?

R Oui. Si une variable locale partage le même nom avec une variable globale, la variable globale
La variable locale peut être masquée par la variable locale pour la portée du bloc dans lequel la variable
locale est définie avec la portée du bloc. Cependant, à l'extérieur du bloc, la variable locale n'est pas visible,
mais la variable globale redevient visible.

Q Pourquoi avez­vous besoin du spécificateur statique ?

A Dans de nombreux cas, la valeur d'une variable est nécessaire, même si la portée du bloc, dans lequel la
variable est déclarée, est sortie. Par défaut, une variable avec une portée de bloc a un stockage en
mémoire temporaire, c'est­à­dire que la durée de vie de la variable commence lorsque le bloc est exécuté
et que la variable est déclarée, et se termine lorsque l'exécution de ce bloc est terminée. Par conséquent,
pour déclarer une variable à durée permanente, vous devez utiliser le spécificateur statique pour indiquer au
compilateur que l'emplacement mémoire de la variable et la valeur stockée dans l'emplacement mémoire
doivent être conservés après l'exécution du bloc.

Q L'utilisation du spécificateur de registre garantit­elle l'amélioration des performances d'un


programme?

R Pas vraiment. Déclarer une variable avec le spécificateur de registre ne fait que suggérer au compilateur
que la variable doit être stockée dans un registre. Mais il n'y a aucune garantie que la variable sera
stockée dans un registre. Le compilateur peut ignorer la demande en fonction de la disponibilité des
registres ou d'autres restrictions.

Q Lorsque vous déclarez une variable avec le spécificateur extern , définissez­vous la vari
pouvoir ou faire allusion à une variable globale ailleurs ?

A Lorsqu'une variable est déclarée avec le spécificateur extern , le compilateur considère


déclaration de la variable comme une allusion plutôt qu'une définition. Le compilateur va donc chercher
14
ailleurs pour trouver une variable globale à laquelle la variable avec extern fait allusion.
Machine Translated by Google

238 Heure 14

Atelier
Pour aider à consolider votre compréhension de cette leçon, nous vous encourageons à répondre aux
questions du quiz et à terminer les exercices fournis dans l'atelier avant de passer à la leçon suivante. Les
réponses et les conseils aux questions et exercices sont donnés dans l'annexe B, « Réponses aux questions
et exercices du quiz ».

Questionnaire

1. Étant donné la portion de code suivante, quelles variables sont des variables globales et lesquelles
celles­ci sont des variables locales avec une portée
de bloc ? int x = 0 ; flottant y = 0,0 ; int maFonction()
{

int je, j ;
flotter y ;
. . .
{
int x, y ;
. . .
}
. . .
}

2. Lorsque deux variables portant le même nom sont définies, comment le compilateur sait­il laquelle
utiliser ?

3. Identifiez la classe de stockage de chaque déclaration dans la portion de code suivante :


int je = 0 ;
entier statique
x ; flotteur externe
y ; int maFonction()
{
int je, j ;
flotteur externe z ;
enregistrer un s
long ; index int
statique ; const char str[] = "Message d'avertissement." ;
. . .
}

4. Compte tenu de la déclaration suivante :

const char ch_str[] = "Le spécificateur const" ;


est le ch_str[9] = '­' ; déclaration légale?
Machine Translated by Google

Présentation de l'étendue et des classes de stockage 239

Des exercices
1. Compte tenu de ce qui suit :

• Une variable int avec une portée de bloc et un stockage temporaire • Une

variable de caractère constant avec une portée de bloc • Une variable

locale flottante avec un stockage permanent • Une variable de registre int •

Un pointeur char initialisé avec un caractère nul

écrire des déclarations pour chacun d'eux.

2. Réécrivez le programme du Listing 14.2. Cette fois, passez la variable int x et la


variable flottante y comme arguments de la fonction function_1() . Qu'est­ce que vous obtenez sur votre
écran après avoir exécuté le programme ?

3. Compilez et exécutez le programme suivant. Qu'est­ce que vous obtenez à l'écran et pourquoi ?
#include <stdio.h> int
main() {

int je ;

pour (i=0 ; i<5 ; i++){ int x


= 0 ; statique int y =
0 ; printf("x=%d,
y=%d\n", x++, y++);

} renvoie 0 ;
}

4. Réécrivez la fonction add_two() du Listing 14.3 pour imprimer le résultat précédent de


l'addition, ainsi que la contre­valeur.

14
Machine Translated by Google
Machine Translated by Google

PARTIE IV

Fonctions et Dynamique
Allocation de mémoire
Heure
15 Utilisation des fonctions

16 Application de pointeurs

17 Allocation de mémoire

18 Utilisation de types de données et de fonctions spéciales


Machine Translated by Google
Machine Translated by Google

HEURE 15

Travailler avec des fonctions


La forme suit la fonction.

—LH Sullivan

Dans l'heure 14, « Comprendre la portée et les classes de stockage », vous avez peut­
être remarqué qu'une définition de fonction est toujours donnée en premier, avant que la
fonction ne soit appelée à partir d'une fonction main() . En fait, vous pouvez placer une
définition de fonction n'importe où, tant que vous placez la déclaration de fonction avant le
premier endroit où la fonction est appelée. Vous découvrirez de nombreuses fonctionnalités
des fonctions dans les rubriques suivantes abordées dans cette leçon :

• Déclarations de fonction

• Prototypage
• Valeurs renvoyées par les fonctions

• Arguments aux fonctions •

Programmation structurée

De plus, plusieurs fonctions et macros de la bibliothèque C, telles que


time(), localtime(), asctime(), va_start(), va_arg() et va_end() sont
introduites dans cette heure.
Machine Translated by Google

244 Heure 15

Déclarer des fonctions


Comme vous le savez, vous devez déclarer ou définir une variable avant de pouvoir l'utiliser. Ceci est également
vrai pour les fonctions. En C, vous devez déclarer ou définir une fonction avant de pouvoir l'appeler.

Déclaration versus définition


Selon la norme ANSI, la déclaration d'une variable ou d'une fonction précise l'interprétation et les attributs
d'un ensemble d'identificateurs. La définition, d'autre part, exige que le compilateur C réserve le stockage
pour une variable ou une fonction nommée par un identifiant.

Une déclaration de variable est une définition, mais une déclaration de fonction ne l'est pas. Une déclaration de
fonction fait allusion à une fonction définie ailleurs et spécifie le type de valeur renvoyée par la fonction. Une
définition de fonction définit ce que fait la fonction, ainsi que le nombre et le type d'arguments passés à la fonction.

Une déclaration de fonction n'est pas une définition de fonction. Si une définition de fonction est placée dans
votre fichier source avant que la fonction ne soit appelée pour la première fois, vous n'avez pas besoin de faire
la déclaration de fonction. Sinon, la déclaration d'une fonction doit être faite avant l'invocation de la fonction.

Par exemple, j'ai utilisé la fonction printf() dans presque tous les exemples de programme de ce livre. À
chaque fois, j'ai dû inclure un fichier d'en­tête, stdio.h, car le fichier d'en­tête contient la déclaration de printf(), qui
indique au compilateur le type de retour et le type de prototype de la fonction. La définition de la fonction printf()
est placée ailleurs.
En C, la définition de cette fonction est enregistrée dans un fichier de bibliothèque qui est invoqué pendant
les états de liaison.

Spécification des types de retour


Une fonction peut être déclarée pour renvoyer n'importe quel type de données, à l'exception d'un tableau
ou d'une fonction. L' instruction return utilisée dans une définition de fonction renvoie une seule valeur dont le
type doit correspondre à celui déclaré dans la déclaration de fonction.

Par défaut, le type de retour d'une fonction est int, si aucun type de données explicite n'est spécifié pour la fonction.
Un spécificateur de type de données est placé avant le nom d'une fonction comme ceci :

data_type_specifier function_name();

Ici data_type_specifier spécifie le type de données que la fonction doit renvoyer. nom_fonction est le nom
de la fonction qui doit suivre les règles de nommage des identificateurs en C.

En fait, ce formulaire de déclaration représente le formulaire de déclaration de fonction traditionnel avant la


création de la norme ANSI. Après la configuration de la norme ANSI, le type de prototype de fonction est ajouté
à la déclaration de fonction.
Machine Translated by Google

Travailler avec des fonctions 245

Utilisation de prototypes Avant la

création de la norme ANSI, une déclaration de fonction incluait uniquement le type de retour de la fonction. 15
Avec la norme ANSI, le nombre et les types d'arguments passés à une fonction peuvent être ajoutés dans la
déclaration de la fonction. Le nombre et les types d'un argument sont appelés le prototype de la fonction.

La forme générale d'une déclaration de fonction, y compris son prototype, est la suivante :

data_type_specifier function_name(
data_type_specifier argument_name1,
data_type_specifier argument_name2,
data_type_specifier argument_name3,
.
.
.
data_type_specifier argument_nameN,

Le but de l'utilisation d'un prototype de fonction est d'aider le compilateur à vérifier si les types de données des
arguments passés à une fonction correspondent à ce que la fonction attend. Le compilateur émet un message
d'erreur si les types de données ne correspondent pas.

Bien que les noms d'arguments, tels que nom_argument1, nom_argument2, etc., soient facultatifs, il est
recommandé de les inclure afin que le compilateur puisse identifier toute incompatibilité de noms d'arguments.

Faire des appels de fonction


Comme le montre la figure 15.1, lorsqu'un appel de fonction est effectué, l'exécution du programme saute à la
fonction et termine la tâche affectée à la fonction. Ensuite, l'exécution du programme reprend après le retour
de la fonction appelée.

Un appel de fonction est une expression qui peut être utilisée comme une seule instruction ou dans d'autres
déclarations.

Le Listing 15.1 donne un exemple de déclaration et de définition de fonctions, ainsi que d'appels de fonction.

TAPER
LISTE 15.1 Appeler des fonctions après qu'elles aient été déclarées et définies

1 : /* 15L01.c : effectuer des appels de fonction */


2 : #include <stdio.h> 3 : 4 : int function_1(int x, int
y) ; 5 : fonction double_2(double x, double y) 6 : {

7: printf("Dans function_2.\n");

continue
Machine Translated by Google

246 Heure 15

LISTE 15.1 suite


retour (x ­ y);
8:
9:}
10 : 11 :
main() 12 :
{ 13 : 14 :entier x1 = 80 ;
15 : 16 : 17 : y1 = 10 ;
entier
18 : 19 : 20 :
double x2 = 100,123456 ;
21 : 22 : double y2 = 10,123456 ;
23 : } 24 : /*
définitionprintf("Passez
de la fonction_1 %d et %d.\n", x1, y1);
la printf("function_1 renvoie %d.\n", function_1(x1, y1)); printf("Passez la
fonction_1()fonction_2 %f et %f.\n", x2, y2); printf("function_2 renvoie %f.\n",
*/ 25 : int function_2(x2, y2)); renvoie 0 ;
fonction_1(int
x, int y) 26 :
{ 27 : 28 : 29 : }

printf("Dans function_1.\n"); retour (x +


y);

FIGURE 15.1

L'exécution du Début

programme saute à une


fonction invoquée lorsqu'un
appel de fonction est effectué.
Une fonction
Appel

prog
Flux
d'ex
du Une fonction
Exécution

Une fonction
Revenir

Finir
Machine Translated by Google

Travailler avec des fonctions 247

La sortie suivante s'affiche après la création et l'exécution de l'exécutable (15L01.exe) du


programme du Listing 15.1 :
15
Passez la fonction_1 80 et 10.
SORTIR Dans function_1.
function_1 renvoie 90.
Passez la fonction_2 100.123456. et 10.123456.
Dans function_2.
function_2 renvoie 90,000000.

Le but du programme du Listing 15.1 est de vous montrer comment déclarer et définir des
UNE ANALYSE
fonctions. L'instruction de la ligne 4 est une déclaration de fonction avec un type prototype.
La déclaration fait allusion à la fonction_1 définie plus loin dans le Listing 15.1. Le type de retour de
function_1 est int, et le prototype de la fonction inclut deux variables int , appelées x et y.

Aux lignes 5 à 9, la deuxième fonction, function_2, est définie avant d'être appelée. Comme vous
pouvez le voir, le type de retour de function_2 est double et deux variables doubles sont passées à la
fonction. Notez que les noms des deux variables sont également x et y. Ne vous inquiétez pas car
function_1 et function_2 partagent les mêmes noms d'arguments. Il n'y a pas de conflit car ces
arguments se trouvent dans des blocs fonctionnels différents et les arguments des fonctions ont une
portée de bloc.

Ensuite, dans la fonction main() définie aux lignes 11 à 23, deux variables int , x1 et y1, et deux
variables doubles , x2 et y2, sont déclarées et initialisées aux lignes 13 à 16, respectivement.
L'instruction de la ligne 18 affiche les valeurs de x1 et y1 transmises à la fonction function_1. La ligne
19 appelle la fonction_1 et affiche la valeur renvoyée par la fonction_1.

De même, les lignes 20 et 21 impriment les valeurs de x2 et y2 transmises à function_2,


ainsi que la valeur renvoyée par function_2 après l'appel et l'exécution de la fonction.

Les lignes 25 à 29 contiennent la définition de la fonction function_1, en précisant que la fonction


peut effectuer une addition de deux variables entières (voir ligne 28) et afficher la chaîne de Within
function_1. à la ligne 27.

Fonctions de prototypage
Dans les sous­sections suivantes, vous allez étudier trois cas concernant les arguments passés
aux fonctions. Le premier cas est que les fonctions ne prennent aucun argument ; la seconde est
que les fonctions prennent un nombre fixe d'arguments ; le troisième cas est que les fonctions
prennent un nombre variable d'arguments.
Machine Translated by Google

248 Heure 15

Fonctions sans arguments


Le premier cas est une fonction qui ne prend aucun argument. Par exemple, la fonction getchar() de la
bibliothèque C n'a pas besoin d'arguments. Il peut être utilisé dans un programme comme celui­ci :
entier
c ; c = getchar();

Comme vous pouvez le voir, la deuxième instruction est laissée vide entre les parenthèses (( et ))
lorsque la fonction est appelée.

En C, la déclaration de la fonction getchar() peut ressembler à ceci :

int getchar(vide);

Notez que le mot clé void est utilisé dans la déclaration pour indiquer au compilateur qu'aucun argument
n'est requis par cette fonction. Le compilateur émettra un message d'erreur si un argument est passé à
getchar() plus tard dans un programme lorsque cette fonction est appelée.

Par conséquent, pour une fonction sans argument, le type de données void est utilisé comme prototype dans
la déclaration de la fonction.

Le programme du Listing 5.2 montre un autre exemple d'utilisation de void dans les déclarations
de fonction.

TAPER
LISTE 15.2 Utilisation de void dans les déclarations de fonction

1 : /* 15L02.c : Fonctions sans arguments */ 2 : #include <stdio.h>


3 : #include <time.h>

4:
5 : annuler GetDateTime(annuler) ;
6 : 7 : principal() 8 : { 9 : 10 : 11 : 12 : 13 : }

printf("Avant que la fonction GetDateTime() ne soit appelée.\n"); GetDateHeure();


printf("Après l'appel de la fonction GetDateTime().\n"); renvoie 0 ;

14 : /* Définition de GetDateTime() */ 15 : void


GetDateTime(void) 16 : { 17 : 18 : 19 : 20 : 21 :
22 : 23 : }
time_t maintenant ;

printf("Dans GetDateTime().\n"); c'est l'heure);


printf("La date et l'heure actuelles sont : %s\n",
asctime(localtime(&now)));
Machine Translated by Google

Travailler avec des fonctions 249

J'obtiens la sortie suivante après avoir exécuté le fichier exécutable, 15L02.exe, du programme du
Listing 15.2 :
15
Avant l'appel de la fonction GetDateTime().
SORTIR Dans GetDateTime().
La date et l'heure actuelles sont : Sam Apr 05 11:50:10 1997

Après l'appel de la fonction GetDateTime().

Le but du programme du Listing 15.2 est de vous montrer comment déclarer et appeler une
UNE ANALYSE
fonction sans passer d'arguments. Le programme imprime la date et l'heure actuelles sur
votre ordinateur en appelant la fonction GetDateTime(), déclarée à la ligne 5. Comme aucun argument
ne doit être passé à la fonction, le type de données void est utilisé comme prototype dans la déclaration
de GetDateTime ().

De plus, un autre mot­clé void est utilisé devant le nom de la fonction GetDateTime() pour indiquer
que cette fonction renvoie une valeur non plus (voir ligne 5.)

Les instructions des lignes 9 et 11 impriment des messages avant et après l' appel de la
fonction GetDateTime() depuis la fonction main() .

A la ligne 10, la fonction est appelée par l'instruction GetDateTime();. Notez qu'aucun argument ne
doit être passé à cette fonction car le prototype de la fonction est vide.

La définition de GetDateTime() est aux lignes 15–23 ; il obtient l'heure calendaire et la convertit en
une chaîne de caractères en appelant plusieurs fonctions de la bibliothèque C : time(), local time() et
asctime(). Ensuite, la chaîne de caractères contenant la date et l'heure courantes est imprimée à l'écran
par la fonction printf() avec le spécificateur de format %s. Comme vous pouvez le voir, la sortie sur mon
écran montre qu'au moment où le fichier exécutable 15L02.exe est en cours d'exécution, la date et
l'heure sont

sam. 05 avril 11:50:10 1997

time(), localtime() et asctime() sont des fonctions de date et d'heure fournies par le langage C.
Ces fonctions sont décrites dans la sous­section suivante. Vous remarquerez peut­être que le
fichier d'en­tête time.h est inclus au début du programme dans le Listing 15.2 avant que ces
fonctions temporelles puissent être utilisées.

Utilisation de time(), localtime() et asctime()


Il existe un groupe de fonctions C appelées fonctions de date et d'heure. Les déclarations de toutes les
fonctions de date et d'heure sont incluses dans le fichier d'en­tête time.h. Ces fonctions peuvent donner
trois types de date et d'heure :

• Heure calendaire

• Heure locale

• Le temps de l'heure d'été


Machine Translated by Google

250 Heure 15

Ici , l'heure calendaire donne la date et l'heure actuelles basées sur le calendrier grégorien.
L'heure locale représente l'heure du calendrier dans un fuseau horaire spécifique. L'heure d'été est
l'heure locale selon la règle de l'heure d'été.

Dans cette section, trois fonctions de date et d'heure — time(), localtime() et asctime() — sont
brièvement présentées.

La fonction time() renvoie l'heure du calendrier.

La syntaxe de la fonction time() est


#include <time.h>
,SYNTAXE
time_t time(time_t *timer);

Ici, time_t est le type arithmétique utilisé pour représenter le temps. timer est une variable de
pointeur pointant vers une mémoire de stockage pouvant contenir l'heure calendaire renvoyée par
cette fonction. La fonction time() renvoie ­1 si l'heure du calendrier n'est pas disponible sur
, l'ordinateur.

La fonction localtime() renvoie l'heure locale convertie à partir de l'heure calendaire.

La syntaxe de la fonction localtime() est


#include <time.h>
,SYNTAXE struct tm *localtime(const time_t *timer);

Ici tm est une structure qui contient les composantes du temps calendaire. struct est le mot­clé
pour structure, qui est un autre type de données en C. (Le concept de structures est introduit dans
l'Heure 19, « Comprendre les structures ». ) fonction temps() .
,
Pour convertir la date et l'heure représentées par la structure tm, vous pouvez appeler la fonction
asctime() .

La syntaxe de la fonction asctime() est


SYNTAXE
#include <time.h>
char *asctime(const struct tm *timeptr);

Ici, timeptr est un pointeur faisant référence à la structure tm renvoyée par les fonctions de date
et d'heure comme localtime(). La fonction asctime() convertit la date et l'heure représentées par tm
, en une chaîne de caractères.

Comme le montre le Listing 15.2, l'instruction de la ligne 17 déclare une variable time_t appelée now.
La ligne 20 stocke l'heure du calendrier dans l'emplacement mémoire référencé par la variable now .
Notez que l'argument passé à la fonction time() doit être la valeur de gauche d'une variable ; par
conséquent, l'opérateur d'adresse (&) est utilisé jusqu'à présent. Ensuite, l'expression dans
Machine Translated by Google

Travailler avec des fonctions 251

ligne 22, asctime(localtime(&now)), obtient l'expression de l'heure locale de l'heure calendaire en appelant
localtime(), et convertit l'heure locale en une chaîne de caractères à l'aide de asctime(). La chaîne de caractères
15
représentant la date et l'heure est ensuite imprimée par l' appel printf() aux lignes 21 et 22, qui a le format
suivant :

Sam 05 avril 11:50:10 1997\n\0

Notez qu'il y a un caractère de saut de ligne ajouté juste avant le caractère nul dans la chaîne de
caractères qui est convertie et renvoyée par la fonction asctime() .

Fonctions avec un nombre fixe d'arguments


Vous avez en fait vu plusieurs exemples qui déclarent et appellent des fonctions avec un nombre fixe
d'arguments. Par exemple, dans le Listing 15.1, la déclaration de la fonction function_1() à la ligne 4

int fonction_1(int x, int y);

contient le prototype de deux arguments, x et y.

Pour déclarer une fonction avec un nombre fixe d'arguments, vous devez spécifier le type de données de
chaque argument. De plus, il est recommandé d'indiquer les noms d'arguments afin que le compilateur
puisse vérifier que les types et noms d'arguments déclarés dans une déclaration de fonction correspondent
à l'implémentation dans la définition de fonction.

Prototypage d'un nombre variable d'arguments


Comme vous vous en souvenez peut­être, la syntaxe de la fonction printf() est

int printf(const char *format[, argument, ...]);

Ici, le jeton de points de suspension ... (c'est­à­dire trois points) représente un nombre variable
d'arguments. Autrement dit, outre le premier argument qui est une chaîne de caractères, la fonction printf()
peut prendre un nombre indéterminé d'arguments supplémentaires, autant que le compilateur le permet. Les
crochets ([ et ]) indiquent que les arguments non spécifiés sont facultatifs.

Voici une forme générale pour déclarer une fonction avec un nombre variable d'argu
commentaires :

data_type_specifier
function_name( data_type_specifier argument_name1, ...

Notez que le nom du premier argument est suivi des points de suspension (...) qui représentent le reste des
arguments non spécifiés.
Machine Translated by Google

252 Heure 15

Par exemple, la déclaration de la fonction printf() ressemblerait à ceci :


int printf(const char *format, ...);

Traitement des arguments variables


Il existe trois routines déclarées dans le fichier d'en­tête stdarg.h qui vous permettent d'écrire des
fonctions prenant un nombre variable d'arguments. Ce sont va_start(), va_arg() et va_end().

Un type de données, va_list, est également inclus dans stdarg.h , qui définit un type de tableau
approprié pour contenir les éléments de données nécessaires à va_start(), va_arg() et va_end().

Pour initialiser un tableau donné nécessaire à va_arg() et va_end(), vous devez utiliser la
routine de macro va_start() avant que les arguments ne soient traités.

La syntaxe de la macro va_start() est


#include <stdarg.h> void
,SYNTAXE
va_start(va_list ap, lastfix);

Ici ap est le nom du tableau qui est sur le point d'être initialisé par la macro­routine va_start() .
lastfix doit être l'argument avant les points de suspension (...) dans la déclaration de la fonction.
,
En utilisant la macro va_arg() , vous pouvez traiter une expression qui a le type et la valeur
de l'argument suivant. En d'autres termes, la macro va_arg() peut être utilisée pour obtenir le
prochain argument passé à la fonction.

La syntaxe de la macro va_arg() est


SYNTAXE #include <stdarg.h> type
va_arg(va_list ap, data_type);

Ici ap est le nom du tableau qui est initialisé par la macro­routine va_start() . data_type est
, le type de données de l'argument passé à la fonction.

Pour faciliter un retour normal de votre fonction, vous devez utiliser la fonction va_end() dans
votre programme après que tous les arguments ont été traités.

La syntaxe de la fonction va_end() est


SYNTAXE #include <stdarg.h> void
va_end(va_list ap);

Ici ap est le nom du tableau qui est initialisé par la macro­routine va_start() .
,
N'oubliez pas d'inclure le fichier d'en­tête stdarg.h dans votre programme avant d'appeler
va_start(), va_arg() ou va_end().
Machine Translated by Google

Travailler avec des fonctions 253

Le Listing 5.3 montre comment utiliser va_start(), va_arg() et va_end() dans une fonction
qui prend un nombre variable d'arguments. 15
TAPER
LISTE 15.3 Traitement des arguments variables
1 : /* 15L03.c : Traitement des arguments de variable */ 2 : #include
<stdio.h> 3 : #include <stdarg.h> 4 :

5 : double AddDouble(int x, ...); 6 : 7 : principal ()


8 : { 9 : 10 : 11 :

double d1 = 1,5 ; double


d2 = 2,5 ; double d3 =
3,5 ; double d4 = 4,5 ;
12 :
13:
14: printf("Étant donné un argument : %2.1f\n", d1); printf("Le
résultat renvoyé par AddDouble() est : %2.1f\n\n",
AddDouble(1, d1));
15 : 16 : 17 printf("Arguments
: donnés : %2.1f et %2.1f\n", d1, d2); printf("Le résultat renvoyé
par AddDouble() est : %2.1f\n\n", AddDouble(2, d1, d2));

printf("Arguments donnés : %2.1f, %2.1f et %2.1f\n", d1, d2, d3); printf("Le résultat renvoyé par
18h19h20h21h
AddDouble() est : %2.1f\n\n", AddDouble(3, d1, d2, d3)); printf("Arguments donnés : %2.1f, %2.1f,
22: %2.1f et %2.1f\n", d1, d2, d3, d4); printf("Le résultat renvoyé par AddDouble() est : %2.1f\n",
23:
24:

AddDouble(4, d1, d2, d3, d4)); renvoie 0 ;


25 : 26 : 27 :
28 : }
29 : /* définition de AddDouble() */ 30 : double
AddDouble(int x, ...) 31 : { 32 : 33 : 34 : 35 : 36 : 37 :
38 : 39 : 40 : 41 :
va_list arglist ; int je ;
double résultat = 0,0 ;

printf("Le nombre d'arguments est : %d\n", x); va_start (arglist, x);


pour (i=0; i<x; i++)

result += va_arg(arglist, double); va_end (arglist);


retourner le résultat ;

42 : }
Machine Translated by Google

254 Heure 15

La sortie suivante s'affiche à l'écran une fois le fichier exécutable, 15L03.exe ,


Cours:

Soit un argument : 1,5 Le


SORTIR nombre d'arguments est : 1 Le
résultat renvoyé par AddDouble() est : 1,5

Arguments donnés : 1,5 et 2,5 Le


nombre d'arguments est : 2 Le
résultat renvoyé par AddDouble() est : 4,0

Arguments donnés : 1,5, 2,5 et 3,5 Le


nombre d'arguments est : 3 Le résultat
renvoyé par AddDouble() est : 7,5

Arguments donnés : 1,5, 2,5, 3,5 et 4,5 Le nombre


d'arguments est : 4 Le résultat renvoyé par
AddDouble() est : 12,0

Le programme du Listing 15.3 contient une fonction qui peut prendre un nombre variable d'
UNE ANALYSE
arguments doubles , effectuer l'opération d'addition sur ces arguments, et
puis renvoyez le résultat à la fonction main() .

La déclaration à la ligne 5 indique au compilateur que la fonction AddDouble() prend un nombre


variable d'arguments. Le premier argument de AddDouble() est une variable entière qui contient le
nombre des autres arguments passés à la fonction chaque fois que AddDouble() est appelé. En
d'autres termes, le premier argument indique le nombre d'arguments restant à traiter.

La définition de AddDouble() est donnée aux lignes 29 à 41, dans lesquelles un tableau
va_list, arglist , est déclaré à la ligne 31. Comme mentionné, la macro va_start() doit être appelée
avant que les arguments ne soient traités. Ainsi, la ligne 36 invoque va_start() pour initialiser le
tableau arglist. La boucle for des lignes 37 et 38 récupère le double argument suivant enregistré
dans le tableau arglist en appelant va_arg(). Ensuite, chaque argument est ajouté dans une double
variable locale appelée résultat.

La fonction va_end() est appelée à la ligne 39 après que tous les arguments enregistrés dans
arglist ont été récupérés et traités. Ensuite, la valeur de result est renvoyée à l'appelant de la
fonction AddDouble() , qui est la fonction main() dans ce cas.

La fonction va_end() doit être appelée dans un programme C pour terminer le traitement des
arguments variables. Sinon, le comportement du programme est indéfini.

Comme vous pouvez le voir, dans la fonction main() , AddDouble() est appelée quatre fois, avec un
nombre différent d'arguments à chaque fois. Ces arguments passés à AddDouble() sont affichés par
les appels printf() aux lignes 14, 17, 20 et 23. De plus, les quatre résultats différents renvoyés par
AddDouble() sont affichés à l'écran.
Machine Translated by Google

Travailler avec des fonctions 255

Apprentissage de la programmation structurée


Vous avez maintenant appris les bases de la déclaration et de la définition des fonctions. Avant de passer à
15
l'heure suivante, parlons un peu de la programmation structurée dans la conception des programmes.

La programmation structurée est l'une des meilleures méthodologies de programmation. Fondamentalement, il


existe deux types de programmation structurée : la programmation descendante et la programmation ascendante.

Lorsque vous commencez à écrire un programme pour résoudre un problème, une façon de le faire est de travailler
sur les plus petits éléments du problème. Tout d'abord, vous définissez et écrivez des fonctions pour chaque
élément. Une fois chaque fonction écrite et testée, vous commencez à les assembler pour créer un programme
capable de résoudre le problème. Cette approche est normalement appelée programmation ascendante.

En revanche, pour résoudre un problème, vous pouvez d'abord élaborer un schéma et commencer votre
programmation à un niveau supérieur. Par exemple, vous pouvez travailler sur la fonction main() au début, puis
passer au niveau inférieur suivant jusqu'à ce que les fonctions de niveau le plus bas soient écrites dix. Ce type
d'approche est appelé programmation descendante.

Vous constaterez qu'il est utile de combiner ces deux types de programmation structurée et de les utiliser
alternativement afin de résoudre de vrais problèmes.

Résumé
Dans cette leçon, vous avez appris les concepts importants suivants sur les fonctions en C :

• Une déclaration de fonction fait allusion à une fonction qui est définie ailleurs et spécifie également le type
d'arguments et de valeurs qui sont passés à et renvoyés par la fonction.

• Une définition de fonction réserve l'espace mémoire et définit ce que fait la fonction, ainsi que le nombre
et le type d'arguments passés à la fonction. • Une fonction peut être déclarée pour renvoyer n'importe

quel type de données, à l'exception d'un tableau ou d'une fonction. • L' instruction return utilisée dans une

définition de fonction renvoie une seule valeur dont le type doit correspondre à celui déclaré dans la
déclaration de fonction. • Un appel de fonction est une expression qui peut être utilisée comme une seule

instruction ou dans
d'autres expressions ou déclarations.

• Le type de données void est nécessaire dans la déclaration d'une fonction qui ne prend aucun argument
ment.

• Pour déclarer une fonction qui prend un nombre variable d'arguments, vous devez spécifier au moins le
premier argument et utiliser les points de suspension (...) pour représenter le reste des arguments passés
à la fonction.
Machine Translated by Google

256 Heure 15

• va_start(), va_arg() et va_end(), tous inclus dans stdarg.h, sont nécessaires pour traiter un nombre variable
d'arguments passés à une fonction.

• time(), localtime() et asctime() sont trois fonctions temporelles fournies par C. Elles peuvent être utilisées ensemble
pour obtenir une chaîne de caractères contenant des informations sur la date et l'heure locales basées sur l'heure
calendaire.

Dans la leçon suivante, vous en apprendrez plus sur les pointeurs et leurs applications en C.

Questions et réponses

Q Quelle est la principale différence entre une déclaration de fonction et une fonction
définition?

A La principale différence entre une déclaration de fonction et une définition de fonction est que

le premier ne réserve aucun espace mémoire et ne spécifie pas non plus ce que fait une fonction. Une déclaration
de fonction fait uniquement allusion à une définition de fonction placée ailleurs. Il spécifie également quel type
d'arguments et de valeurs sont passés à et renvoyés par la fonction. Une définition de fonction, en revanche,
réserve l'espace mémoire et spécifie les tâches que la fonction peut accomplir.

Q Pourquoi avons­nous besoin de prototypes de fonction ?

A En déclarant une fonction avec des prototypes, vous spécifiez non seulement le type de données
retourné par la fonction, mais aussi les types et les noms des arguments passés à la fonction. A l'aide d'un
prototype de fonction, le compilateur peut vérifier automatiquement par type de formulaire la définition de la
fonction, ce qui vous fait gagner du temps lors du débogage du programme.

Q Une fonction peut­elle renvoyer un pointeur ?

R Oui. En fait, une fonction peut renvoyer une seule valeur qui peut être n'importe quel type de données à l'exception
d'un tableau ou d'une fonction. Une valeur de pointeur, c'est­à­dire l'adresse, renvoyée par une fonction peut faire
référence à un tableau de caractères ou à un emplacement mémoire qui stocke d'autres types de données.
Par exemple, la fonction asctime() de la bibliothèque C renvoie un pointeur de caractère qui pointe vers
une chaîne de caractères convertie à partir d'une structure date­heure.

Q Pouvez­vous utiliser la programmation descendante et la programmation ascendante ensemble pour résoudre un


problème ?

R Oui. En pratique, vous pouvez constater que c'est en fait une bonne idée de combiner le haut
approches de programmation descendante et ascendante pour résoudre des problèmes. L'utilisation des deux
types de programmation structurée peut rendre votre programme facile à écrire et à comprendre.
Machine Translated by Google

Travailler avec des fonctions 257

Atelier 15
Pour aider à consolider votre compréhension de la leçon de cette heure, nous vous encourageons
à répondre aux questions du quiz et à terminer les exercices fournis dans l'atelier avant de passer
à la leçon suivante. Les réponses et les conseils aux questions et exercices sont donnés dans
l'annexe B, « Réponses aux questions et exercices du quiz ».

Questionnaire

1. Étant donné les déclarations de fonction suivantes, lesquelles sont des fonctions avec
nombre d'arguments, lesquels sont des fonctions sans arguments et lesquels sont des fonctions
avec un nombre variable d'arguments ?

• int fonction_1(int x, float y);

• void function_2(char *str);

• char *asctime(const struct tm *timeptr);

• int fonction_3(vide);

• char fonction_4(car c, ...);

• void function_5(void);

2. Laquelle des deux expressions suivantes est une définition de fonction ? int
fonction_1(int x, int y); int function_2(int x, int y){retour x+y ;}

3. Quel est le type de données renvoyé par une fonction lorsqu'un spécificateur de type est omis ?

4. Dans les déclarations de fonction suivantes, lesquelles sont illégales ?

• fonction double_1(int x, ...);

• void function_2(int x, int y, ...);

• fonction char_3(...);

• int fonction_4(entier, entier, entier, entier);

Des exercices

1. Réécrivez le programme du Listing 15.2. Cette fois, utilisez le spécificateur de format %c, au
lieu de %s, pour imprimer la chaîne de caractères de l'heure locale sur votre ordinateur.

2. Déclarez et définissez une fonction, appelée MultiTwo(), qui peut effectuer une multiplication sur
deux variables entières. Appelez la fonction MultiTwo() à partir de la fonction main() et
transmettez deux entiers à MultiTwo(). Imprimez ensuite le résultat renvoyé par la fonction
MultiTwo() à l'écran.
Machine Translated by Google

258 Heure 15

3. Réécrivez le programme du Listing 15.3. Cette fois, créez une fonction qui prend un nombre
variable d' arguments int et effectue l'opération de multiplication sur ces arguments.

4. Réécrivez à nouveau le programme du Listing 15.3. Cette fois, imprimez tous les arguments
passé à la fonction AddDouble() . Est­ce que va_arg() récupère chaque argument dans le
même ordre (c'est­à­dire de gauche à droite) de la liste d'arguments passée à AddDouble() ?
Machine Translated by Google

HEURE 16

Application de pointeurs
Réfléchissez à deux fois et faites une fois.

­Proverbe chinois

Dans l'heure 11, « Comprendre les pointeurs », vous avez appris les bases de l'utilisation des
pointeurs en C. Comme les pointeurs sont très utiles en programmation, cela vaut la peine de
consacrer une heure de plus à en apprendre davantage à leur sujet. Dans cette leçon, les sujets
suivants sont abordés :

• Arithmétique des pointeurs

• Passage de tableaux à des

fonctions • Passage de pointeurs à des

fonctions • Pointage à des fonctions

Arithmétique du pointeur
En C, vous pouvez déplacer la position d'un pointeur en ajoutant ou en soustrayant des
entiers vers ou depuis le pointeur. Par exemple, étant donné une variable de pointeur de
caractère ptr_str, l'expression suivante :

ptr_str + 1
Machine Translated by Google

260 Heure 16

déplace le pointeur vers l'emplacement mémoire situé à un octet de la position actuelle de ptr_str.

Notez que pour les pointeurs de différents types de données, les entiers ajoutés ou soustraits aux pointeurs
ont des tailles différentes. En d'autres termes, ajouter (ou soustraire) 1 à un pointeur n'indique pas
nécessairement au compilateur d'ajouter (ou de soustraire) un octet à l'adresse, mais plutôt d'ajuster
l'adresse de manière à ce qu'elle saute un élément du type du aiguille.
Vous verrez plus de détails dans les sections suivantes.

La taille scalaire des pointeurs


Le format général pour changer la position d'un pointeur est

nom_pointeur + n

Ici n est un entier dont la valeur peut être positive ou négative. pointer_name est le nom d'une variable de
pointeur qui a la déclaration suivante :

spécificateur_type_données *nom_pointeur ;

Lorsque le compilateur C lit l'expression nom_pointeur + n, il l'interprète comme

pointer_name + n * sizeof(data_type_specifier)

Notez que l' opérateur sizeof est utilisé pour obtenir le nombre d'octets du type de données spécifié. Par
conséquent, pour la variable de pointeur char ptr_str, l'expression ptr_str + 1 signifie en réalité

ptr_str + 1 * sizeof(char).

Étant donné que la taille d'un caractère est d'un octet, ptr_str + 1 indique au compilateur de se déplacer
vers l'emplacement mémoire situé 1 octet après l'emplacement actuel référencé par le pointeur.

Le programme du Listing 16.1 montre comment les tailles scalaires des différents types de données
affectent les décalages ajoutés ou soustraits aux pointeurs.

TAPER LISTE 16.1 Déplacer des pointeurs de différents types de données

1 : /* 16L01.c : arithmétique de pointeur */


2 : #include <stdio.h> 3 : 4 : main() 5 : { 6 : 7 :

char *ptr_ch;
entier *ptr_int;
double *ptr_db ; /*
pointeur de caractère ptr_ch */
8 : 9 : 10 : printf("Position actuelle de ptr_ch : %p\n", ptr_ch);
Machine Translated by Google

Application de pointeurs 261

}_ printf("La position après ptr_ch + 1 : %p\n", ptr_ch + 1); printf("La position


après ptr_ch + 2 : %p\n", ptr_ch + 2); printf("La position après ptr_ch ­
1 : %p\n", ptr_ch ­ 1); printf("La position après ptr_ch ­ 2 : %p\n", ptr_ch
­ 2); /* pointeur int ptr_int */ printf("Position actuelle de ptr_int : %p\n",
ptr_int); printf("La position après ptr_int + 1 : %p\n", ptr_int + 1); printf("La
position après ptr_int + 2 : %p\n", ptr_int + 2); printf("La position après
ptr_int ­ 1 : %p\n", ptr_int ­ 1); printf("La position après ptr_int ­ 2 : %p\n",
ptr_int ­ 2); /* double pointeur ptr_ch */ printf("Position actuelle de ptr_db :
%p\n", ptr_db); printf("La position après ptr_db + 1 : %p\n", ptr_db + 1);
printf("La position après ptr_db + 2 : %p\n", ptr_db + 2); printf("La position 16
après ptr_db ­ 1 : %p\n", ptr_db ­ 1); printf("La position après ptr_db ­ 2 :
%p\n", ptr_db ­ 2);

renvoie 0 ;

La sortie suivante est obtenue en exécutant le fichier exécutable 16L01.exe du programme du


Listing 16.1 sur ma machine. Vous pouvez obtenir différentes adresses sur votre ordinateur, ainsi
que différents décalages en fonction de la taille des types de données sur votre système :

Position actuelle de ptr_ch : 0x000B


SORTIR La position après ptr_ch + 1 : 0x000C
La position après ptr_ch + 2 : 0x000D
La position après ptr_ch ­ 1 : 0x000A
La position après ptr_ch ­ 2 : 0x0009
Position actuelle de ptr_int : 0x028B
La position après ptr_int + 1 : 0x028D
La position après ptr_int + 2 : 0x028F
La position après ptr_int ­ 1 : 0x0289
La position après ptr_int ­ 2 : 0x0287
Position actuelle de ptr_db : 0x0128
La position après ptr_db + 1 : 0x0130
La position après ptr_db + 2 : 0x0138
La position après ptr_db ­ 1 : 0x0120
La position après ptr_db ­ 2 : 0x0118

Comme vous pouvez le voir dans le Listing 16.1, il existe trois pointeurs de types
UNE ANALYSE
différents — ptr_ch, ptr_int et ptr_db — déclarés aux lignes 6–8. Parmi eux, ptr_ch est un
pointeur vers un caractère, ptr_int est un pointeur vers un entier et ptr_db est un pointeur vers un
double.

Ensuite, l'instruction de la ligne 10 montre l'adresse mémoire, 0x000B, contenue par la variable de
pointeur char ptr_ch. Les lignes 11 et 12 affichent les deux adresses, 0x000C et 0x000D, lorsque ptr_ch
est additionné de 1 et 2, respectivement. De même, les lignes 13 et 14 donnent 0x000A
Machine Translated by Google

262 Heure 16

et 0x0009 lorsque ptr_ch est déplacé vers le bas vers des adresses mémoire inférieures. Étant donné
que la taille de char est de 1 octet, ptr_ch+1 signifie se déplacer vers l'emplacement mémoire supérieur
d'un octet à l'emplacement mémoire actuel, 0x000B, référencé par le pointeur ptr_ch.

La ligne 16 montre l'emplacement mémoire référencé par la variable de pointeur int ptr_int à 0x028B.
Étant donné que la taille de int est de 2 octets sur mon système, l'expression ptr_int + 1 déplace ptr_int
vers l'emplacement mémoire supérieur de 2 octets à celui pointé par ptr_int. C'est exactement le résultat
que vous voyez à la ligne 17. De même, la ligne 18 montre que ptr_int+2 déplace la référence vers
0x028F, qui est 4 octets plus haut (2*sizeof(int)) que 0x028B. L'emplacement mémoire 0x0289 est
référencé par l'expression ptr_int­1 à la ligne 19 ; 0x0287 est référencé par ptr_int­2 à la ligne 20.

La taille du type de données double est de 8 octets sur mon système. Par conséquent, l'expression
ptr_db+1 est interprétée comme l'adresse mémoire référencée par ptr_db plus 8 octets, c'est­à­dire
0x0128+8, ce qui donne 0x0130 au format hexadécimal, comme vous pouvez le voir à la ligne 23.

Les lignes 24 à 26 affichent les adresses mémoire référencées respectivement par ptr_db+2,
ptr_db­1 et ptr_db­2, ce qui prouve que le compilateur a utilisé la même taille scalaire de double dans
l'arithmétique du pointeur.

Les pointeurs sont très utiles lorsqu'ils sont utilisés correctement. Cependant, un pointeur peut vous
attirer rapidement des ennuis s'il contient la mauvaise valeur. Une erreur courante, par exemple,
consiste à attribuer une valeur droite à un pointeur qui attend en fait une valeur gauche.
Heureusement, de nombreux compilateurs C trouveront de telles erreurs et émettront un avertissement
message.

Il existe une autre erreur courante que le compilateur ne détecte pas toujours pour vous :
l'utilisation de pointeurs non initialisés. Par exemple, le code suivant a un problème potentiel : int
x, *ptr_int; x = 8 ; *ptr_int = x ;

Le problème est que le pointeur ptr_int n'est pas initialisé ; il pointe vers un emplacement de
mémoire inconnu. Par conséquent, l'attribution d'une valeur, comme 8 dans ce cas, à un
emplacement de mémoire inconnu est dangereuse. Il peut écraser certaines données importantes
qui sont déjà enregistrées à l'emplacement de la mémoire, causant ainsi un sérieux problème. La
solution consiste à s'assurer qu'un pointeur pointe vers un emplacement mémoire légal et valide
avant de l'utiliser.

Vous pouvez réécrire le code ci­dessus pour éviter le problème potentiel comme celui­ci : int x,

*ptr_int; x = 8 ; ptr_int = &x;

/* initialise le pointeur */
Machine Translated by Google

Application de pointeurs 263

Soustraction de pointeur
Vous pouvez soustraire une valeur de pointeur de l'autre pour obtenir la distance entre les deux
emplacements de mémoire. Par exemple, étant donné deux variables de pointeur char , ptr_str1 et
ptr_str2, vous pouvez calculer le décalage entre les deux emplacements mémoire pointés par les deux
pointeurs comme ceci :

ptr_str2 ­ ptr_str1

Pour obtenir des résultats significatifs, il est préférable de soustraire uniquement les pointeurs du même type de données.
16
Le Listing 16.2 montre un exemple de soustraction sur une variable de pointeur int .

TAPER LISTE 16.2 Effectuer une soustraction sur des pointeurs

1 : /* 16L02.c : Soustraction de pointeur */


2 : #include <stdio.h> 3 : 4 : main() 5 : { 6 :

entier *ptr_int1, *ptr_int2 ;

7 : 8 : printf("La position de ptr_int1 : %p\n", ptr_int1) ; 9 : ptr_int2 = ptr_int1


+ 5 ; 10 : printf("La
printf("La soustraction
position de ptr_int2 = ptr_int1
de ptr_int2 + 5 :: %d\n",
­ ptr_int1 %p\n", ptr_int2
ptr_int2)­ ; 11 :
ptr_int1) ;ptr_int1
12 : ptr_int2 = ptr_int1
­ 5 : %p\n", ­ 5 ; 13
ptr_int2) : printf("La
; 14 position
: printf("La de ptr_int2
soustraction =
de ptr_int2 ­ ptr_int1 : %d\n",
ptr_int2 ­ ptr_int1) ; 15 : 16 : 17 : }

renvoie 0 ;

Après avoir exécuté l'exécutable (16L02.exe) du programme du Listing 16.2 sur ma machine, j'ai la sortie
suivante affichée à l'écran :

La position de ptr_int1 : 0x0128


SORTIR
La position de ptr_int2 = ptr_int1 + 5 : 0x0132
La soustraction de ptr_int2 ­ ptr_int1 : 5
La position de ptr_int2 = ptr_int1 ­ 5 : 0x011E
La soustraction de ptr_int2 ­ ptr_int1 : ­5

Le programme du Listing 16.2 déclare deux variables de pointeur int , ptr_int1 et ptr_int2, à
UNE ANALYSE
la ligne 6. L'instruction de la ligne 8 imprime la position mémoire détenue par ptr_int1. La
ligne 9 affecte l'adresse mémoire référencée par ptr_int1+5 à ptr_int2.
Ensuite, le contenu de ptr_int2 est imprimé à la ligne 10.
Machine Translated by Google

264 Heure 16

L'instruction de la ligne 11 montre la différence entre les deux pointeurs int , c'est­à­dire la soustraction de
ptr_int2 et ptr_int1. Le résultat est 5.

La ligne 12 attribue alors une autre adresse mémoire, référencée par l'expression ptr_int1­5, au pointeur
ptr_int2 . Maintenant, ptr_int2 pointe vers un emplacement mémoire inférieur de 10 octets à l'emplacement
mémoire pointé par ptr_int1 (voir la sortie faite par la ligne 13.)
La différence entre ptr_int2 et ptr_int1 est obtenue par la soustraction des deux pointeurs, qui est ­5
(puisqu'un int sur ma machine est de deux octets) tel qu'imprimé par l'instruction de la ligne 14.

Pointeurs et tableaux
Comme indiqué dans les leçons précédentes, les pointeurs et les tableaux ont une relation étroite. Vous
pouvez accéder à un tableau via un pointeur qui contient l'adresse de début du tableau. La sous­section
suivante présente comment accéder aux éléments du tableau via des pointeurs.

Accéder aux tableaux via des pointeurs


Comme un nom de tableau qui n'est pas suivi d'un indice est interprété comme un pointeur vers le
premier élément du tableau, vous pouvez affecter l'adresse de début du tableau à un pointeur du même
type de données ; vous pouvez alors accéder à n'importe quel élément du tableau en ajoutant un entier
approprié au pointeur. La valeur de l'entier que vous utilisez est la même que la valeur de l'indice de
l'élément auquel vous souhaitez accéder.

En d'autres termes, étant donné un tableau, un tableau et un pointeur, ptr_array, si tableau et ptr_array sont
du même type de données, et ptr_array contient l'adresse de début du tableau, c'est­à­dire

ptr_array = tableau ;

alors l'expression array[n] est équivalente à l'expression

*(tableau_ptr + n)

Ici n est un nombre en indice dans le tableau.

Le Listing 16.3 montre comment accéder aux tableaux et modifier les valeurs des éléments du tableau à
l'aide de pointeurs.

TAPER LISTE 16.3 Accéder aux tableaux à l'aide de pointeurs

1 : /* 16L03.c : Accéder aux tableaux via des pointeurs */


2 : #include <stdio.h> 3 : 4 : main() 5 : {
Machine Translated by Google

Application de pointeurs 265

6: char str[] = "C'est une chaîne !" ;


7: caractère *ptr_str ; int liste[] = {1, 2, 3,
8: 4, 5} ; entier *ptr_int;
9:
10 :
11 : /* accéder au tableau de
12 : caractères */ ptr_str = str;
13 : printf("Avant le changement, str contient : %s\n", str); printf("Avant
14 : le changement, str[5] contient : %c\n", str[5]); *(ptr_str + 5) = 'A' ; printf("Après
15 : le changement, str[5] contient : %c\n", str[5]); printf("Après le changement, 16
16 : str contient : %s\n", str); /* accès au tableau int */ ptr_int = liste ; printf("Avant
17 : le changement, liste[2] contient : %d\n", liste[2]); *(ptr_int + 2) = ­3 ;
18 : printf("Après le changement, la liste[2] contient : %d\n", liste[2]);
19 :
20 :
21 :
22 :
23 :
24 : renvoie 0 ;
25 : }

La sortie suivante s'affiche après la création et l'exécution du fichier exécutable 16L03.exe sur mon
ordinateur :

Avant le changement, str contient : C'est une chaîne !


SORTIR Avant le changement, str[5] contient : a Après
le changement, str[5] contient : A Après le
changement, str contient : C'est une chaîne A !
Avant le changement, la liste[2] contient : 3 Après
le changement, la liste[2] contient : ­3

Le but du programme du Listing 16.3 est de vous montrer comment accéder à un tableau
UNE ANALYSE
char , str, et à un tableau int , list. Aux lignes 6 et 8, str et list sont déclarés et initialisés avec
une chaîne et un ensemble d'entiers, respectivement. Un pointeur char , ptr_str, et un pointeur int ,
ptr_int, sont déclarés aux lignes 7 et 9.

La ligne 12 affecte l'adresse de début du tableau str au pointeur ptr_str . Les instructions des lignes 13
et 14 montrent le contenu de la chaîne enregistrée dans le tableau str , ainsi que le caractère contenu
par l' élément str[5] dans le tableau avant toute modification .
à str.

La déclaration de la ligne 15 montre que la constante de caractère, 'A', est assignée à l'élément du
tableau str pointé par l'expression

*(ptr_str + 5)

Pour vérifier que le contenu de l'élément dans str a été mis à jour, les lignes 16 et 17 impriment
respectivement l'élément et la chaîne entière. La sortie indique que 'A' a remplacé la constante de
caractère d'origine, 'a'.
Machine Translated by Google

266 Heure 16

L'adresse de début de la liste de tableaux int est affectée au pointeur ptr_int à la ligne 19.
Avant de faire quoi que ce soit avec l' élément list[2] du tableau list , j'affiche sa valeur, qui est 3 en ce
moment (voir la sortie faite par la ligne 20). À la ligne 21, l' élément list[2] reçoit une autre valeur, ­3, via
le pointeur déréférencé *(ptr_int + 2). L' appel printf() à la ligne 22 imprime la valeur mise à jour de list[2] .

Pointeurs et fonctions
Avant de commencer à parler de la transmission de pointeurs vers des fonctions, voyons d'abord comment
transmettre des tableaux à des fonctions.

Passer des tableaux aux fonctions


En pratique, il est généralement gênant de passer plus de cinq ou six arguments à une fonction. Une
façon d'économiser le nombre d'arguments passés à une fonction consiste à utiliser des tableaux. Vous
pouvez placer toutes les variables du même type dans un tableau, puis passer le tableau en tant
qu'argument unique.

Le programme du Listing 16.4 montre comment passer un tableau d'entiers à une fonction.

TAPER LISTE 16.4 Passer des tableaux aux fonctions

1 : /* 16L04.c : Passer des tableaux aux fonctions */ 2 : #include


<stdio.h> 3 : 4 : int AddThree(int list[]) ; 5 : 6 : principal() 7 : { 8 :
9 : 10 : 11 :

entier somme, liste[3] ;

printf("Entrez trois entiers séparés par des espaces :\n"); scanf("%d%d%d",


&list[0], &list[1], &list[2]); somme = AddThree(liste); printf("La somme des
12 : trois entiers est : %d\n", somme);
13:
14:
15 : renvoie 0 ;
16 : }
17 :
18 : int AddThree(ent list[]) 19 : { 20 :
21 :
int je ;
entier résultat = 0 ;
22:
23: pour (i=0; i<3; i++)
24: résultat += liste[i] ;
25 : retourner le résultat ;
26 : }
Machine Translated by Google

Application de pointeurs 267

La sortie suivante est obtenue après avoir exécuté l'exécutable, 16L04.exe, et saisi trois nombres
entiers, 10, 20 et 30, sur ma machine :

Entrez trois nombres entiers séparés par des


SORTIR espaces : 10 20 30
La somme des trois entiers est : 60

Le but du programme du Listing 16.4 est d'obtenir trois entiers entrés par l'utilisateur, puis de
UNE ANALYSE
passer les trois entiers sous forme de tableau à une fonction appelée AddThree() pour
effectuer l'opération d'addition. 16
La ligne 4 donne la déclaration de la fonction AddThree() . Notez que le tableau non dimensionné,
list[], est utilisé dans l'expression d'argument, ce qui indique que l'argument contient l'adresse de
début du tableau de liste .

Le tableau list et une variable entière, sum, sont déclarés à la ligne 8. L' appel printf() à la ligne 10
affiche un message demandant à l'utilisateur d'entrer trois entiers. Ensuite, la ligne 11 utilise scanf()
pour récupérer les entiers saisis par l'utilisateur et les stocke dans les trois emplacements mémoire
des éléments du tableau d'entiers référencés par &list[0], &list[1] et &list[2], respectivement.

L'instruction de la ligne 12 appelle la fonction AddThree() avec le nom du tableau comme argument. L'
expression AddThree(list) transmet en fait l'adresse de début du tableau de liste (&list[0]) à la fonction
AddThree() .

La définition de la fonction AddThree() se trouve aux lignes 18–26 ; il ajoute les valeurs des trois
éléments dans le tableau de liste et renvoie le résultat de l'addition. Le résultat renvoyé par la fonction
AddThree() est affecté à la variable entière sum à la ligne 12 et est imprimé à la ligne 13.

Vous pouvez également spécifier la taille d'un tableau transmis à une fonction. Par
exemple, les éléments suivants :

fonction(char str[16]); est

équivalent à l'énoncé suivant :

fonction (chaîne de caractères

[]); N'oubliez pas que le compilateur peut déterminer la taille du tableau non
dimensionné str[].

Pour les tableaux multidimensionnels, le format d'un tableau non dimensionné doit
toujours être utilisé dans la déclaration. (Voir la section intitulée "Passer des tableaux
multidimensionnels en tant qu'arguments", plus tard dans cette heure.)
Machine Translated by Google

268 Heure 16

Passage de pointeurs vers des fonctions Comme vous


le savez, un nom de tableau qui n'est pas suivi d'un indice est interprété comme un pointeur vers le
premier élément du tableau. En fait, l'adresse du premier élément d'un tableau est l'adresse de début
du tableau. Par conséquent, vous pouvez affecter l'adresse de début d'un tableau à un pointeur, puis
passer le nom du pointeur, au lieu du tableau non dimensionné, à une fonction.

Le Listing 16.5 montre un exemple de passage de pointeurs vers des fonctions, qui est similaire au
passage de tableaux passés à des fonctions.

TAPER LISTE 16.5 Passer des pointeurs à des fonctions

1 : /* 16L05.c : passage de pointeurs vers des fonctions */ 2 :


#include <stdio.h> 3 : 4 : void ChPrint(char *ch); 5 : int
DonnéesAjout(int *liste, int max) ; 6 : main() 7 : { 8 : 9 : 10 :
11 : 12 : 13 : 14 : 15 : 16 : 17 : 18 : 19 : 20 : 21 : 22 : 23 : 24 :
25 : } 26 : /* fonction definition */ 27 : void ChPrint(char *ch)
28 : { 29 : 30 : } 31 : /* function definition */ 32 : int DataAdd(int
*list, int max) 33 : { 34 : 35 : 36 :
char str[] = "C'est une chaîne !" ;
caractère *ptr_str ; int liste[5] = {1, 2,
3, 4, 5} ; entier *ptr_int;

/* attribue une adresse au pointeur */


ptr_str = str;
ChPrint(ptr_str);
ChPrint(str);

/* attribue une adresse au pointeur */


ptr_int = list; printf("La somme retournée
par DataAdd() : %d\n",
DataAdd(ptr_int, 5));
printf("La somme retournée par DataAdd() : %d\n",
DonnéesAjouter(liste,
5)); renvoie 0 ;

printf("%s\n", ch);

int je ;
entier somme = 0 ;
Machine Translated by Google

Application de pointeurs 269

37 : for (i=0; i<max; i++) somme


38 : += liste[i]; somme de
39 : retour ;
40 : }

Après avoir exécuté le programme 16L05.exe , j'obtiens la sortie suivante affichée sur l'écran de mon
ordinateur :

SORTIR
C'est une chaîne ! 16
C'est une chaîne !
La somme renvoyée par DataAdd() : 15 La
somme renvoyée par DataAdd() : 15

Le but du programme du Listing 16.5 est de montrer comment passer deux pointeurs (un
UNE ANALYSE
pointeur entier qui pointe sur un tableau d'entiers et un pointeur caractère qui référence
une chaîne de caractères) à deux fonctions déclarées aux lignes 4 et 5.

Notez que des expressions telles que char *ch et int *list sont utilisées comme arguments dans les
déclarations de fonction, ce qui indique au compilateur qu'un pointeur char et un pointeur int sont
respectivement passés aux fonctions ChPrint() et DataAdd().

Dans le corps de la fonction main() , les lignes 8 et 9 déclarent un tableau de caractères (str) initialisé
avec une chaîne de caractères et une variable de pointeur de caractères (ptr_str). La ligne 10 déclare
et initialise un tableau int (liste) avec un ensemble d'entiers. Une variable de pointeur int , ptr_int, est
déclarée à la ligne 11.

L'adresse de début du tableau str est affectée au pointeur ptr_str par l'instruction d'affectation de la
ligne 14. Ensuite, le pointeur ptr_str est passé à la fonction ChPrint() comme argument de la ligne 15.
Selon la définition de ChPrint() dans lignes 27 à 30, le contenu du tableau str dont l'adresse de début
est transmise à la fonction lorsque l'argument est imprimé par l' appel printf() à l'intérieur de la fonction
ChPrint() à la ligne 29.

En fait, vous pouvez toujours utiliser le nom du tableau str comme argument et le passer à la
fonction ChPrint() . La ligne 16 montre que l'adresse de début du tableau de caractères est passée à
ChPrint() via le nom du tableau.

L'instruction de la ligne 19 affecte l'adresse de début de la liste de tableaux d'entiers au pointeur d'entier
ptr_int. Ensuite, le pointeur ptr_int est passé à la fonction DataAdd() à la ligne 21, avec 5, qui est le
nombre maximum d'éléments contenus par le tableau de liste . L'argument max est utilisé car la
fonction ne peut pas déterminer la taille du tableau étant donné uniquement l'adresse de début. À partir
de la définition de la fonction DataAdd() aux lignes 32 à 40, vous pouvez voir que DataAdd() ajoute tous
les éléments entiers de la liste et renvoie la somme à l'appelant. Par la suite, l'instruction des lignes 20
et 21 imprime le résultat renvoyé par DataAdd().
Machine Translated by Google

270 Heure 16

L'expression de la ligne 23 invoque également la fonction DataAdd() , mais cette fois, le nom du tableau de
liste est utilisé comme argument de la fonction. Sans surprise, l'adresse de début du tableau de liste est
transmise avec succès à la fonction DataAdd() et l' instruction printf() des lignes 22 et 23 affiche le résultat
correct à l'écran.

Passer des tableaux multidimensionnels comme arguments


Au cours de l'heure 12, "Comprendre les tableaux", vous avez découvert les tableaux multidimensionnels.
Dans cette section, vous allez voir comment passer des tableaux multidimensionnels aux fonctions.

Comme vous l'avez peut­être deviné, passer un tableau multidimensionnel à une fonction revient à passer
un tableau unidimensionnel à une fonction. Vous pouvez soit transmettre le format non dimensionné d'un
tableau multidimensionnel, soit un pointeur contenant l'adresse de début du tableau multidimensionnel à une
fonction. Le Listing 16.6 est un exemple de ces deux méthodes.

TAPER LISTE 16.6 Passer des tableaux multidimensionnels aux fonctions

1 : /* 16L06.c : Passer des tableaux multidimensionnels aux fonctions */ 2 : #include


<stdio.h> 3 : /* déclarations de fonction */ 4 : int DataAdd1(int list[][5], int max1, int
max2 ); 5 : int DonnéesAjout2(int *liste, int max1, int max2) ; 6 : /* fonction main() */ 7 :
main() 8 : { 9 : 10 : 11 :

int liste[2][5] = {1, 2, 3, 4, 5,


5, 4, 3, 2, 1} ;
entier *ptr_int;
12 :
13: printf("La somme retournée par DataAdd1() : %d\n",
14: DonnéesAjoute1(liste, 2, 5));
ptr_int = &list[0][0]; printf("La
somme retournée par DataAdd2() : %d\n",
15 : 16 : 17 : DataAdd2(ptr_int, 2, 5));
18 :
19 : renvoie 0 ;
20 : }
21 : /* définition de la fonction */ 22 : int
DataAdd1(int list[][5], int max1, int max2) 23 : { 24 :

int je, j ;
entier somme = 0 ;

25 : 26 : 27 pour
: (i=0; i<max1; i++)
28 : pour (j=0; j<max2; j++) somme
29 : += liste[i][j]; somme de retour ;
30 :
31 : }
Machine Translated by Google

Application de pointeurs 271

32 : /* définition de la fonction */ 33 :
int DataAdd2(int *list, int max1, int max2) 34 : { 35 : 36 : 37 :
38 : 39 : 40 : 41 : 42 : }
int je, j ;
entier somme = 0 ;

pour (i=0; i<max1; i++)


pour (j=0; j<max2; j++)
somme += *(liste + i*max2 + j);
somme de retour ; 16

La sortie suivante s'affiche sur l'écran de mon ordinateur après l'exécution de l'exécutable
(16L06.exe) :
La somme renvoyée par DataAdd1() : 30
SORTIR La somme retournée par DataAdd2() : 30

UNE ANALYSE Au début du programme du Listing 16.6, je déclare deux fonctions, DataAdd1() et
DataAdd2(), aux lignes 4 et 5. Notez que le premier argument de DataAdd1() à la ligne 4
est le tableau non dimensionné de list. En fait, list est un tableau d'entiers à deux dimensions
déclaré aux lignes 9 et 10 à l'intérieur du corps de la fonction main() . Les deux autres arguments,
max1 et max2, sont deux tailles de dimension du tableau de liste .

Comme vous pouvez le constater à partir de la définition de DataAdd1() aux lignes 22 à 31, chaque
élément du tableau de liste , exprimé sous la forme list[i][j], est ajouté et affecté à une variable locale
appelée sum qui est renvoyée à la fin de la fonction DataAdd1() à la ligne 30. Ici, i va de 0 à max1 ­ 1, et
j est compris entre 0 et max2 ­ 1.

La fonction DataAdd1() est appelée à la ligne 14, avec le nom du tableau de liste et les deux tailles
de dimension, 2 et 5. Le résultat renvoyé par DataAdd1() est imprimé par l'instruction aux lignes 13
et 14. Vous voyez donc , le passage d'un tableau multidimensionnel à une fonction est assez similaire
au passage d'un tableau unidimensionnel à une fonction. La fonction, dans ce cas, a besoin des deux
tailles de dimension pour déterminer le nombre total d'éléments dans le tableau.

Une autre façon de faire le travail consiste à passer un pointeur contenant l'adresse de début d'un
tableau multidimensionnel à une fonction. Dans cet exemple, la fonction DataAdd2() est déclarée à la
ligne 5 avec une expression de pointeur, int *list, comme premier argument de la fonction. La définition
de DataAdd2() est donnée aux lignes 33–42.

Notez qu'à la ligne 40, chaque élément du tableau de liste est récupéré en déplaçant le pointeur
pour pointer vers l'emplacement mémoire de l'élément. Autrement dit, le pointeur déréférencé *(list +
i*max2 + j) donne la valeur d'un élément situé à la ligne i et à la colonne j, si vous imaginez que le
tableau à deux dimensions est une matrice à la fois horizontale et verticale dimensions cal. Par
conséquent, l'ajout de i*max2 à la liste calcule l'adresse de la ligne i (c'est­à­dire,
Machine Translated by Google

272 Heure 16

en sautant les lignes 0 à i­1), puis en ajoutant j calcule l'adresse de l'élément j (c'est­à­dire la colonne j)
dans la ligne actuelle (i). Dans cet exemple, la plage de la ligne va de 0 à 1 (c'est­à­dire un total de 2
lignes) ; la plage de la colonne va de 0 à 4 (c'est­à­dire un total de 5 colonnes). Voir Figure 16.1.

Le résultat renvoyé par la fonction DataAdd2() est affiché à l'écran par l' instruction printf() aux
lignes 16 et 17.

FIGURE 16.1 Colonne


0 1234
La coordonnée
bidimensionnelle montre
les emplacements des
0 1 2 3 4 5
éléments dans la liste
Ligne
déployer.
1 5 4 3 2 1

Tableaux de pointeurs
Dans de nombreux cas, il est utile de déclarer un tableau de pointeurs et d'accéder au contenu pointé par
le tableau en déréférencant chaque pointeur. Par exemple, la déclaration suivante déclare un tableau de
pointeurs int :

entier *ptr_int[3] ;

En d'autres termes, la variable ptr_int est un tableau à trois éléments de pointeurs vers des entiers. De
plus, vous pouvez initialiser le tableau de pointeurs. Par example:
entier x1 = 10 ;
entier x2 = 100 ;
entier x3 = 1000 ;
ptr_int[0] = &x1;
ptr_int[1] = &x2;
ptr_int[2] = &x3;

Le Listing 16.7 montre un autre exemple. Ici, un tableau de pointeurs est utilisé pour accéder à un tableau
de chaînes.

TAPER
LISTE 16.7 Utilisation d'un tableau de pointeurs vers des chaînes de caractères

1 : /* 16L07.c : Utilisation d'un tableau de pointeurs */ 2 :


#include <stdio.h> 3 : /* déclarations de fonction */ 4 : void
StrPrint1(char **str1, int size); 5 : annuler StrPrint2(char
*str2);
Machine Translated by Google

Application de pointeurs 273

6 : /* fonction main() */ 7 : main()


8 : { 9 : 10 : 11 : 12 : 13 : 14 : 15 :
16 : 17 : 18 : 19 : 20 : 21 : } 22 : /
* fonction char
définition
*str[4]*/=23
{"Il: void
y a de la musique dans le soupir d'un roseau ;", "Il y a de la
StrPrint1(char **str1, int size) 24musique
: dans le jaillissement d'un ruisseau ;", "Il y a de
{ 25 : 26 : 27 : 28 : 29 : } 30 : /* la musique en toutes choses si les hommes avaient des
définition de la fonction */ 31 : oreilles ;", "Il n'y a que la terre un écho des sphères.\n" } ;
void StrPrint2(char *str2) 32 : entier je, taille = 4 ;
{ 33 : 34 : 35 : }
16
StrPrint1(chaîne, taille);
pour (i=0; i<taille; i++)
StrPrint2(str[i]);

renvoie 0 ;

int je ;
/* Affiche toutes les chaînes d'un tableau de pointeurs vers des chaînes */ for
(i=0; i<size; i++) printf(“%s\n”, str1[i]);

/* Imprime une chaîne à la fois */ printf(“%s\n”,


str2);

Un extrait d'un poème écrit par Lord Byron est imprimé après la création et l'exécution de l'exécutable
(16L07.exe) du programme du Listing 16.7 :

Il y a de la musique dans le soupir d'un roseau ; Il y


SORTIR a de la musique dans le jaillissement d'un ruisseau ;
Il y a de la musique en toutes choses si les hommes
avaient des oreilles ; Là, la terre n'est qu'un écho des sphères.
Il y a de la musique dans le soupir d'un roseau ; Il y
a de la musique dans le jaillissement d'un ruisseau ;
Il y a de la musique en toutes choses si les hommes
avaient des oreilles ; Là, la terre n'est qu'un écho des sphères.

Examinons d'abord le tableau de pointeurs, str, qui est déclaré et initialisé aux lignes 9 à 13
UNE ANALYSE
dans le corps de la fonction main() du programme de l'extrait 16.7. Comme vous pouvez le
voir, str est un tableau de quatre éléments de pointeurs vers un ensemble de chaînes de caractères.
J'ai adopté quatre phrases d'un poème écrit par Lord Byron et je les ai utilisées comme quatre
chaînes de caractères dans le programme.
Machine Translated by Google

274 Heure 16

Vous pouvez accéder à une chaîne de caractères en utilisant un pointeur correspondant dans le tableau.
En fait, il y a deux fonctions, StrPrint1() et StrPrint2(), dans le Listing 16.7. Les deux peuvent être
appelées pour accéder aux chaînes de caractères. À partir de la déclaration de fonction à la ligne 4, vous
pouvez voir que la fonction StrPrint1() prend un pointeur de pointeurs, c'est­à­dire **str1, qui est déréférencé
à l'intérieur de la fonction StrPrint1() pour représenter les quatre pointeurs qui pointent vers les quatre
caractères cordes. La définition de StrPrint1() se trouve aux lignes 23–29.

La fonction StrPrint2() , d'autre part, ne prend qu'une variable de pointeur comme argument et imprime
une chaîne de caractères référencée par le pointeur. Les lignes 31 à 35 donnent la définition de la
fonction StrPrint2() .

Revenons maintenant à la fonction main() . La fonction StrPrint1() est appelée à la ligne 16 avec le nom
du tableau de pointeurs, str, comme argument. StrPrint1() affiche alors les quatre phrases du poème de
Byron à l'écran. La boucle for des lignes 17 et 18 fait la même chose en appelant quatre fois la fonction
StrPrint2() . A chaque fois, l'adresse de début d'une phrase est passée à StrPrint2(). Par conséquent, vous
voyez toutes les phrases du poème imprimées deux fois à l'écran.

Pointant vers des fonctions


Avant de terminer le cours de cette heure, il y a encore une chose intéressante que vous devez apprendre :
les pointeurs vers les fonctions.

Comme pour les pointeurs vers des tableaux, vous pouvez déclarer un pointeur initialisé avec la valeur de
gauche d'une fonction. (La valeur de gauche est l'adresse mémoire à laquelle se trouve la fonction.)
Ensuite, vous pouvez appeler la fonction via le pointeur.

Le programme du Listing 16.8 est un exemple qui déclare un pointeur vers une fonction.

TAPER
LISTE 16.8 Pointer vers une fonction

1 : /* 16L08.c : pointant vers une fonction */ 2 :


#include <stdio.h> 3 : /* déclaration de fonction */ 4 :
int StrPrint(char *str); 5 : /* fonction principale() */ 6 :
principale() 7 : { 8 : 9 : 10 : 11 :

char str[24] = "Pointant vers une fonction."; int (*ptr)


(char *str);

ptr = StrPrint ; si (!
12 : (*ptr)(str))
Machine Translated by Google

Application de pointeurs 275

printf("Terminé !\n");

renvoie 0 ;
13 :
14 : 15 : 16 : } 17 : /* définition de la
fonction */ 18 : int StrPrint(char *str)
19 : { 20 : 21 : 22 : }
printf("%s\n", chaîne);
renvoie 0 ;
16

Une fois l'exécutable 16L08.exe du programme du Listing 16.8 créé et exécuté sur mon
SORTIR
ordinateur, la sortie suivante s'affiche à l'écran :

UNE ANALYSE
Pointant vers une fonction.
Fait!

Comme d'habitude, une déclaration de fonction vient en premier dans le Listing 16.8. La fonction StrPrint()
est déclarée avec le spécificateur de type de données int et un argument d'un pointeur char à la ligne 4.

L'instruction de la ligne 9 donne la déclaration d'un pointeur (ptr) vers la fonction StrPrint() : c'est­à­dire
int (*ptr)(char *str);.

Notez que le pointeur, ptr, est spécifié avec le type de données int et passé avec un pointeur char . En
d'autres termes, le format de la déclaration du pointeur à la ligne 9 est assez similaire à la déclaration de
StrPrint() à la ligne 4. N'oubliez pas que vous devez mettre l' expression *ptr entre une paire de parenthèses
(( et )) afin que le compilateur ne le confondra pas avec un nom de fonction.

À la ligne 11, la valeur de gauche (c'est­à­dire l'adresse) de la fonction StrPrint() est affectée au pointeur
ptr . Ensuite, l' expression (*ptr)(str) de la ligne 12 appelle la fonction StrPrint() via le pointeur déréférencé
ptr, et passe l'adresse de la chaîne déclarée à la ligne 8 à la fonction.

D'après la définition de la fonction StrPrint() aux lignes 18 à 22, vous pouvez dire que la fonction imprime le
contenu d'une chaîne dont l'adresse est passée à la fonction comme argument. Ensuite, 0 est retourné à la
fin de la fonction.

En fait, l' instruction if des lignes 12 et 13 vérifie la valeur renvoyée par la fonction StrPrint() . Lorsque la
valeur est 0, l' appel printf() à la ligne 13 affiche la chaîne Done! sur l'écran.

La sortie du programme du Listing 16.8 montre que la fonction StrPrint() a été invoquée avec succès en
utilisant un pointeur contenant l'adresse de la fonction.
Machine Translated by Google

276 Heure 16

Résumé
Dans cette leçon, vous avez appris les concepts et applications très importants suivants des pointeurs et
des tableaux en C :

• Vous devez toujours vous assurer qu'un pointeur pointe vers un emplacement de mémoire légal et
valide avant de l'utiliser.

• La position d'un pointeur peut être déplacée en ajoutant ou en soustrayant un entier. • La

taille scalaire d'un pointeur est déterminée par la taille de son type de données, qui est spécifiée
dans la déclaration du pointeur. • Pour deux pointeurs du même type, vous pouvez soustraire

une valeur de pointeur du


autre pour obtenir le décalage entre eux.

• Les éléments d'un tableau sont accessibles via un pointeur contenant l'adresse de début
du tableau.

• Vous pouvez passer un tableau non dimensionné comme argument unique à une

fonction. • Vous pouvez également passer un tableau à une fonction via un pointeur. Le pointeur
doit contenir l'adresse de début du tableau.

• Vous pouvez passer soit le format non dimensionné d'un tableau multidimensionnel, soit un pointeur
contenant l'adresse de début du tableau multidimensionnel à une fonction. • Une fonction qui

prend un tableau comme argument ne sait pas combien d'éléments se trouvent dans le tableau. Vous
devez également passer le nombre d'éléments comme un autre argument à la fonction.

• Les tableaux de pointeurs sont utiles pour traiter les chaînes de caractères. •

Vous pouvez affecter un pointeur à l'adresse d'une fonction, puis appeler la fonction à l'aide de ce
pointeur.

Dans la leçon suivante, vous apprendrez à allouer de la mémoire en C.

Questions et réponses

Q Pourquoi avez­vous besoin de l'arithmétique des pointeurs ?

R L'avantage d'utiliser des pointeurs est que vous pouvez déplacer des pointeurs pour accéder à des
données valides qui sont enregistrées dans les emplacements de mémoire référencés par les
pointeurs. Pour ce faire, vous pouvez effectuer une arithmétique de pointeur pour ajouter (ou
soustraire) un entier à (ou à partir) d'un pointeur. Par exemple, si un pointeur de caractère, ptr_str,
contient l'adresse de début d'une chaîne de caractères, l' expression ptr_str+1 se déplace vers
l'emplacement mémoire suivant, qui contient le deuxième caractère de la chaîne.
Machine Translated by Google

Application de pointeurs 277

Q Comment le compilateur détermine­t­il la taille scalaire d'un pointeur ?

A Le compilateur détermine la taille scalaire d'un pointeur par son type de données, qui est spécifié
dans la déclaration. Lorsqu'un entier est ajouté ou soustrait d'un pointeur, la valeur réelle utilisée
par le compilateur est la multiplication de l'entier et de la taille du type pointeur. Par exemple,
étant donné un pointeur int ptr_int, l'expression ptr_int + 1 est interprétée par le compilateur
comme ptr_int + 1 * sizeof(int). Si la taille du type int est de 2 octets, l' expression ptr_int + 1
signifie en réalité se déplacer de 2 octets vers le haut depuis l'emplacement mémoire référencé
par le pointeur ptr_int .
16
Q Comment accéder à un élément d'un tableau à l'aide d'un pointeur ?

A Pour un tableau unidimensionnel, vous pouvez affecter l'adresse de début d'un tableau à un
pointeur du même type, puis déplacez le pointeur vers l'emplacement mémoire qui contient la
valeur d'un élément qui vous intéresse. Ensuite, vous déréférencez le pointeur pour obtenir la
valeur de l'élément. Pour les tableaux multidimensionnels, la méthode est similaire, mais vous
devez penser aux autres dimensions en même temps (voir l'exemple présenté dans le Listing
16.6.)

Q Pourquoi avez­vous besoin d'utiliser des tableaux de pointeurs ?

R Dans de nombreux cas, il est utile d'utiliser des tableaux de pointeurs. Par exemple, il est pratique d'utiliser
un tableau de pointeurs pour pointer vers un ensemble de chaînes de caractères afin de pouvoir accéder
à n'importe laquelle des chaînes référencées par un pointeur correspondant dans le tableau.

Atelier
Pour aider à consolider votre compréhension de la leçon de cette heure, nous vous encourageons à
répondre aux questions du quiz et à terminer les exercices fournis dans l'atelier avant de passer à la
leçon suivante. Les réponses et les conseils aux questions et exercices sont donnés dans l'annexe B,
« Réponses aux questions et exercices du quiz ».

Questionnaire

1. Étant donné un pointeur char , ptr_ch, un pointeur int , ptr_int, et un pointeur flottant ,
ptr_flt, combien d'octets seront ajoutés, respectivement, dans les expressions suivantes sur
votre machine ?

• ptr_ch + 4

• ptr_int + 2

• ptr_flt + 1

• ptr_ch + 12

• ptr_int + 6

• ptr_flt + 3
Machine Translated by Google

278 Heure 16

2. Si l'adresse détenue par un pointeur int , ptr1, est 0x100A et que l'adresse détenue par un
autre pointeur int , ptr2, est 0x1006, qu'obtiendrez­ vous de la soustraction de ptr1–ptr2 ?

3. Étant donné que la taille du type de données double est de 8 octets et que l'adresse actuelle
détenue par une variable à double pointeur, ptr_db, est 0x0238, quelles sont les adresses
détenues, respectivement, par ptr_db–1 et ptr_db+5 ?

4. Compte tenu des déclarations et affectations suivantes :


char ch[] = {'a', 'b', 'c', 'd', 'A', 'B', 'C', 'D'} ; caractère *ptr ; ptr = &ch[1];

à quoi sert chacune de ces expressions ?

• *(ptr + 3)

• ptr ­ ch

• *(point ­ 1)

• *ptr = 'F'

Des exercices
1. Étant donné une chaîne de caractères, j'aime C !, écrivez un programme pour passer la chaîne à une fonction
tion qui affiche la chaîne à l'écran.

2. Réécrivez le programme de l'exercice 1. Cette fois, changez la chaîne de I like C! à j'aime C! en


déplaçant un pointeur initialisé avec l'adresse de début de la chaîne et en mettant à jour la
chaîne avec de nouveaux caractères. Ensuite, transmettez la chaîne mise à jour à la fonction
pour afficher le contenu de la chaîne à l'écran.

3. Étant donné un tableau de caractères à deux dimensions, str, qui est initialisé comme

char str[2][15] = { "Vous savez quoi", "C est puissant." } ;

écrivez un programme pour passer l'adresse de début de str à une fonction qui imprime le
contenu du tableau de caractères.

4. Réécrivez le programme du Listing 16.7. Cette fois, le tableau de pointeurs est initialisé
avec les chaînes suivantes :

« dimanche », « lundi », « mardi », « mercredi », « jeudi », « vendredi » et « samedi ».


Machine Translated by Google

HEURE 17
Allocation de mémoire
Il est tout aussi désagréable d'obtenir plus que ce que vous avez négocié que d'obtenir moins.

—GB Shaw

Jusqu'à présent, vous avez appris à déclarer et à réserver un espace mémoire avant qu'il ne
soit utilisé dans votre programme. Par exemple, vous devez spécifier la taille d'un tableau
dans votre programme (ou le compilateur doit déterminer la taille si vous déclarez un tableau
non dimensionné) avant de lui affecter des données au moment de l'exécution. Dans cette
leçon, vous apprendrez à allouer dynamiquement de l'espace mémoire lorsque votre programme
est en cours d'exécution. Les quatre fonctions d'allocation de mémoire dynamique abordées
dans cette leçon sont

• La fonction malloc()
• La fonction calloc()
• La fonction realloc()
• La fonction libre()

Vous aimerez peut-être aussi